From: Greg Kroah-Hartman Date: Tue, 16 Jun 2026 05:25:46 +0000 (+0530) Subject: 6.1-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f342f63da35fc225d046771a4b3657fda0aef152;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch bluetooth-init-sk_peer_-on-bt_sock_alloc.patch bluetooth-serialize-accept_q-access.patch btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_space_info_type.patch ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch crypto-nx-migrate-to-scomp-api.patch erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch fbcon-avoid-oob-font-access-if-console-rotation-fails.patch genetlink-use-internal-flags-for-multicast-groups.patch hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch ice-fix-vf-queue-configuration-with-low-mtu-values.patch iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch mm-hugetlb_cma-round-up-per_node-before-logging-it.patch mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch mptcp-do-not-drop-partial-packets.patch mptcp-fastclose-msk-when-linger-time-is-0.patch mptcp-pm-add_addr-rtx-allow-id-0.patch mptcp-pm-add_addr-rtx-fix-potential-data-race.patch mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch mptcp-pm-kernel-correctly-retransmit-add_addr-id-0.patch mptcp-pm-prio-skip-closed-subflows.patch mptcp-reset-rcv-wnd-on-disconnect.patch mtd-spi-nor-core-fix-implicit-declaration-warning.patch mtd-spi-nor-debugfs-fix-out-of-bounds-read-in-spi_nor_params_show.patch net-hsr-defer-node-table-free-until-after-rcu-readers.patch net-ipv4-stop-checking-crypto_ahash_alignmask.patch net-ipv6-stop-checking-crypto_ahash_alignmask.patch net-stmmac-avoid-shadowing-global-buf_sz.patch net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch net-wwan-t7xx-validate-port_count-against-message-length-in-t7xx_port_enum_msg_handler.patch netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch platform-x86-intel-vsec-add-private-data-for-per-device-data.patch platform-x86-intel-vsec-create-wrapper-to-walk-pci-config-space.patch platform-x86-intel-vsec-fix-enable_cnt-imbalance-on-pcie-error-recovery.patch platform-x86-intel-vsec-make-driver_data-info-const.patch pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch printk-add-print_hex_dump_devel.patch rdma-move-dma-block-iterator-logic-into-dedicated-files.patch rdma-umem-fix-kernel-doc-warnings.patch rdma-umem-fix-truncation-for-block-sizes-4g.patch scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch selftests-mptcp-drop-nanoseconds-width-specifier.patch serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch serial-samsung_tty-use-port-lock-wrappers.patch smb-client-require-net-admin-for-cifs-swn-netlink.patch smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch smb-client-validate-dacloffset-before-building-dacl-pointers.patch spi-convert-to-spi_controller_half_duplex.patch spi-lantiq-ssc-fix-controller-deregistration.patch spi-microchip-core-qspi-convert-to-platform-remove-callback-returning-void.patch spi-microchip-core-qspi-fix-controller-deregistration.patch spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch spi-qup-switch-to-use-modern-name.patch spi-s3c64xx-fix-null-deref-on-driver-unbind.patch spi-s3c64xx-use-devm_clk_get_enabled.patch spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch spi-spi-ti-qspi-switch-to-use-modern-name.patch spi-spi-zynq-do-not-check-for-0-return-after-calling-platform_get_irq.patch spi-st-ssc4-fix-controller-deregistration.patch spi-st-ssc4-switch-to-use-modern-name.patch spi-sun4i-convert-to-platform-remove-callback-returning-void.patch spi-sun4i-fix-controller-deregistration.patch spi-sun4i-switch-to-use-modern-name.patch spi-sun6i-fix-controller-deregistration.patch spi-syncuacer-fix-controller-deregistration.patch spi-synquacer-convert-to-platform-remove-callback-returning-void.patch spi-synquacer-switch-to-use-modern-name.patch spi-tegra114-fix-controller-deregistration.patch spi-tegra20-sflash-fix-controller-deregistration.patch spi-ti-qspi-fix-controller-deregistration.patch spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch spi-uniphier-convert-to-platform-remove-callback-returning-void.patch spi-uniphier-fix-controller-deregistration.patch spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch spi-uniphier-switch-to-use-modern-name.patch spi-zynq-qspi-convert-to-platform-remove-callback-returning-void.patch spi-zynq-qspi-fix-controller-deregistration.patch spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch spi-zynq-qspi-switch-to-use-modern-name.patch thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch tracing-probes-limit-size-of-event-probe-to-3k.patch tty-serial-qcom-geni-serial-align-define-values.patch tty-serial-qcom-geni-serial-remove-unused-symbols.patch tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch tty-serial-samsung-use-u32-for-register-interactions.patch udf-fix-partition-descriptor-append-bookkeeping.patch usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch usb-dwc3-move-guid-programming-after-phy-initialization.patch usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch wifi-mac80211-remove-station-if-connection-prep-fails.patch xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch xfs-fix-a-resource-leak-in-xfs_alloc_buftarg.patch --- diff --git a/queue-6.1/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch b/queue-6.1/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch new file mode 100644 index 0000000000..961d83f8ed --- /dev/null +++ b/queue-6.1/alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch @@ -0,0 +1,74 @@ +From stable+bounces-260690-greg=kroah.com@vger.kernel.org Fri Jun 5 18:39:23 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 09:00:33 -0400 +Subject: ALSA: firewire-motu: Protect register DSP event queue positions +To: stable@vger.kernel.org +Cc: "Cássio Gabriel" , "Takashi Sakamoto" , "Takashi Iwai" , "Sasha Levin" +Message-ID: <20260605130033.370944-1-sashal@kernel.org> + +From: Cássio Gabriel + +[ Upstream commit 98fb1c1bb11e29eb609b7200a25e136e05aa4498 ] + +The register DSP event queue is updated under parser->lock, but +snd_motu_register_dsp_message_parser_count_event() reads pull_pos and +push_pos without the lock. +snd_motu_register_dsp_message_parser_copy_event() also reads both queue +positions before taking the lock. + +Protect these accesses with parser->lock as well. This keeps the hwdep +poll/read path consistent with the producer side and with the cached +meter/parameter accessors. + +Fixes: 634ec0b2906e ("ALSA: firewire-motu: notify event for parameter change in register DSP model") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Reviewed-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260521-alsa-firewire-motu-event-locking-v1-1-708e1c2b5e56@gmail.com +[ converted copy_event() from manual spin_lock_irqsave/spin_unlock_irqrestore to guard(spinlock_irqsave) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/firewire/motu/motu-register-dsp-message-parser.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/sound/firewire/motu/motu-register-dsp-message-parser.c ++++ b/sound/firewire/motu/motu-register-dsp-message-parser.c +@@ -390,6 +390,8 @@ unsigned int snd_motu_register_dsp_messa + { + struct msg_parser *parser = motu->message_parser; + ++ guard(spinlock_irqsave)(&parser->lock); ++ + if (parser->pull_pos > parser->push_pos) + return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos; + else +@@ -399,14 +401,14 @@ unsigned int snd_motu_register_dsp_messa + bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event) + { + struct msg_parser *parser = motu->message_parser; +- unsigned int pos = parser->pull_pos; +- unsigned long flags; ++ unsigned int pos; + +- if (pos == parser->push_pos) +- return false; ++ guard(spinlock_irqsave)(&parser->lock); + +- spin_lock_irqsave(&parser->lock, flags); ++ if (parser->pull_pos == parser->push_pos) ++ return false; + ++ pos = parser->pull_pos; + *event = parser->event_queue[pos]; + + ++pos; +@@ -414,7 +416,5 @@ bool snd_motu_register_dsp_message_parse + pos = 0; + parser->pull_pos = pos; + +- spin_unlock_irqrestore(&parser->lock, flags); +- + return true; + } diff --git a/queue-6.1/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch b/queue-6.1/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch new file mode 100644 index 0000000000..ae45021d42 --- /dev/null +++ b/queue-6.1/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch @@ -0,0 +1,55 @@ +From stable+bounces-259404-greg=kroah.com@vger.kernel.org Mon Jun 1 06:41:59 2026 +From: Sasha Levin +Date: Sun, 31 May 2026 21:11:52 -0400 +Subject: arm64: tlb: Flush walk cache when unsharing PMD tables +To: stable@vger.kernel.org +Cc: Zeng Heng , Catalin Marinas , Sasha Levin +Message-ID: <20260601011152.135244-1-sashal@kernel.org> + +From: Zeng Heng + +[ Upstream commit c2ff4764e03e7a8d758352f4aceb8fe1be6ac971 ] + +When huge_pmd_unshare() is called to unshare a PMD table, the +tlb_unshare_pmd_ptdesc() function sets tlb->unshared_tables=true +but the aarch64 tlb_flush() only checked tlb->freed_tables to +determine whether to use TLBF_NONE (vae1is, invalidates walk +cache) or TLBF_NOWALKCACHE (vale1is, leaf-only). + +This caused the stale PMD page table entry to remain in the walk cache +after unshare, potentially leading to incorrect page table walks. + +Fix by including unshared_tables in the check, so that when +unsharing tables, TLBF_NONE is used and the walk cache is properly +invalidated. + +Here is the detailed distinction between vae1is and vale1is: + +| Instruction Combination | Actual Invalidation Scope | +| ------------------------ | --------------------------------------------------| +| `VAE1IS` + TTL=`0` | All entries at all levels (full invalidation) | +| `VAE1IS` + TTL=`2` (L2) | Non-leaf at Level 0/1 + leaf at Level 2 | +| `VALE1IS` + TTL=`0` | Leaf entries at all levels (non-leaf not cleared) | +| `VALE1IS` + TTL=`2` (L2) | Leaf entry at Level 2 only | + +Signed-off-by: Zeng Heng +Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather") +Cc: +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/include/asm/tlb.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/include/asm/tlb.h ++++ b/arch/arm64/include/asm/tlb.h +@@ -53,7 +53,7 @@ static inline int tlb_get_level(struct m + static inline void tlb_flush(struct mmu_gather *tlb) + { + struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0); +- bool last_level = !tlb->freed_tables; ++ bool last_level = !(tlb->freed_tables || tlb->unshared_tables); + unsigned long stride = tlb_get_unmap_size(tlb); + int tlb_level = tlb_get_level(tlb); + diff --git a/queue-6.1/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch b/queue-6.1/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch new file mode 100644 index 0000000000..006ecf82cd --- /dev/null +++ b/queue-6.1/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch @@ -0,0 +1,155 @@ +From stable+bounces-256790-greg=kroah.com@vger.kernel.org Sat May 30 03:13:20 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 17:42:32 -0400 +Subject: Bluetooth: hci_qca: Convert timeout from jiffies to ms +To: stable@vger.kernel.org +Cc: Shuai Zhang , Paul Menzel , Bartosz Golaszewski , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529214232.1794166-1-sashal@kernel.org> + +From: Shuai Zhang + +[ Upstream commit 375ba7484132662a4a8c7547d088fb6275c00282 ] + +Since the timer uses jiffies as its unit rather than ms, the timeout value +must be converted from ms to jiffies when configuring the timer. Otherwise, +the intended 8s timeout is incorrectly set to approximately 33s. + +To improve readability, embed msecs_to_jiffies() directly in the macro +definitions and drop the _MS suffix from macros that now yield jiffies +values: MEMDUMP_TIMEOUT, FW_DOWNLOAD_TIMEOUT, IBS_DISABLE_SSR_TIMEOUT, +CMD_TRANS_TIMEOUT, and IBS_BTSOC_TX_IDLE_TIMEOUT. + +IBS_WAKE_RETRANS_TIMEOUT_MS and IBS_HOST_TX_IDLE_TIMEOUT_MS are +intentionally left unchanged. Their values are stored in the struct fields +wake_retrans and tx_idle_delay, which hold ms values at runtime and can be +modified via debugfs. The msecs_to_jiffies() conversion happens at each +call site against the field value, so it cannot be embedded in the macro. + +Wake timer depends on commit c347ca17d62a + +Cc: stable@vger.kernel.org +Fixes: d841502c79e3 ("Bluetooth: hci_qca: Collect controller memory dump during SSR") +Reviewed-by: Paul Menzel +Acked-by: Bartosz Golaszewski +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +[ adapted to `vmalloc`-based memdump path and older `qca_serdev_shutdown(struct device *dev)` signature ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bluetooth/hci_qca.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -46,13 +46,12 @@ + #define HCI_MAX_IBS_SIZE 10 + + #define IBS_WAKE_RETRANS_TIMEOUT_MS 100 +-#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS 200 ++#define IBS_BTSOC_TX_IDLE_TIMEOUT msecs_to_jiffies(200) + #define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000 +-#define CMD_TRANS_TIMEOUT_MS 100 +-#define MEMDUMP_TIMEOUT_MS 8000 +-#define IBS_DISABLE_SSR_TIMEOUT_MS \ +- (MEMDUMP_TIMEOUT_MS + FW_DOWNLOAD_TIMEOUT_MS) +-#define FW_DOWNLOAD_TIMEOUT_MS 3000 ++#define CMD_TRANS_TIMEOUT msecs_to_jiffies(100) ++#define MEMDUMP_TIMEOUT msecs_to_jiffies(8000) ++#define FW_DOWNLOAD_TIMEOUT msecs_to_jiffies(3000) ++#define IBS_DISABLE_SSR_TIMEOUT (MEMDUMP_TIMEOUT + FW_DOWNLOAD_TIMEOUT) + + /* susclk rate */ + #define SUSCLK_RATE_32KHZ 32768 +@@ -1059,7 +1058,7 @@ static void qca_controller_memdump(struc + dump_size); + queue_delayed_work(qca->workqueue, + &qca->ctrl_memdump_timeout, +- msecs_to_jiffies(MEMDUMP_TIMEOUT_MS) ++ MEMDUMP_TIMEOUT + ); + + skb_pull(skb, sizeof(dump_size)); +@@ -1327,7 +1326,7 @@ static int qca_set_baudrate(struct hci_d + + if (hu->serdev) + serdev_device_wait_until_sent(hu->serdev, +- msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); ++ CMD_TRANS_TIMEOUT); + + /* Give the controller time to process the request */ + switch (qca_soc_type(hu)) { +@@ -1358,8 +1357,8 @@ static inline void host_set_baudrate(str + + static int qca_send_power_pulse(struct hci_uart *hu, bool on) + { ++ int timeout = CMD_TRANS_TIMEOUT; + int ret; +- int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); + u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE; + + /* These power pulses are single byte command which are sent +@@ -1561,7 +1560,7 @@ static void qca_wait_for_dump_collection + struct qca_data *qca = hu->priv; + + wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION, +- TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS); ++ TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT); + + clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } +@@ -2390,7 +2389,7 @@ static void qca_serdev_remove(struct ser + static void qca_serdev_shutdown(struct device *dev) + { + int ret; +- int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); ++ int timeout = CMD_TRANS_TIMEOUT; + struct serdev_device *serdev = to_serdev_device(dev); + struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &qcadev->serdev_hu; +@@ -2448,7 +2447,7 @@ static int __maybe_unused qca_suspend(st + bool tx_pending = false; + int ret = 0; + u8 cmd; +- u32 wait_timeout = 0; ++ unsigned long wait_timeout = 0; + + set_bit(QCA_SUSPENDING, &qca->flags); + +@@ -2469,15 +2468,15 @@ static int __maybe_unused qca_suspend(st + if (test_bit(QCA_IBS_DISABLED, &qca->flags) || + test_bit(QCA_SSR_TRIGGERED, &qca->flags)) { + wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ? +- IBS_DISABLE_SSR_TIMEOUT_MS : +- FW_DOWNLOAD_TIMEOUT_MS; ++ IBS_DISABLE_SSR_TIMEOUT : ++ FW_DOWNLOAD_TIMEOUT; + + /* QCA_IBS_DISABLED flag is set to true, During FW download + * and during memory dump collection. It is reset to false, + * After FW download complete. + */ + wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED, +- TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout)); ++ TASK_UNINTERRUPTIBLE, wait_timeout); + + if (test_bit(QCA_IBS_DISABLED, &qca->flags)) { + bt_dev_err(hu->hdev, "SSR or FW download time out"); +@@ -2529,7 +2528,7 @@ static int __maybe_unused qca_suspend(st + + if (tx_pending) { + serdev_device_wait_until_sent(hu->serdev, +- msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); ++ CMD_TRANS_TIMEOUT); + serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); + } + +@@ -2538,7 +2537,7 @@ static int __maybe_unused qca_suspend(st + */ + ret = wait_event_interruptible_timeout(qca->suspend_wait_q, + qca->rx_ibs_state == HCI_IBS_RX_ASLEEP, +- msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS)); ++ IBS_BTSOC_TX_IDLE_TIMEOUT); + if (ret == 0) { + ret = -ETIMEDOUT; + goto error; diff --git a/queue-6.1/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch b/queue-6.1/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch new file mode 100644 index 0000000000..3c0b35f7b9 --- /dev/null +++ b/queue-6.1/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch @@ -0,0 +1,139 @@ +From stable+bounces-256803-greg=kroah.com@vger.kernel.org Sat May 30 04:52:03 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 19:21:52 -0400 +Subject: Bluetooth: Init sk_peer_* on bt_sock_alloc +To: stable@vger.kernel.org +Cc: Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529232154.1873470-1-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ Upstream commit 464c702fb9374ff8f3f816f24fb7ac719dd20e1e ] + +This makes sure peer information is always available via sock when using +bt_sock_alloc. + +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/af_bluetooth.c | 24 ++++++++++++++++++++++++ + net/bluetooth/hidp/sock.c | 10 +--------- + net/bluetooth/l2cap_sock.c | 19 ------------------- + 3 files changed, 25 insertions(+), 28 deletions(-) + +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -157,6 +157,14 @@ struct sock *bt_sock_alloc(struct net *n + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; + ++ /* Init peer information so it can be properly monitored */ ++ if (!kern) { ++ spin_lock(&sk->sk_peer_lock); ++ sk->sk_peer_pid = get_pid(task_tgid(current)); ++ sk->sk_peer_cred = get_current_cred(); ++ spin_unlock(&sk->sk_peer_lock); ++ } ++ + return sk; + } + EXPORT_SYMBOL(bt_sock_alloc); +@@ -201,6 +209,9 @@ EXPORT_SYMBOL(bt_sock_linked); + + void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh) + { ++ const struct cred *old_cred; ++ struct pid *old_pid; ++ + BT_DBG("parent %p, sk %p", parent, sk); + + sock_hold(sk); +@@ -213,6 +224,19 @@ void bt_accept_enqueue(struct sock *pare + list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q); + bt_sk(sk)->parent = parent; + ++ /* Copy credentials from parent since for incoming connections the ++ * socket is allocated by the kernel. ++ */ ++ spin_lock(&sk->sk_peer_lock); ++ old_pid = sk->sk_peer_pid; ++ old_cred = sk->sk_peer_cred; ++ sk->sk_peer_pid = get_pid(parent->sk_peer_pid); ++ sk->sk_peer_cred = get_cred(parent->sk_peer_cred); ++ spin_unlock(&sk->sk_peer_lock); ++ ++ put_pid(old_pid); ++ put_cred(old_cred); ++ + if (bh) + bh_unlock_sock(sk); + else +--- a/net/bluetooth/hidp/sock.c ++++ b/net/bluetooth/hidp/sock.c +@@ -256,21 +256,13 @@ static int hidp_sock_create(struct net * + if (sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + +- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern); ++ sk = bt_sock_alloc(net, sock, &hidp_proto, protocol, GFP_ATOMIC, kern); + if (!sk) + return -ENOMEM; + +- sock_init_data(sock, sk); +- + sock->ops = &hidp_sock_ops; +- + sock->state = SS_UNCONNECTED; + +- sock_reset_flag(sk, SOCK_ZAPPED); +- +- sk->sk_protocol = protocol; +- sk->sk_state = BT_OPEN; +- + bt_sock_link(&hidp_sk_list, sk); + + return 0; +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -178,21 +178,6 @@ done: + return err; + } + +-static void l2cap_sock_init_pid(struct sock *sk) +-{ +- struct l2cap_chan *chan = l2cap_pi(sk)->chan; +- +- /* Only L2CAP_MODE_EXT_FLOWCTL ever need to access the PID in order to +- * group the channels being requested. +- */ +- if (chan->mode != L2CAP_MODE_EXT_FLOWCTL) +- return; +- +- spin_lock(&sk->sk_peer_lock); +- sk->sk_peer_pid = get_pid(task_tgid(current)); +- spin_unlock(&sk->sk_peer_lock); +-} +- + static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, + int alen, int flags) + { +@@ -268,8 +253,6 @@ static int l2cap_sock_connect(struct soc + chan->mode != L2CAP_MODE_EXT_FLOWCTL) + chan->mode = L2CAP_MODE_LE_FLOWCTL; + +- l2cap_sock_init_pid(sk); +- + err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), + &la.l2_bdaddr, la.l2_bdaddr_type); + if (err) +@@ -325,8 +308,6 @@ static int l2cap_sock_listen(struct sock + goto done; + } + +- l2cap_sock_init_pid(sk); +- + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + diff --git a/queue-6.1/bluetooth-serialize-accept_q-access.patch b/queue-6.1/bluetooth-serialize-accept_q-access.patch new file mode 100644 index 0000000000..831ce85652 --- /dev/null +++ b/queue-6.1/bluetooth-serialize-accept_q-access.patch @@ -0,0 +1,222 @@ +From stable+bounces-256804-greg=kroah.com@vger.kernel.org Sat May 30 04:54:44 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 19:21:53 -0400 +Subject: Bluetooth: serialize accept_q access +To: stable@vger.kernel.org +Cc: Jiexun Wang , Jann Horn , Yuan Tan , Yifan Wu , Juefei Pu , Xin Liu , Ren Wei , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260529232154.1873470-2-sashal@kernel.org> + +From: Jiexun Wang + +[ Upstream commit e83f5e24da741fa9405aeeff00b08c5ee7c37b88 ] + +bt_sock_poll() walks the accept queue without synchronization, while +child teardown can unlink the same socket and drop its last reference. +The unsynchronized accept queue walk has existed since the initial +Bluetooth import. + +Protect accept_q with a dedicated lock for queue updates and polling. +Also rework bt_accept_dequeue() to take temporary child references under +the queue lock before dropping it and locking the child socket. + +Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reported-by: Jann Horn +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Signed-off-by: Jiexun Wang +Reviewed-by: Jann Horn +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/af_bluetooth.c | 87 ++++++++++++++++++++++++++++---------- + 2 files changed, 66 insertions(+), 22 deletions(-) + +--- a/include/net/bluetooth/bluetooth.h ++++ b/include/net/bluetooth/bluetooth.h +@@ -361,6 +361,7 @@ void baswap(bdaddr_t *dst, const bdaddr_ + struct bt_sock { + struct sock sk; + struct list_head accept_q; ++ spinlock_t accept_q_lock; /* protects accept_q */ + struct sock *parent; + unsigned long flags; + void (*skb_msg_name)(struct sk_buff *, void *, int *); +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -151,6 +151,7 @@ struct sock *bt_sock_alloc(struct net *n + + sock_init_data(sock, sk); + INIT_LIST_HEAD(&bt_sk(sk)->accept_q); ++ spin_lock_init(&bt_sk(sk)->accept_q_lock); + + sock_reset_flag(sk, SOCK_ZAPPED); + +@@ -211,6 +212,7 @@ void bt_accept_enqueue(struct sock *pare + { + const struct cred *old_cred; + struct pid *old_pid; ++ struct bt_sock *par = bt_sk(parent); + + BT_DBG("parent %p, sk %p", parent, sk); + +@@ -221,9 +223,13 @@ void bt_accept_enqueue(struct sock *pare + else + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + +- list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q); + bt_sk(sk)->parent = parent; + ++ spin_lock_bh(&par->accept_q_lock); ++ list_add_tail(&bt_sk(sk)->accept_q, &par->accept_q); ++ sk_acceptq_added(parent); ++ spin_unlock_bh(&par->accept_q_lock); ++ + /* Copy credentials from parent since for incoming connections the + * socket is allocated by the kernel. + */ +@@ -241,8 +247,6 @@ void bt_accept_enqueue(struct sock *pare + bh_unlock_sock(sk); + else + release_sock(sk); +- +- sk_acceptq_added(parent); + } + EXPORT_SYMBOL(bt_accept_enqueue); + +@@ -251,45 +255,72 @@ EXPORT_SYMBOL(bt_accept_enqueue); + */ + void bt_accept_unlink(struct sock *sk) + { ++ struct sock *parent = bt_sk(sk)->parent; ++ + BT_DBG("sk %p state %d", sk, sk->sk_state); + ++ spin_lock_bh(&bt_sk(parent)->accept_q_lock); + list_del_init(&bt_sk(sk)->accept_q); +- sk_acceptq_removed(bt_sk(sk)->parent); ++ sk_acceptq_removed(parent); ++ spin_unlock_bh(&bt_sk(parent)->accept_q_lock); + bt_sk(sk)->parent = NULL; + sock_put(sk); + } + EXPORT_SYMBOL(bt_accept_unlink); + ++static struct sock *bt_accept_get(struct sock *parent, struct sock *sk) ++{ ++ struct bt_sock *bt = bt_sk(parent); ++ struct sock *next = NULL; ++ ++ /* accept_q is modified from child teardown paths too, so take a ++ * temporary reference before dropping the queue lock. ++ */ ++ spin_lock_bh(&bt->accept_q_lock); ++ ++ if (sk) { ++ if (bt_sk(sk)->parent != parent) ++ goto out; ++ ++ if (!list_is_last(&bt_sk(sk)->accept_q, &bt->accept_q)) { ++ next = &list_next_entry(bt_sk(sk), accept_q)->sk; ++ sock_hold(next); ++ } ++ } else if (!list_empty(&bt->accept_q)) { ++ next = &list_first_entry(&bt->accept_q, ++ struct bt_sock, accept_q)->sk; ++ sock_hold(next); ++ } ++ ++out: ++ spin_unlock_bh(&bt->accept_q_lock); ++ return next; ++} ++ + struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) + { +- struct bt_sock *s, *n; +- struct sock *sk; ++ struct sock *sk, *next; + + BT_DBG("parent %p", parent); + + restart: +- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { +- sk = (struct sock *)s; +- ++ for (sk = bt_accept_get(parent, NULL); sk; sk = next) { + /* Prevent early freeing of sk due to unlink and sock_kill */ +- sock_hold(sk); + lock_sock(sk); + + /* Check sk has not already been unlinked via + * bt_accept_unlink() due to serialisation caused by sk locking + */ +- if (!bt_sk(sk)->parent) { ++ if (bt_sk(sk)->parent != parent) { + BT_DBG("sk %p, already unlinked", sk); + release_sock(sk); + sock_put(sk); + +- /* Restart the loop as sk is no longer in the list +- * and also avoid a potential infinite loop because +- * list_for_each_entry_safe() is not thread safe. +- */ + goto restart; + } + ++ next = bt_accept_get(parent, sk); ++ + /* sk is safely in the parent list so reduce reference count */ + sock_put(sk); + +@@ -317,6 +348,8 @@ restart: + sock_hold(sk); + + release_sock(sk); ++ if (next) ++ sock_put(next); + return sk; + } + +@@ -519,18 +552,28 @@ EXPORT_SYMBOL(bt_sock_stream_recvmsg); + + static inline __poll_t bt_accept_poll(struct sock *parent) + { +- struct bt_sock *s, *n; ++ struct bt_sock *bt = bt_sk(parent); ++ struct bt_sock *s; + struct sock *sk; ++ __poll_t mask = 0; ++ ++ spin_lock_bh(&bt->accept_q_lock); ++ list_for_each_entry(s, &bt->accept_q, accept_q) { ++ int state; + +- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { + sk = (struct sock *)s; +- if (sk->sk_state == BT_CONNECTED || +- (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && +- sk->sk_state == BT_CONNECT2)) +- return EPOLLIN | EPOLLRDNORM; ++ state = READ_ONCE(sk->sk_state); ++ ++ if (state == BT_CONNECTED || ++ (test_bit(BT_SK_DEFER_SETUP, &bt->flags) && ++ state == BT_CONNECT2)) { ++ mask = EPOLLIN | EPOLLRDNORM; ++ break; ++ } + } ++ spin_unlock_bh(&bt->accept_q_lock); + +- return 0; ++ return mask; + } + + __poll_t bt_sock_poll(struct file *file, struct socket *sock, diff --git a/queue-6.1/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch b/queue-6.1/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch new file mode 100644 index 0000000000..d6e8394d96 --- /dev/null +++ b/queue-6.1/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch @@ -0,0 +1,59 @@ +From stable+bounces-247736-greg=kroah.com@vger.kernel.org Fri May 15 18:19:20 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 08:15:04 -0400 +Subject: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak +To: stable@vger.kernel.org +Cc: Yochai Eisenrich , Yochai Eisenrich , David Sterba , Sasha Levin +Message-ID: <20260515121504.3129260-1-sashal@kernel.org> + +From: Yochai Eisenrich + +[ Upstream commit 973e57c726c1f8e77259d1c8e519519f1e9aea77 ] + +btrfs_ioctl_space_info() has a TOCTOU race between two passes over the +block group RAID type lists. The first pass counts entries to determine +the allocation size, then the second pass fills the buffer. The +groups_sem rwlock is released between passes, allowing concurrent block +group removal to reduce the entry count. + +When the second pass fills fewer entries than the first pass counted, +copy_to_user() copies the full alloc_size bytes including trailing +uninitialized kmalloc bytes to userspace. + +Fix by copying only total_spaces entries (the actually-filled count from +the second pass) instead of alloc_size bytes, and switch to kzalloc so +any future copy size mismatch cannot leak heap data. + +Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl") +CC: stable@vger.kernel.org # 3.0 +Signed-off-by: Yochai Eisenrich +Reviewed-by: David Sterba +Signed-off-by: David Sterba +[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/ioctl.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3977,7 +3977,7 @@ static long btrfs_ioctl_space_info(struc + return -ENOMEM; + + space_args.total_spaces = 0; +- dest = kmalloc(alloc_size, GFP_KERNEL); ++ dest = kzalloc(alloc_size, GFP_KERNEL); + if (!dest) + return -ENOMEM; + dest_orig = dest; +@@ -4033,7 +4033,8 @@ static long btrfs_ioctl_space_info(struc + user_dest = (struct btrfs_ioctl_space_info __user *) + (arg + sizeof(struct btrfs_ioctl_space_args)); + +- if (copy_to_user(user_dest, dest_orig, alloc_size)) ++ if (copy_to_user(user_dest, dest_orig, ++ space_args.total_spaces * sizeof(*dest_orig))) + ret = -EFAULT; + + kfree(dest_orig); diff --git a/queue-6.1/btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch b/queue-6.1/btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch new file mode 100644 index 0000000000..3dcb0544aa --- /dev/null +++ b/queue-6.1/btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch @@ -0,0 +1,58 @@ +From stable+bounces-247814-greg=kroah.com@vger.kernel.org Fri May 15 20:37:50 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 11:07:28 -0400 +Subject: btrfs: fix double free in create_space_info_sub_group() error path +To: stable@vger.kernel.org +Cc: Guangshuo Li , Qu Wenruo , David Sterba , Sasha Levin +Message-ID: <20260515150728.3262445-2-sashal@kernel.org> + +From: Guangshuo Li + +[ Upstream commit a7449edf96143f192606ec8647e3167e1ecbd728 ] + +When kobject_init_and_add() fails, the call chain is: + +create_space_info_sub_group() +-> btrfs_sysfs_add_space_info_type() +-> kobject_init_and_add() +-> failure +-> kobject_put(&sub_group->kobj) +-> space_info_release() +-> kfree(sub_group) + +Then control returns to create_space_info_sub_group(), where: + +btrfs_sysfs_add_space_info_type() returns error +-> kfree(sub_group) + +Thus, sub_group is freed twice. + +Keep parent->sub_group[index] = NULL for the failure path, but after +btrfs_sysfs_add_space_info_type() has called kobject_put(), let the +kobject release callback handle the cleanup. + +Fixes: f92ee31e031c ("btrfs: introduce btrfs_space_info sub-group") +CC: stable@vger.kernel.org # 6.18+ +Reviewed-by: Qu Wenruo +Signed-off-by: Guangshuo Li +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/space-info.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -260,10 +260,8 @@ static int create_space_info_sub_group(s + sub_group->subgroup_id = id; + + ret = btrfs_sysfs_add_space_info_type(sub_group); +- if (ret) { +- kfree(sub_group); ++ if (ret) + parent->sub_group[index] = NULL; +- } + return ret; + } + diff --git a/queue-6.1/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch b/queue-6.1/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch new file mode 100644 index 0000000000..9029908bb1 --- /dev/null +++ b/queue-6.1/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch @@ -0,0 +1,224 @@ +From stable+bounces-249114-greg=kroah.com@vger.kernel.org Sun May 17 21:22:43 2026 +From: Sasha Levin +Date: Sun, 17 May 2026 11:52:35 -0400 +Subject: btrfs: fix missing last_unlink_trans update when removing a directory +To: stable@vger.kernel.org +Cc: Filipe Manana , Slava0135 , David Sterba , Sasha Levin +Message-ID: <20260517155235.302489-1-sashal@kernel.org> + +From: Filipe Manana + +[ Upstream commit 999757231c49376cd1a37308d2c8c4c9932571e1 ] + +When removing a directory we are not updating its last_unlink_trans field, +which can result in incorrect fsync behaviour in case some one fsyncs the +directory after it was removed because it's holding a file descriptor on +it. + +Example scenario: + + mkdir /mnt/dir1 + mkdir /mnt/dir1/dir2 + mkdir /mnt/dir3 + + sync -f /mnt + + # Do some change to the directory and fsync it. + chmod 700 /mnt/dir1 + xfs_io -c fsync /mnt/dir1 + + # Move dir2 out of dir1 so that dir1 becomes empty. + mv /mnt/dir1/dir2 /mnt/dir3/ + + open fd on /mnt/dir1 + call rmdir(2) on path "/mnt/dir1" + fsync fd + + + +When attempting to mount the filesystem, the log replay will fail with +an -EIO error and dmesg/syslog has the following: + + [445771.626482] BTRFS info (device dm-0): first mount of filesystem 0368bbea-6c5e-44b5-b409-09abe496e650 + [445771.626486] BTRFS info (device dm-0): using crc32c checksum algorithm + [445771.627912] BTRFS info (device dm-0): start tree-log replay + [445771.628335] page: refcount:2 mapcount:0 mapping:0000000061443ddc index:0x1d00 pfn:0x7072a5 + [445771.629453] memcg:ffff89f400351b00 + [445771.629892] aops:btree_aops [btrfs] ino:1 + [445771.630737] flags: 0x17fffc00000402a(uptodate|lru|private|writeback|node=0|zone=2|lastcpupid=0x1ffff) + [445771.632359] raw: 017fffc00000402a fffff47284d950c8 fffff472907b7c08 ffff89f458e412b8 + [445771.633713] raw: 0000000000001d00 ffff89f6c51d1a90 00000002ffffffff ffff89f400351b00 + [445771.635029] page dumped because: eb page dump + [445771.635825] BTRFS critical (device dm-0): corrupt leaf: root=5 block=30408704 slot=10 ino=258, invalid nlink: has 2 expect no more than 1 for dir + [445771.638088] BTRFS info (device dm-0): leaf 30408704 gen 10 total ptrs 17 free space 14878 owner 5 + [445771.638091] BTRFS info (device dm-0): refs 4 lock_owner 0 current 3581087 + [445771.638094] item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 + [445771.638097] inode generation 3 transid 9 size 16 nbytes 16384 + [445771.638098] block group 0 mode 40755 links 1 uid 0 gid 0 + [445771.638100] rdev 0 sequence 2 flags 0x0 + [445771.638102] atime 1775744884.0 + [445771.660056] ctime 1775744885.645502983 + [445771.660058] mtime 1775744885.645502983 + [445771.660060] otime 1775744884.0 + [445771.660062] item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 + [445771.660064] index 0 name_len 2 + [445771.660066] item 2 key (256 DIR_ITEM 1843588421) itemoff 16077 itemsize 34 + [445771.660068] location key (259 1 0) type 2 + [445771.660070] transid 9 data_len 0 name_len 4 + [445771.660075] item 3 key (256 DIR_ITEM 2363071922) itemoff 16043 itemsize 34 + [445771.660076] location key (257 1 0) type 2 + [445771.660077] transid 9 data_len 0 name_len 4 + [445771.660078] item 4 key (256 DIR_INDEX 2) itemoff 16009 itemsize 34 + [445771.660079] location key (257 1 0) type 2 + [445771.660080] transid 9 data_len 0 name_len 4 + [445771.660081] item 5 key (256 DIR_INDEX 3) itemoff 15975 itemsize 34 + [445771.660082] location key (259 1 0) type 2 + [445771.660083] transid 9 data_len 0 name_len 4 + [445771.660084] item 6 key (257 INODE_ITEM 0) itemoff 15815 itemsize 160 + [445771.660086] inode generation 9 transid 9 size 8 nbytes 0 + [445771.660087] block group 0 mode 40777 links 1 uid 0 gid 0 + [445771.660088] rdev 0 sequence 2 flags 0x0 + [445771.660089] atime 1775744885.641174097 + [445771.660090] ctime 1775744885.645502983 + [445771.660091] mtime 1775744885.645502983 + [445771.660105] otime 1775744885.641174097 + [445771.660106] item 7 key (257 INODE_REF 256) itemoff 15801 itemsize 14 + [445771.660107] index 2 name_len 4 + [445771.660108] item 8 key (257 DIR_ITEM 2676584006) itemoff 15767 itemsize 34 + [445771.660109] location key (258 1 0) type 2 + [445771.660110] transid 9 data_len 0 name_len 4 + [445771.660111] item 9 key (257 DIR_INDEX 2) itemoff 15733 itemsize 34 + [445771.660112] location key (258 1 0) type 2 + [445771.660113] transid 9 data_len 0 name_len 4 + [445771.660114] item 10 key (258 INODE_ITEM 0) itemoff 15573 itemsize 160 + [445771.660115] inode generation 9 transid 10 size 0 nbytes 0 + [445771.660116] block group 0 mode 40755 links 2 uid 0 gid 0 + [445771.660117] rdev 0 sequence 0 flags 0x0 + [445771.660118] atime 1775744885.645502983 + [445771.660119] ctime 1775744885.645502983 + [445771.660120] mtime 1775744885.645502983 + [445771.660121] otime 1775744885.645502983 + [445771.660122] item 11 key (258 INODE_REF 257) itemoff 15559 itemsize 14 + [445771.660123] index 2 name_len 4 + [445771.660124] item 12 key (258 INODE_REF 259) itemoff 15545 itemsize 14 + [445771.660125] index 2 name_len 4 + [445771.660126] item 13 key (259 INODE_ITEM 0) itemoff 15385 itemsize 160 + [445771.660127] inode generation 9 transid 10 size 8 nbytes 0 + [445771.660128] block group 0 mode 40755 links 1 uid 0 gid 0 + [445771.660129] rdev 0 sequence 1 flags 0x0 + [445771.660130] atime 1775744885.645502983 + [445771.660130] ctime 1775744885.645502983 + [445771.660131] mtime 1775744885.645502983 + [445771.660132] otime 1775744885.645502983 + [445771.660133] item 14 key (259 INODE_REF 256) itemoff 15371 itemsize 14 + [445771.660134] index 3 name_len 4 + [445771.660135] item 15 key (259 DIR_ITEM 2676584006) itemoff 15337 itemsize 34 + [445771.660136] location key (258 1 0) type 2 + [445771.660137] transid 10 data_len 0 name_len 4 + [445771.660138] item 16 key (259 DIR_INDEX 2) itemoff 15303 itemsize 34 + [445771.660139] location key (258 1 0) type 2 + [445771.660140] transid 10 data_len 0 name_len 4 + [445771.660144] BTRFS error (device dm-0): block=30408704 write time tree block corruption detected + [445771.661650] ------------[ cut here ]------------ + [445771.662358] WARNING: fs/btrfs/disk-io.c:326 at btree_csum_one_bio+0x217/0x230 [btrfs], CPU#8: mount/3581087 + [445771.663588] Modules linked in: btrfs f2fs xfs (...) + [445771.671229] CPU: 8 UID: 0 PID: 3581087 Comm: mount Tainted: G W 7.0.0-rc6-btrfs-next-230+ #2 PREEMPT(full) + [445771.672575] Tainted: [W]=WARN + [445771.672987] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [445771.674460] RIP: 0010:btree_csum_one_bio+0x217/0x230 [btrfs] + [445771.675222] Code: 89 44 24 (...) + [445771.677364] RSP: 0018:ffffd23882247660 EFLAGS: 00010246 + [445771.678029] RAX: 0000000000000000 RBX: ffff89f6c51d1a90 RCX: 0000000000000000 + [445771.678975] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff89f406020000 + [445771.679983] RBP: ffff89f821204000 R08: 0000000000000000 R09: 00000000ffefffff + [445771.680905] R10: ffffd23882247448 R11: 0000000000000003 R12: ffffd23882247668 + [445771.681978] R13: ffff89f458e40fc0 R14: ffff89f737f4f500 R15: ffff89f737f4f500 + [445771.682912] FS: 00007f0447a98840(0000) GS:ffff89fb9771d000(0000) knlGS:0000000000000000 + [445771.684393] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [445771.685230] CR2: 00007f0447bf1330 CR3: 000000017cb02002 CR4: 0000000000370ef0 + [445771.686273] Call Trace: + [445771.686646] + [445771.686969] btrfs_submit_bbio+0x83f/0x860 [btrfs] + [445771.687750] ? write_one_eb+0x28f/0x340 [btrfs] + [445771.688428] btree_writepages+0x2e3/0x550 [btrfs] + [445771.689180] ? kmem_cache_alloc_noprof+0x12a/0x490 + [445771.689963] ? alloc_extent_state+0x19/0x120 [btrfs] + [445771.690801] ? kmem_cache_free+0x135/0x380 + [445771.691328] ? preempt_count_add+0x69/0xa0 + [445771.691831] ? set_extent_bit+0x252/0x8e0 [btrfs] + [445771.692468] ? xas_load+0x9/0xc0 + [445771.692873] ? xas_find+0x14d/0x1a0 + [445771.693304] do_writepages+0xc6/0x160 + [445771.693756] filemap_writeback+0xb8/0xe0 + [445771.694274] btrfs_write_marked_extents+0x61/0x170 [btrfs] + [445771.694999] btrfs_write_and_wait_transaction+0x4e/0xc0 [btrfs] + [445771.695818] btrfs_commit_transaction+0x5c8/0xd10 [btrfs] + [445771.696530] ? kmem_cache_free+0x135/0x380 + [445771.697120] ? release_extent_buffer+0x34/0x160 [btrfs] + [445771.697786] btrfs_recover_log_trees+0x7be/0x7e0 [btrfs] + [445771.698525] ? __pfx_replay_one_buffer+0x10/0x10 [btrfs] + [445771.699206] open_ctree+0x11e5/0x1810 [btrfs] + [445771.699776] btrfs_get_tree.cold+0xb/0x162 [btrfs] + [445771.700463] ? fscontext_read+0x165/0x180 + [445771.701146] ? rw_verify_area+0x50/0x180 + [445771.701866] vfs_get_tree+0x25/0xd0 + [445771.702491] vfs_cmd_create+0x59/0xe0 + [445771.703125] __do_sys_fsconfig+0x303/0x610 + [445771.703603] do_syscall_64+0xe9/0xf20 + [445771.703974] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [445771.704700] RIP: 0033:0x7f0447cbd4aa + [445771.705108] Code: 73 01 c3 (...) + [445771.707263] RSP: 002b:00007ffc4e528318 EFLAGS: 00000246 ORIG_RAX: 00000000000001af + [445771.708107] RAX: ffffffffffffffda RBX: 00005561585d8c20 RCX: 00007f0447cbd4aa + [445771.708931] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003 + [445771.709744] RBP: 00005561585d9120 R08: 0000000000000000 R09: 0000000000000000 + [445771.710674] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + [445771.711477] R13: 00007f0447e4f580 R14: 00007f0447e5126c R15: 00007f0447e36a23 + [445771.712277] + [445771.712541] ---[ end trace 0000000000000000 ]--- + [445771.713382] BTRFS error (device dm-0): error while writing out transaction: -5 + [445771.714679] BTRFS warning (device dm-0): Skipping commit of aborted transaction. + [445771.715562] BTRFS error (device dm-0 state A): Transaction aborted (error -5) + [445771.716459] BTRFS: error (device dm-0 state A) in cleanup_transaction:2068: errno=-5 IO failure + [445771.717936] BTRFS error (device dm-0 state EA): failed to recover log trees with error: -5 + [445771.719681] BTRFS error (device dm-0 state EA): open_ctree failed: -5 + +The problem is that such a fsync should have result in a fallback to a +transaction commit, but that did not happen because through the +btrfs_rmdir() we never update the directory's last_unlink_trans field. +Any inode that had a link removed must have its last_unlink_trans updated +to the ID of transaction used for the operation, otherwise fsync and log +replay will not work correctly. + +btrfs_rmdir() calls btrfs_unlink_inode() and through that call chain we +never call btrfs_record_unlink_dir() in order to update last_unlink_trans. +However btrfs_unlink(), which is used for unlinking regular files, calls +btrfs_record_unlink_dir() and then calls btrfs_unlink_inode(). So fix +this by moving the call to btrfs_record_unlink_dir() from btrfs_unlink() +to btrfs_unlink_inode(). + +A test case for fstests will follow soon. + +Reported-by: Slava0135 +Link: https://lore.kernel.org/linux-btrfs/CAAJYhww5ov62Hm+n+tmhcL-e_4cBobg+OWogKjOJxVUXivC=MQ@mail.gmail.com/ +CC: stable@vger.kernel.org +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +[ wrapped dir and inode arguments with BTRFS_I() since 6.1 btrfs_rmdir() uses struct inode * instead of struct btrfs_inode * ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -4915,6 +4915,8 @@ static int btrfs_rmdir(struct inode *dir + if (err) + goto out; + ++ btrfs_record_unlink_dir(trans, BTRFS_I(dir), BTRFS_I(inode), false); ++ + /* now the directory is empty */ + err = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)), + &fname.disk_name); diff --git a/queue-6.1/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_space_info_type.patch b/queue-6.1/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_space_info_type.patch new file mode 100644 index 0000000000..7ebf4c4e75 --- /dev/null +++ b/queue-6.1/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_space_info_type.patch @@ -0,0 +1,78 @@ +From stable+bounces-247813-greg=kroah.com@vger.kernel.org Fri May 15 20:46:03 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 11:07:27 -0400 +Subject: btrfs: remove fs_info argument from btrfs_sysfs_add_space_info_type() +To: stable@vger.kernel.org +Cc: Filipe Manana , Johannes Thumshirn , David Sterba , Sasha Levin +Message-ID: <20260515150728.3262445-1-sashal@kernel.org> + +From: Filipe Manana + +[ Upstream commit 771af6ff72e0ed0eb8bf97e5ae4fa5094e0c5d1d ] + +We don't need it since we can grab fs_info from the given space_info. +So remove the fs_info argument. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: a7449edf9614 ("btrfs: fix double free in create_space_info_sub_group() error path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/space-info.c | 4 ++-- + fs/btrfs/sysfs.c | 5 ++--- + fs/btrfs/sysfs.h | 3 +-- + 3 files changed, 5 insertions(+), 7 deletions(-) + +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -259,7 +259,7 @@ static int create_space_info_sub_group(s + sub_group->parent = parent; + sub_group->subgroup_id = id; + +- ret = btrfs_sysfs_add_space_info_type(fs_info, sub_group); ++ ret = btrfs_sysfs_add_space_info_type(sub_group); + if (ret) { + kfree(sub_group); + parent->sub_group[index] = NULL; +@@ -288,7 +288,7 @@ static int create_space_info(struct btrf + goto out_free; + } + +- ret = btrfs_sysfs_add_space_info_type(info, space_info); ++ ret = btrfs_sysfs_add_space_info_type(space_info); + if (ret) + return ret; + +--- a/fs/btrfs/sysfs.c ++++ b/fs/btrfs/sysfs.c +@@ -1618,13 +1618,12 @@ static const char *alloc_name(struct btr + * Create a sysfs entry for a space info type at path + * /sys/fs/btrfs/UUID/allocation/TYPE + */ +-int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, +- struct btrfs_space_info *space_info) ++int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info) + { + int ret; + + ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, +- fs_info->space_info_kobj, "%s", ++ space_info->fs_info->space_info_kobj, "%s", + alloc_name(space_info)); + if (ret) { + kobject_put(&space_info->kobj); +--- a/fs/btrfs/sysfs.h ++++ b/fs/btrfs/sysfs.h +@@ -28,8 +28,7 @@ void __cold btrfs_exit_sysfs(void); + int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info); + void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info); + void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache); +-int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, +- struct btrfs_space_info *space_info); ++int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info); + void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info); + void btrfs_sysfs_update_devid(struct btrfs_device *device); + diff --git a/queue-6.1/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch b/queue-6.1/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch new file mode 100644 index 0000000000..06e52116c4 --- /dev/null +++ b/queue-6.1/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch @@ -0,0 +1,113 @@ +From stable+bounces-244962-greg=kroah.com@vger.kernel.org Sat May 9 20:23:14 2026 +From: Sasha Levin +Date: Sat, 9 May 2026 10:53:07 -0400 +Subject: ceph: only d_add() negative dentries when they are unhashed +To: stable@vger.kernel.org +Cc: Max Kellermann , Viacheslav Dubeyko , Ilya Dryomov , Sasha Levin +Message-ID: <20260509145307.3498924-1-sashal@kernel.org> + +From: Max Kellermann + +[ Upstream commit 803447f93d75ab6e40c85e6d12b5630d281d70d6 ] + +Ceph can call d_add(dentry, NULL) on a negative dentry that is already +present in the primary dcache hash. + +In the current VFS that is not safe. d_add() goes through __d_add() +to __d_rehash(), which unconditionally reinserts dentry->d_hash into +the hlist_bl bucket. If the dentry is already hashed, reinserting the +same node can corrupt the bucket, including creating a self-loop. +Once that happens, __d_lookup() can spin forever in the hlist_bl walk, +typically looping only on the d_name.hash mismatch check and +eventually triggering RCU stall reports like this one: + + rcu: INFO: rcu_sched self-detected stall on CPU + rcu: 87-....: (2100 ticks this GP) idle=3a4c/1/0x4000000000000000 softirq=25003319/25003319 fqs=829 + rcu: (t=2101 jiffies g=79058445 q=698988 ncpus=192) + CPU: 87 UID: 2952868916 PID: 3933303 Comm: php-cgi8.3 Not tainted 6.18.17-i1-amd #950 NONE + Hardware name: Dell Inc. PowerEdge R7615/0G9DHV, BIOS 1.6.6 09/22/2023 + RIP: 0010:__d_lookup+0x46/0xb0 + Code: c1 e8 07 48 8d 04 c2 48 8b 00 49 89 fc 49 89 f5 48 89 c3 48 83 e3 fe 48 83 f8 01 77 0f eb 2d 0f 1f 44 00 00 48 8b 1b 48 85 db <74> 20 39 6b 18 75 f3 48 8d 7b 78 e8 ba 85 d0 00 4c 39 63 10 74 1f + RSP: 0018:ff745a70c8253898 EFLAGS: 00000282 + RAX: ff26e470054cb208 RBX: ff26e470054cb208 RCX: 000000006e958966 + RDX: ff26e48267340000 RSI: ff745a70c82539b0 RDI: ff26e458f74655c0 + RBP: 000000006e958966 R08: 0000000000000180 R09: 9cd08d909b919a89 + R10: ff26e458f74655c0 R11: 0000000000000000 R12: ff26e458f74655c0 + R13: ff745a70c82539b0 R14: d0d0d0d0d0d0d0d0 R15: 2f2f2f2f2f2f2f2f + FS: 00007f5770896980(0000) GS:ff26e482c5d88000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007f5764de50c0 CR3: 000000a72abb5001 CR4: 0000000000771ef0 + PKRU: 55555554 + Call Trace: + + lookup_fast+0x9f/0x100 + walk_component+0x1f/0x150 + link_path_walk+0x20e/0x3d0 + path_lookupat+0x68/0x180 + filename_lookup+0xdc/0x1e0 + vfs_statx+0x6c/0x140 + vfs_fstatat+0x67/0xa0 + __do_sys_newfstatat+0x24/0x60 + do_syscall_64+0x6a/0x230 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +This is reachable with reused cached negative dentries. A Ceph lookup +or atomic_open can be handed a negative dentry that is already hashed, +and fs/ceph/dir.c then hits one of two paths that incorrectly assume +"negative" also means "unhashed": + + - ceph_finish_lookup(): + MDS reply is -ENOENT with no trace + -> d_add(dentry, NULL) + + - ceph_lookup(): + local ENOENT fast path for a complete directory with shared caps + -> d_add(dentry, NULL) + +Both paths can therefore re-add an already-hashed negative dentry. + +Ceph already uses the correct pattern elsewhere: ceph_fill_trace() only +calls d_add(dn, NULL) for a negative null-dentry reply when d_unhashed(dn) +is true. + +Fix both fs/ceph/dir.c sites the same way: only call d_add() for a +negative dentry when it is actually unhashed. If the negative dentry +is already hashed, leave it in place and reuse it as-is. + +This preserves the existing behavior for unhashed dentries while +avoiding d_hash list corruption for reused hashed negatives. + +Cc: stable@vger.kernel.org +Fixes: 2817b000b02c ("ceph: directory operations") +Signed-off-by: Max Kellermann +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +[ kept existing dout() debug call instead of upstream's doutc() form when adding the d_unhashed() guard around d_add() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/dir.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -721,7 +721,8 @@ struct dentry *ceph_finish_lookup(struct + d_drop(dentry); + err = -ENOENT; + } else { +- d_add(dentry, NULL); ++ if (d_unhashed(dentry)) ++ d_add(dentry, NULL); + } + } + } +@@ -777,7 +778,8 @@ static struct dentry *ceph_lookup(struct + __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD); + spin_unlock(&ci->i_ceph_lock); + dout(" dir %p complete, -ENOENT\n", dir); +- d_add(dentry, NULL); ++ if (d_unhashed(dentry)) ++ d_add(dentry, NULL); + di->lease_shared_gen = atomic_read(&ci->i_shared_gen); + return NULL; + } diff --git a/queue-6.1/cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch b/queue-6.1/cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch new file mode 100644 index 0000000000..6e5fcbca48 --- /dev/null +++ b/queue-6.1/cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch @@ -0,0 +1,70 @@ +From stable+bounces-253851-greg=kroah.com@vger.kernel.org Sat May 23 02:21:25 2026 +From: Sasha Levin +Date: Fri, 22 May 2026 16:51:17 -0400 +Subject: cgroup/cpuset: Reset DL migration state on can_attach() failure +To: stable@vger.kernel.org +Cc: Guopeng Zhang , Tejun Heo , Chen Ridong , Waiman Long , Sasha Levin +Message-ID: <20260522205117.4065831-1-sashal@kernel.org> + +From: Guopeng Zhang + +[ Upstream commit 4a39eda5fdd867fc39f3c039714dd432cee00268 ] + +cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration +state in the destination cpuset while walking the taskset. + +If a later task_can_attach() or security_task_setscheduler() check +fails, cgroup_migrate_execute() treats cpuset as the failing subsystem +and does not call cpuset_cancel_attach() for it. The partially +accumulated state is then left behind and can be consumed by a later +attach, corrupting cpuset DL task accounting and pending DL bandwidth +accounting. + +Reset the pending DL migration state from the common error exit when +ret is non-zero. Successful can_attach() keeps the state for +cpuset_attach() or cpuset_cancel_attach(). + +Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails") +Cc: stable@vger.kernel.org # v6.10+ +Signed-off-by: Guopeng Zhang +Signed-off-by: Tejun Heo +Reviewed-by: Chen Ridong +Reviewed-by: Waiman Long +[ omitted upstream context line `cs->dl_bw_cpu = cpu;` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/cgroup/cpuset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -2579,16 +2579,13 @@ static int cpuset_can_attach(struct cgro + int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus); + + if (unlikely(cpu >= nr_cpu_ids)) { +- reset_migrate_dl_data(cs); + ret = -EINVAL; + goto out_unlock; + } + + ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw); +- if (ret) { +- reset_migrate_dl_data(cs); ++ if (ret) + goto out_unlock; +- } + } + + out_success: +@@ -3401,7 +3398,10 @@ static int cpuset_can_fork(struct task_s + * changes which zero cpus/mems_allowed. + */ + cs->attach_in_progress++; ++ + out_unlock: ++ if (ret) ++ reset_migrate_dl_data(cs); + mutex_unlock(&cpuset_mutex); + return ret; + } diff --git a/queue-6.1/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch b/queue-6.1/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch new file mode 100644 index 0000000000..9d601e5f9c --- /dev/null +++ b/queue-6.1/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch @@ -0,0 +1,68 @@ +From stable+bounces-245029-greg=kroah.com@vger.kernel.org Sun May 10 19:52:58 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 10:22:50 -0400 +Subject: crypto: caam - guard HMAC key hex dumps in hash_digest_key +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , Sasha Levin +Message-ID: <20260510142250.4179491-2-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit 177730a273b18e195263ed953853273e901b5064 ] + +Use print_hex_dump_devel() for dumping sensitive HMAC key bytes in +hash_digest_key() to avoid leaking secrets at runtime when +CONFIG_DYNAMIC_DEBUG is enabled. + +Fixes: 045e36780f11 ("crypto: caam - ahash hmac support") +Fixes: 3f16f6c9d632 ("crypto: caam/qi2 - add support for ahash algorithms") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/caam/caamalg_qi2.c | 4 ++-- + drivers/crypto/caam/caamhash.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -3264,7 +3264,7 @@ static int hash_digest_key(struct caam_h + dpaa2_fl_set_addr(out_fle, key_dma); + dpaa2_fl_set_len(out_fle, digestsize); + +- print_hex_dump_debug("key_in@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key_in@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); + print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), +@@ -3284,7 +3284,7 @@ static int hash_digest_key(struct caam_h + /* in progress */ + wait_for_completion(&result.completion); + ret = result.err; +- print_hex_dump_debug("digested key@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("digested key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, + digestsize, 1); + } +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -390,7 +390,7 @@ static int hash_digest_key(struct caam_h + append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +- print_hex_dump_debug("key_in@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key_in@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), +@@ -405,7 +405,7 @@ static int hash_digest_key(struct caam_h + wait_for_completion(&result.completion); + ret = result.err; + +- print_hex_dump_debug("digested key@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("digested key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, + digestsize, 1); + } diff --git a/queue-6.1/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch b/queue-6.1/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch new file mode 100644 index 0000000000..daaa07bd11 --- /dev/null +++ b/queue-6.1/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch @@ -0,0 +1,120 @@ +From stable+bounces-244904-greg=kroah.com@vger.kernel.org Sat May 9 09:14:27 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:44:17 -0400 +Subject: crypto: nx - Avoid -Wflex-array-member-not-at-end warning +To: stable@vger.kernel.org +Cc: "Gustavo A. R. Silva" , Herbert Xu , Sasha Levin +Message-ID: <20260509034419.3105450-1-sashal@kernel.org> + +From: "Gustavo A. R. Silva" + +[ Upstream commit 1e6b251ce1759392666856908113dd5d7cea044d ] + +-Wflex-array-member-not-at-end is coming in GCC-14, and we are getting +ready to enable it globally. So, we are deprecating flexible-array +members in the middle of another structure. + +There is currently an object (`header`) in `struct nx842_crypto_ctx` +that contains a flexible structure (`struct nx842_crypto_header`): + +struct nx842_crypto_ctx { + ... + struct nx842_crypto_header header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + ... +}; + +So, in order to avoid ending up with a flexible-array member in the +middle of another struct, we use the `struct_group_tagged()` helper to +separate the flexible array from the rest of the members in the flexible +structure: + +struct nx842_crypto_header { + struct_group_tagged(nx842_crypto_header_hdr, hdr, + + ... the rest of the members + + ); + struct nx842_crypto_header_group group[]; +} __packed; + +With the change described above, we can now declare an object of the +type of the tagged struct, without embedding the flexible array in the +middle of another struct: + +struct nx842_crypto_ctx { + ... + struct nx842_crypto_header_hdr header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + ... + } __packed; + +We also use `container_of()` whenever we need to retrieve a pointer to +the flexible structure, through which we can access the flexible +array if needed. + +So, with these changes, fix the following warning: + +In file included from drivers/crypto/nx/nx-842.c:55: +drivers/crypto/nx/nx-842.h:174:36: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] + 174 | struct nx842_crypto_header header; + | ^~~~~~ + +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Herbert Xu +Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 6 ++++-- + drivers/crypto/nx/nx-842.h | 10 ++++++---- + 2 files changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -251,7 +251,9 @@ int nx842_crypto_compress(struct crypto_ + u8 *dst, unsigned int *dlen) + { + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); +- struct nx842_crypto_header *hdr = &ctx->header; ++ struct nx842_crypto_header *hdr = ++ container_of(&ctx->header, ++ struct nx842_crypto_header, hdr); + struct nx842_crypto_param p; + struct nx842_constraints c = *ctx->driver->constraints; + unsigned int groups, hdrsize, h; +@@ -490,7 +492,7 @@ int nx842_crypto_decompress(struct crypt + } + + memcpy(&ctx->header, src, hdr_len); +- hdr = &ctx->header; ++ hdr = container_of(&ctx->header, struct nx842_crypto_header, hdr); + + for (n = 0; n < hdr->groups; n++) { + /* ignore applies to last group */ +--- a/drivers/crypto/nx/nx-842.h ++++ b/drivers/crypto/nx/nx-842.h +@@ -157,9 +157,11 @@ struct nx842_crypto_header_group { + } __packed; + + struct nx842_crypto_header { +- __be16 magic; /* NX842_CRYPTO_MAGIC */ +- __be16 ignore; /* decompressed end bytes to ignore */ +- u8 groups; /* total groups in this header */ ++ struct_group_tagged(nx842_crypto_header_hdr, hdr, ++ __be16 magic; /* NX842_CRYPTO_MAGIC */ ++ __be16 ignore; /* decompressed end bytes to ignore */ ++ u8 groups; /* total groups in this header */ ++ ); + struct nx842_crypto_header_group group[]; + } __packed; + +@@ -171,7 +173,7 @@ struct nx842_crypto_ctx { + u8 *wmem; + u8 *sbounce, *dbounce; + +- struct nx842_crypto_header header; ++ struct nx842_crypto_header_hdr header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + + struct nx842_driver *driver; diff --git a/queue-6.1/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch b/queue-6.1/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch new file mode 100644 index 0000000000..244ef83187 --- /dev/null +++ b/queue-6.1/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch @@ -0,0 +1,51 @@ +From stable+bounces-244906-greg=kroah.com@vger.kernel.org Sat May 9 09:14:35 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:44:19 -0400 +Subject: crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , Sasha Levin +Message-ID: <20260509034419.3105450-3-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit adb3faf2db1a66d0f015b44ac909a32dfc7f2f9c ] + +The bounce buffers are allocated with __get_free_pages() using +BOUNCE_BUFFER_ORDER (order 2 = 4 pages), but both the allocation error +path and nx842_crypto_free_ctx() release the buffers with free_page(). +Use free_pages() with the matching order instead. + +Fixes: ed70b479c2c0 ("crypto: nx - add hardware 842 crypto comp alg") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -116,8 +116,8 @@ void *nx842_crypto_alloc_ctx(struct nx84 + ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); + if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { + kfree(ctx->wmem); +- free_page((unsigned long)ctx->sbounce); +- free_page((unsigned long)ctx->dbounce); ++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); ++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); + kfree(ctx); + return ERR_PTR(-ENOMEM); + } +@@ -131,8 +131,8 @@ void nx842_crypto_free_ctx(void *p) + struct nx842_crypto_ctx *ctx = p; + + kfree(ctx->wmem); +- free_page((unsigned long)ctx->sbounce); +- free_page((unsigned long)ctx->dbounce); ++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); ++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); + } + EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx); + diff --git a/queue-6.1/crypto-nx-migrate-to-scomp-api.patch b/queue-6.1/crypto-nx-migrate-to-scomp-api.patch new file mode 100644 index 0000000000..959bebab9f --- /dev/null +++ b/queue-6.1/crypto-nx-migrate-to-scomp-api.patch @@ -0,0 +1,279 @@ +From stable+bounces-244905-greg=kroah.com@vger.kernel.org Sat May 9 09:14:30 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:44:18 -0400 +Subject: crypto: nx - Migrate to scomp API +To: stable@vger.kernel.org +Cc: Ard Biesheuvel , Herbert Xu , Sasha Levin +Message-ID: <20260509034419.3105450-2-sashal@kernel.org> + +From: Ard Biesheuvel + +[ Upstream commit 980b5705f4e73f567e405cd18337cc32fd51cf79 ] + +The only remaining user of 842 compression has been migrated to the +acomp compression API, and so the NX hardware driver has to follow suit, +given that no users of the obsolete 'comp' API remain, and it is going +to be removed. + +So migrate the NX driver code to scomp. These will be wrapped and +exposed as acomp implementation via the crypto subsystem's +acomp-to-scomp adaptation layer. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 33 +++++++++++++++++++-------------- + drivers/crypto/nx/nx-842.h | 14 ++++++++------ + drivers/crypto/nx/nx-common-powernv.c | 31 +++++++++++++++---------------- + drivers/crypto/nx/nx-common-pseries.c | 33 ++++++++++++++++----------------- + 4 files changed, 58 insertions(+), 53 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -101,9 +101,13 @@ static int update_param(struct nx842_cry + return 0; + } + +-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver) ++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return ERR_PTR(-ENOMEM); + + spin_lock_init(&ctx->lock); + ctx->driver = driver; +@@ -114,22 +118,23 @@ int nx842_crypto_init(struct crypto_tfm + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); +- return -ENOMEM; ++ kfree(ctx); ++ return ERR_PTR(-ENOMEM); + } + +- return 0; ++ return ctx; + } +-EXPORT_SYMBOL_GPL(nx842_crypto_init); ++EXPORT_SYMBOL_GPL(nx842_crypto_alloc_ctx); + +-void nx842_crypto_exit(struct crypto_tfm *tfm) ++void nx842_crypto_free_ctx(void *p) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = p; + + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); + } +-EXPORT_SYMBOL_GPL(nx842_crypto_exit); ++EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx); + + static void check_constraints(struct nx842_constraints *c) + { +@@ -246,11 +251,11 @@ nospc: + return update_param(p, slen, dskip + dlen); + } + +-int nx842_crypto_compress(struct crypto_tfm *tfm, ++int nx842_crypto_compress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ u8 *dst, unsigned int *dlen, void *pctx) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_header *hdr = + container_of(&ctx->header, + struct nx842_crypto_header, hdr); +@@ -431,11 +436,11 @@ usesw: + return update_param(p, slen + padding, dlen); + } + +-int nx842_crypto_decompress(struct crypto_tfm *tfm, ++int nx842_crypto_decompress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ u8 *dst, unsigned int *dlen, void *pctx) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_header *hdr; + struct nx842_crypto_param p; + struct nx842_constraints c = *ctx->driver->constraints; +--- a/drivers/crypto/nx/nx-842.h ++++ b/drivers/crypto/nx/nx-842.h +@@ -101,6 +101,8 @@ + #define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1))) + #define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE) + ++struct crypto_scomp; ++ + static inline unsigned long nx842_get_pa(void *addr) + { + if (!is_vmalloc_addr(addr)) +@@ -179,13 +181,13 @@ struct nx842_crypto_ctx { + struct nx842_driver *driver; + }; + +-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver); +-void nx842_crypto_exit(struct crypto_tfm *tfm); +-int nx842_crypto_compress(struct crypto_tfm *tfm, ++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver); ++void nx842_crypto_free_ctx(void *ctx); ++int nx842_crypto_compress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); +-int nx842_crypto_decompress(struct crypto_tfm *tfm, ++ u8 *dst, unsigned int *dlen, void *ctx); ++int nx842_crypto_decompress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); ++ u8 *dst, unsigned int *dlen, void *ctx); + + #endif /* __NX_842_H__ */ +--- a/drivers/crypto/nx/nx-common-powernv.c ++++ b/drivers/crypto/nx/nx-common-powernv.c +@@ -9,6 +9,7 @@ + + #include "nx-842.h" + ++#include + #include + + #include +@@ -1034,23 +1035,21 @@ static struct nx842_driver nx842_powernv + .decompress = nx842_powernv_decompress, + }; + +-static int nx842_powernv_crypto_init(struct crypto_tfm *tfm) ++static void *nx842_powernv_crypto_alloc_ctx(void) + { +- return nx842_crypto_init(tfm, &nx842_powernv_driver); ++ return nx842_crypto_alloc_ctx(&nx842_powernv_driver); + } + +-static struct crypto_alg nx842_powernv_alg = { +- .cra_name = "842", +- .cra_driver_name = "842-nx", +- .cra_priority = 300, +- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, +- .cra_ctxsize = sizeof(struct nx842_crypto_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = nx842_powernv_crypto_init, +- .cra_exit = nx842_crypto_exit, +- .cra_u = { .compress = { +- .coa_compress = nx842_crypto_compress, +- .coa_decompress = nx842_crypto_decompress } } ++static struct scomp_alg nx842_powernv_alg = { ++ .base.cra_name = "842", ++ .base.cra_driver_name = "842-nx", ++ .base.cra_priority = 300, ++ .base.cra_module = THIS_MODULE, ++ ++ .alloc_ctx = nx842_powernv_crypto_alloc_ctx, ++ .free_ctx = nx842_crypto_free_ctx, ++ .compress = nx842_crypto_compress, ++ .decompress = nx842_crypto_decompress, + }; + + static __init int nx_compress_powernv_init(void) +@@ -1110,7 +1109,7 @@ static __init int nx_compress_powernv_in + nx842_powernv_exec = nx842_exec_vas; + } + +- ret = crypto_register_alg(&nx842_powernv_alg); ++ ret = crypto_register_scomp(&nx842_powernv_alg); + if (ret) { + nx_delete_coprocs(); + return ret; +@@ -1131,7 +1130,7 @@ static void __exit nx_compress_powernv_e + if (!nx842_ct) + vas_unregister_api_powernv(); + +- crypto_unregister_alg(&nx842_powernv_alg); ++ crypto_unregister_scomp(&nx842_powernv_alg); + + nx_delete_coprocs(); + } +--- a/drivers/crypto/nx/nx-common-pseries.c ++++ b/drivers/crypto/nx/nx-common-pseries.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "nx-842.h" + #include "nx_csbcpb.h" /* struct nx_csbcpb */ +@@ -1006,23 +1007,21 @@ static struct nx842_driver nx842_pseries + .decompress = nx842_pseries_decompress, + }; + +-static int nx842_pseries_crypto_init(struct crypto_tfm *tfm) ++static void *nx842_pseries_crypto_alloc_ctx(void) + { +- return nx842_crypto_init(tfm, &nx842_pseries_driver); ++ return nx842_crypto_alloc_ctx(&nx842_pseries_driver); + } + +-static struct crypto_alg nx842_pseries_alg = { +- .cra_name = "842", +- .cra_driver_name = "842-nx", +- .cra_priority = 300, +- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, +- .cra_ctxsize = sizeof(struct nx842_crypto_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = nx842_pseries_crypto_init, +- .cra_exit = nx842_crypto_exit, +- .cra_u = { .compress = { +- .coa_compress = nx842_crypto_compress, +- .coa_decompress = nx842_crypto_decompress } } ++static struct scomp_alg nx842_pseries_alg = { ++ .base.cra_name = "842", ++ .base.cra_driver_name = "842-nx", ++ .base.cra_priority = 300, ++ .base.cra_module = THIS_MODULE, ++ ++ .alloc_ctx = nx842_pseries_crypto_alloc_ctx, ++ .free_ctx = nx842_crypto_free_ctx, ++ .compress = nx842_crypto_compress, ++ .decompress = nx842_crypto_decompress, + }; + + static int nx842_probe(struct vio_dev *viodev, +@@ -1070,7 +1069,7 @@ static int nx842_probe(struct vio_dev *v + if (ret) + goto error; + +- ret = crypto_register_alg(&nx842_pseries_alg); ++ ret = crypto_register_scomp(&nx842_pseries_alg); + if (ret) { + dev_err(&viodev->dev, "could not register comp alg: %d\n", ret); + goto error; +@@ -1118,7 +1117,7 @@ static void nx842_remove(struct vio_dev + if (caps_feat) + sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group); + +- crypto_unregister_alg(&nx842_pseries_alg); ++ crypto_unregister_scomp(&nx842_pseries_alg); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, +@@ -1250,7 +1249,7 @@ static void __exit nx842_pseries_exit(vo + + vas_unregister_api_pseries(); + +- crypto_unregister_alg(&nx842_pseries_alg); ++ crypto_unregister_scomp(&nx842_pseries_alg); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, diff --git a/queue-6.1/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch b/queue-6.1/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch new file mode 100644 index 0000000000..e80a06703d --- /dev/null +++ b/queue-6.1/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch @@ -0,0 +1,58 @@ +From stable+bounces-244936-greg=kroah.com@vger.kernel.org Sat May 9 17:56:21 2026 +From: Sasha Levin +Date: Sat, 9 May 2026 08:26:09 -0400 +Subject: erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap() +To: stable@vger.kernel.org +Cc: Junrui Luo , Yuhao Jiang , Gao Xiang , Sasha Levin +Message-ID: <20260509122609.3351909-1-sashal@kernel.org> + +From: Junrui Luo + +[ Upstream commit 21e161de2dc660b1bb70ef5b156ab8e6e1cca3ab ] + +Some crafted images can have illegal (!partial_decoding && +m_llen < m_plen) extents, and the LZ4 inplace decompression path +can be wrongly hit, but it cannot handle (outpages < inpages) +properly: "outpages - inpages" wraps to a large value and +the subsequent rq->out[] access reads past the decompressed_pages +array. + +However, such crafted cases can correctly result in a corruption +report in the normal LZ4 non-inplace path. + +Let's add an additional check to fix this for backporting. + +Reproducible image (base64-encoded gzipped blob): + +H4sIAJGR12kCA+3SPUoDQRgG4MkmkkZk8QRbRFIIi9hbpEjrHQI5ghfwCN5BLCzTGtLbBI+g +dilSJo1CnIm7GEXFxhT6PDDwfrs73/ywIQD/1ePD4r7Ou6ETsrq4mu7XcWfj++Pb58nJU/9i +PNtbjhan04/9GtX4qVYc814WDqt6FaX5s+ZwXXeq52lndT6IuVvlblytLMvh4Gzwaf90nsvz +2DF/21+20T/ldgp5s1jXRaN4t/8izsy/OUB6e/Qa79r+JwAAAAAAAL52vQVuGQAAAP6+my1w +ywAAAAAAAADwu14ATsEYtgBQAAA= + +$ mount -t erofs -o cache_strategy=disabled foo.erofs /mnt +$ dd if=/mnt/data of=/dev/null bs=4096 count=1 + +Fixes: 598162d05080 ("erofs: support decompress big pcluster for lz4 backend") +Reported-by: Yuhao Jiang +Cc: stable@vger.kernel.org +Signed-off-by: Junrui Luo +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +[ inverted condition to early-out `goto docopy` form and used `ctx->inpages`/`ctx->outpages` instead of `rq->` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/decompressor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/erofs/decompressor.c ++++ b/fs/erofs/decompressor.c +@@ -133,6 +133,7 @@ static void *z_erofs_lz4_handle_overlap( + if (rq->inplace_io) { + omargin = PAGE_ALIGN(ctx->oend) - ctx->oend; + if (rq->partial_decoding || !may_inplace || ++ ctx->outpages < ctx->inpages || + omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize)) + goto docopy; + diff --git a/queue-6.1/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch b/queue-6.1/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch new file mode 100644 index 0000000000..1d86452610 --- /dev/null +++ b/queue-6.1/f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch @@ -0,0 +1,102 @@ +From stable+bounces-249888-greg=kroah.com@vger.kernel.org Wed May 20 17:12:40 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 07:29:17 -0400 +Subject: f2fs: fix false alarm of lockdep on cp_global_sem lock +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Shin'ichiro Kawasaki , Jaegeuk Kim , Sasha Levin +Message-ID: <20260520112917.3439771-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 6a5e3de9c2bb0b691d16789a5d19e9276a09b308 ] + +lockdep reported a potential deadlock: + +a) TCMU device removal context: + - call del_gendisk() to get q->q_usage_counter + - call start_flush_work() to get work_completion of wb->dwork +b) f2fs writeback context: + - in wb_workfn(), which holds work_completion of wb->dwork + - call f2fs_balance_fs() to get sbi->gc_lock +c) f2fs vfs_write context: + - call f2fs_gc() to get sbi->gc_lock + - call f2fs_write_checkpoint() to get sbi->cp_global_sem +d) f2fs mount context: + - call recover_fsync_data() to get sbi->cp_global_sem + - call f2fs_check_and_fix_write_pointer() to call blkdev_report_zones() + that goes down to blk_mq_alloc_request and get q->q_usage_counter + +Original callstack is in Closes tag. + +However, I think this is a false alarm due to before mount returns +successfully (context d), we can not access file therein via vfs_write +(context c). + +Let's introduce per-sb cp_global_sem_key, and assign the key for +cp_global_sem, so that lockdep can recognize cp_global_sem from +different super block correctly. + +A lot of work are done by Shin'ichiro Kawasaki, thanks a lot for +the work. + +Fixes: c426d99127b1 ("f2fs: Check write pointer consistency of open zones") +Cc: stable@kernel.org +Reported-and-tested-by: Shin'ichiro Kawasaki +Closes: https://lore.kernel.org/linux-f2fs-devel/20260218125237.3340441-1-shinichiro.kawasaki@wdc.com +Signed-off-by: Shin'ichiro Kawasaki +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ re-anchored lockdep_register_key after init_f2fs_rwsem and placed lockdep_unregister_key before kfree(sbi) in f2fs_put_super instead of kill_f2fs_super ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 3 +++ + fs/f2fs/super.c | 11 +++++++++++ + 2 files changed, 14 insertions(+) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1853,6 +1853,9 @@ struct f2fs_sb_info { + spinlock_t iostat_lat_lock; + struct iostat_lat_info *iostat_io_lat; + #endif ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ struct lock_class_key cp_global_sem_key; ++#endif + }; + + #ifdef CONFIG_F2FS_FAULT_INJECTION +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1687,6 +1687,9 @@ static void f2fs_put_super(struct super_ + #if IS_ENABLED(CONFIG_UNICODE) + utf8_unload(sb->s_encoding); + #endif ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ lockdep_unregister_key(&sbi->cp_global_sem_key); ++#endif + kfree(sbi); + } + +@@ -4188,6 +4191,11 @@ try_onemore: + init_f2fs_rwsem(&sbi->gc_lock); + mutex_init(&sbi->writepages); + init_f2fs_rwsem(&sbi->cp_global_sem); ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ lockdep_register_key(&sbi->cp_global_sem_key); ++ lockdep_set_class(&sbi->cp_global_sem.internal_rwsem, ++ &sbi->cp_global_sem_key); ++#endif + init_f2fs_rwsem(&sbi->node_write); + init_f2fs_rwsem(&sbi->node_change); + spin_lock_init(&sbi->stat_lock); +@@ -4651,6 +4659,9 @@ free_sb_buf: + free_sbi: + if (sbi->s_chksum_driver) + crypto_free_shash(sbi->s_chksum_driver); ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++ lockdep_unregister_key(&sbi->cp_global_sem_key); ++#endif + kfree(sbi); + + /* give only one another chance */ diff --git a/queue-6.1/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch b/queue-6.1/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch new file mode 100644 index 0000000000..e5aff72c6a --- /dev/null +++ b/queue-6.1/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch @@ -0,0 +1,68 @@ +From stable+bounces-249813-greg=kroah.com@vger.kernel.org Wed May 20 16:52:16 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 07:16:27 -0400 +Subject: f2fs: fix incorrect file address mapping when inline inode is unwritten +To: stable@vger.kernel.org +Cc: Yongpeng Yang , stable@kernel.org, Chao Yu , Jaegeuk Kim , Sasha Levin +Message-ID: <20260520111627.3416675-1-sashal@kernel.org> + +From: Yongpeng Yang + +[ Upstream commit 68a0178981a0f493295afa29f8880246e561494c ] + +When `fileinfo->fi_flags` does not have the `FIEMAP_FLAG_SYNC` bit set +and inline data has not been persisted yet, the physical address of the +extent is calculated incorrectly for unwritten inline inodes. + +root@vm:/mnt/f2fs# dd if=/dev/zero of=data.3k bs=3k count=1 +root@vm:/mnt/f2fs# f2fs_io fiemap 0 100 data.3k +Fiemap: offset = 0 len = 100 + logical addr. physical addr. length flags +0 0000000000000000 00000ffffffff16c 0000000000000c00 00000301 + +This patch fixes the issue by checking if the inode's address is valid. +If the inline inode is unwritten, set the physical address to 0 and +mark the extent with `FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC` +flags. + +Cc: stable@kernel.org +Fixes: 67f8cf3cee6f ("f2fs: support fiemap for inline_data") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ renamed `ifolio` to `ipage` in `inline_data_addr()` and `F2FS_INODE()` calls ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/inline.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/fs/f2fs/inline.c ++++ b/fs/f2fs/inline.c +@@ -774,7 +774,7 @@ int f2fs_read_inline_dir(struct file *fi + int f2fs_inline_data_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) + { +- __u64 byteaddr, ilen; ++ __u64 byteaddr = 0, ilen; + __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | + FIEMAP_EXTENT_LAST; + struct node_info ni; +@@ -807,9 +807,14 @@ int f2fs_inline_data_fiemap(struct inode + if (err) + goto out; + +- byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; +- byteaddr += (char *)inline_data_addr(inode, ipage) - +- (char *)F2FS_INODE(ipage); ++ if (__is_valid_data_blkaddr(ni.blk_addr)) { ++ byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; ++ byteaddr += (char *)inline_data_addr(inode, ipage) - ++ (char *)F2FS_INODE(ipage); ++ } else { ++ f2fs_bug_on(F2FS_I_SB(inode), ni.blk_addr != NEW_ADDR); ++ flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; ++ } + err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags); + trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err); + out: diff --git a/queue-6.1/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch b/queue-6.1/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch new file mode 100644 index 0000000000..15998892fd --- /dev/null +++ b/queue-6.1/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch @@ -0,0 +1,56 @@ +From stable+bounces-247665-greg=kroah.com@vger.kernel.org Fri May 15 17:31:07 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 07:31:45 -0400 +Subject: fbcon: Avoid OOB font access if console rotation fails +To: stable@vger.kernel.org +Cc: Thomas Zimmermann , Helge Deller , Sasha Levin +Message-ID: <20260515113145.2964271-1-sashal@kernel.org> + +From: Thomas Zimmermann + +[ Upstream commit e4ef723d8975a2694cc90733a6b888a5e2841842 ] + +Clear the font buffer if the reallocation during console rotation fails +in fbcon_rotate_font(). The putcs implementations for the rotated buffer +will return early in this case. See [1] for an example. + +Currently, fbcon_rotate_font() keeps the old buffer, which is too small +for the rotated font. Printing to the rotated console with a high-enough +character code will overflow the font buffer. + +v2: +- fix typos in commit message + +Signed-off-by: Thomas Zimmermann +Fixes: 6cc50e1c5b57 ("[PATCH] fbcon: Console Rotation - Add support to rotate font bitmap") +Cc: stable@vger.kernel.org # v2.6.15+ +Link: https://elixir.bootlin.com/linux/v6.19/source/drivers/video/fbdev/core/fbcon_ccw.c#L144 # [1] +Signed-off-by: Helge Deller +[ renamed `par` to `ops` to match the 6.12 local pointer name ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/video/fbdev/core/fbcon_rotate.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -46,6 +46,10 @@ static int fbcon_rotate_font(struct fb_i + info->fbops->fb_sync(info); + + if (ops->fd_size < d_cellsize * len) { ++ kfree(ops->fontbuffer); ++ ops->fontbuffer = NULL; ++ ops->fd_size = 0; ++ + dst = kmalloc_array(len, d_cellsize, GFP_KERNEL); + + if (dst == NULL) { +@@ -54,7 +58,6 @@ static int fbcon_rotate_font(struct fb_i + } + + ops->fd_size = d_cellsize * len; +- kfree(ops->fontbuffer); + ops->fontbuffer = dst; + } + diff --git a/queue-6.1/genetlink-use-internal-flags-for-multicast-groups.patch b/queue-6.1/genetlink-use-internal-flags-for-multicast-groups.patch new file mode 100644 index 0000000000..ccf91f00ae --- /dev/null +++ b/queue-6.1/genetlink-use-internal-flags-for-multicast-groups.patch @@ -0,0 +1,116 @@ +From stable+bounces-256667-greg=kroah.com@vger.kernel.org Fri May 29 22:36:19 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 13:06:09 -0400 +Subject: genetlink: Use internal flags for multicast groups +To: stable@vger.kernel.org +Cc: Ido Schimmel , Mat Martineau , Andy Shevchenko , "David S. Miller" , Sasha Levin +Message-ID: <20260529170610.1279657-1-sashal@kernel.org> + +From: Ido Schimmel + +[ Upstream commit cd4d7263d58ab98fd4dee876776e4da6c328faa3 ] + +As explained in commit e03781879a0d ("drop_monitor: Require +'CAP_SYS_ADMIN' when joining "events" group"), the "flags" field in the +multicast group structure reuses uAPI flags despite the field not being +exposed to user space. This makes it impossible to extend its use +without adding new uAPI flags, which is inappropriate for internal +kernel checks. + +Solve this by adding internal flags (i.e., "GENL_MCAST_*") and convert +the existing users to use them instead of the uAPI flags. + +Tested using the reproducers in commit 44ec98ea5ea9 ("psample: Require +'CAP_NET_ADMIN' when joining "packets" group") and commit e03781879a0d +("drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group"). + +No functional changes intended. + +Signed-off-by: Ido Schimmel +Reviewed-by: Mat Martineau +Reviewed-by: Andy Shevchenko +Signed-off-by: David S. Miller +Stable-dep-of: d1ebfce2c1d1 ("smb: client: require net admin for CIFS SWN netlink") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/net/genetlink.h | 9 ++++++--- + net/core/drop_monitor.c | 2 +- + net/mptcp/pm_netlink.c | 2 +- + net/netlink/genetlink.c | 4 ++-- + net/psample/psample.c | 2 +- + 5 files changed, 11 insertions(+), 8 deletions(-) + +--- a/include/net/genetlink.h ++++ b/include/net/genetlink.h +@@ -8,16 +8,19 @@ + + #define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN) + ++/* Binding to multicast group requires %CAP_NET_ADMIN */ ++#define GENL_MCAST_CAP_NET_ADMIN BIT(0) ++/* Binding to multicast group requires %CAP_SYS_ADMIN */ ++#define GENL_MCAST_CAP_SYS_ADMIN BIT(1) ++ + /** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family +- * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM) +- * @cap_sys_admin: whether %CAP_SYS_ADMIN is required for binding ++ * @flags: GENL_MCAST_* flags + */ + struct genl_multicast_group { + char name[GENL_NAMSIZ]; + u8 flags; +- u8 cap_sys_admin:1; + }; + + struct genl_ops; +--- a/net/core/drop_monitor.c ++++ b/net/core/drop_monitor.c +@@ -181,7 +181,7 @@ out: + } + + static const struct genl_multicast_group dropmon_mcgrps[] = { +- { .name = "events", .cap_sys_admin = 1 }, ++ { .name = "events", .flags = GENL_MCAST_CAP_SYS_ADMIN, }, + }; + + static void send_dm_alert(struct work_struct *work) +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -1313,7 +1313,7 @@ bool mptcp_pm_nl_is_backup(struct mptcp_ + static const struct genl_multicast_group mptcp_pm_mcgrps[] = { + [MPTCP_PM_CMD_GRP_OFFSET] = { .name = MPTCP_PM_CMD_GRP_NAME, }, + [MPTCP_PM_EV_GRP_OFFSET] = { .name = MPTCP_PM_EV_GRP_NAME, +- .flags = GENL_UNS_ADMIN_PERM, ++ .flags = GENL_MCAST_CAP_NET_ADMIN, + }, + }; + +--- a/net/netlink/genetlink.c ++++ b/net/netlink/genetlink.c +@@ -1431,10 +1431,10 @@ static int genl_bind(struct net *net, in + continue; + + grp = &family->mcgrps[i]; +- if ((grp->flags & GENL_UNS_ADMIN_PERM) && ++ if ((grp->flags & GENL_MCAST_CAP_NET_ADMIN) && + !ns_capable(net->user_ns, CAP_NET_ADMIN)) + ret = -EPERM; +- if (grp->cap_sys_admin && ++ if ((grp->flags & GENL_MCAST_CAP_SYS_ADMIN) && + !ns_capable(net->user_ns, CAP_SYS_ADMIN)) + ret = -EPERM; + +--- a/net/psample/psample.c ++++ b/net/psample/psample.c +@@ -32,7 +32,7 @@ enum psample_nl_multicast_groups { + static const struct genl_multicast_group psample_nl_mcgrps[] = { + [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME }, + [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME, +- .flags = GENL_UNS_ADMIN_PERM }, ++ .flags = GENL_MCAST_CAP_NET_ADMIN, }, + }; + + static struct genl_family psample_nl_family __ro_after_init; diff --git a/queue-6.1/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch b/queue-6.1/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch new file mode 100644 index 0000000000..6dedc97513 --- /dev/null +++ b/queue-6.1/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch @@ -0,0 +1,142 @@ +From stable+bounces-244868-greg=kroah.com@vger.kernel.org Sat May 9 06:28:19 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 20:58:08 -0400 +Subject: hfsplus: fix held lock freed on hfsplus_fill_super() +To: stable@vger.kernel.org +Cc: Zilin Guan , Viacheslav Dubeyko , Sasha Levin +Message-ID: <20260509005809.2569358-2-sashal@kernel.org> + +From: Zilin Guan + +[ Upstream commit 90c500e4fd83fa33c09bc7ee23b6d9cc487ac733 ] + +hfsplus_fill_super() calls hfs_find_init() to initialize a search +structure, which acquires tree->tree_lock. If the subsequent call to +hfsplus_cat_build_key() fails, the function jumps to the out_put_root +error label without releasing the lock. The later cleanup path then +frees the tree data structure with the lock still held, triggering a +held lock freed warning. + +Fix this by adding the missing hfs_find_exit(&fd) call before jumping +to the out_put_root error label. This ensures that tree->tree_lock is +properly released on the error path. + +The bug was originally detected on v6.13-rc1 using an experimental +static analysis tool we are developing, and we have verified that the +issue persists in the latest mainline kernel. The tool is specifically +designed to detect memory management issues. It is currently under active +development and not yet publicly available. + +We confirmed the bug by runtime testing under QEMU with x86_64 defconfig, +lockdep enabled, and CONFIG_HFSPLUS_FS=y. To trigger the error path, we +used GDB to dynamically shrink the max_unistr_len parameter to 1 before +hfsplus_asc2uni() is called. This forces hfsplus_asc2uni() to naturally +return -ENAMETOOLONG, which propagates to hfsplus_cat_build_key() and +exercises the faulty error path. The following warning was observed +during mount: + + ========================= + WARNING: held lock freed! + 7.0.0-rc3-00016-gb4f0dd314b39 #4 Not tainted + ------------------------- + mount/174 is freeing memory ffff888103f92000-ffff888103f92fff, with a lock still held there! + ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0 + 2 locks held by mount/174: + #0: ffff888103f960e0 (&type->s_umount_key#42/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x167/0xa40 + #1: ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0 + + stack backtrace: + CPU: 2 UID: 0 PID: 174 Comm: mount Not tainted 7.0.0-rc3-00016-gb4f0dd314b39 #4 PREEMPT(lazy) + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 + Call Trace: + + dump_stack_lvl+0x82/0xd0 + debug_check_no_locks_freed+0x13a/0x180 + kfree+0x16b/0x510 + ? hfsplus_fill_super+0xcb4/0x18a0 + hfsplus_fill_super+0xcb4/0x18a0 + ? __pfx_hfsplus_fill_super+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? bdev_open+0x65f/0xc30 + ? srso_return_thunk+0x5/0x5f + ? pointer+0x4ce/0xbf0 + ? trace_contention_end+0x11c/0x150 + ? __pfx_pointer+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? bdev_open+0x79b/0xc30 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? vsnprintf+0x6da/0x1270 + ? srso_return_thunk+0x5/0x5f + ? __mutex_unlock_slowpath+0x157/0x740 + ? __pfx_vsnprintf+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? mark_held_locks+0x49/0x80 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? irqentry_exit+0x17b/0x5e0 + ? trace_irq_disable.constprop.0+0x116/0x150 + ? __pfx_hfsplus_fill_super+0x10/0x10 + ? __pfx_hfsplus_fill_super+0x10/0x10 + get_tree_bdev_flags+0x302/0x580 + ? __pfx_get_tree_bdev_flags+0x10/0x10 + ? vfs_parse_fs_qstr+0x129/0x1a0 + ? __pfx_vfs_parse_fs_qstr+0x3/0x10 + vfs_get_tree+0x89/0x320 + fc_mount+0x10/0x1d0 + path_mount+0x5c5/0x21c0 + ? __pfx_path_mount+0x10/0x10 + ? trace_irq_enable.constprop.0+0x116/0x150 + ? trace_irq_enable.constprop.0+0x116/0x150 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? kmem_cache_free+0x307/0x540 + ? user_path_at+0x51/0x60 + ? __x64_sys_mount+0x212/0x280 + ? srso_return_thunk+0x5/0x5f + __x64_sys_mount+0x212/0x280 + ? __pfx___x64_sys_mount+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + ? trace_irq_enable.constprop.0+0x116/0x150 + ? srso_return_thunk+0x5/0x5f + do_syscall_64+0x111/0x680 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7ffacad55eae + Code: 48 8b 0d 85 1f 0f 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 8 + RSP: 002b:00007fff1ab55718 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5 + RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ffacad55eae + RDX: 000055740c64e5b0 RSI: 000055740c64e630 RDI: 000055740c651ab0 + RBP: 000055740c64e380 R08: 0000000000000000 R09: 0000000000000001 + R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + R13: 000055740c64e5b0 R14: 000055740c651ab0 R15: 000055740c64e380 + + +After applying this patch, the warning no longer appears. + +Fixes: 89ac9b4d3d1a ("hfsplus: fix longname handling") +CC: stable@vger.kernel.org +Signed-off-by: Zilin Guan +Reviewed-by: Viacheslav Dubeyko +Tested-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/hfsplus/super.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/hfsplus/super.c ++++ b/fs/hfsplus/super.c +@@ -539,8 +539,10 @@ static int hfsplus_fill_super(struct sup + if (err) + goto out_put_root; + err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); +- if (unlikely(err < 0)) ++ if (unlikely(err < 0)) { ++ hfs_find_exit(&fd); + goto out_put_root; ++ } + if (!hfsplus_brec_read_cat(&fd, &entry)) { + hfs_find_exit(&fd); + if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) { diff --git a/queue-6.1/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch b/queue-6.1/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch new file mode 100644 index 0000000000..81851f627d --- /dev/null +++ b/queue-6.1/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch @@ -0,0 +1,189 @@ +From stable+bounces-244867-greg=kroah.com@vger.kernel.org Sat May 9 06:28:16 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 20:58:07 -0400 +Subject: hfsplus: fix uninit-value by validating catalog record size +To: stable@vger.kernel.org +Cc: Deepanshu Kartikey , syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com, Viacheslav Dubeyko , Charalampos Mitrodimas , Sasha Levin +Message-ID: <20260509005809.2569358-1-sashal@kernel.org> + +From: Deepanshu Kartikey + +[ Upstream commit b6b592275aeff184aa82fcf6abccd833fb71b393 ] + +Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp(). The +root cause is that hfs_brec_read() doesn't validate that the on-disk +record size matches the expected size for the record type being read. + +When mounting a corrupted filesystem, hfs_brec_read() may read less data +than expected. For example, when reading a catalog thread record, the +debug output showed: + + HFSPLUS_BREC_READ: rec_len=520, fd->entrylength=26 + HFSPLUS_BREC_READ: WARNING - entrylength (26) < rec_len (520) - PARTIAL READ! + +hfs_brec_read() only validates that entrylength is not greater than the +buffer size, but doesn't check if it's less than expected. It successfully +reads 26 bytes into a 520-byte structure and returns success, leaving 494 +bytes uninitialized. + +This uninitialized data in tmp.thread.nodeName then gets copied by +hfsplus_cat_build_key_uni() and used by hfsplus_strcasecmp(), triggering +the KMSAN warning when the uninitialized bytes are used as array indices +in case_fold(). + +Fix by introducing hfsplus_brec_read_cat() wrapper that: +1. Calls hfs_brec_read() to read the data +2. Validates the record size based on the type field: + - Fixed size for folder and file records + - Variable size for thread records (depends on string length) +3. Returns -EIO if size doesn't match expected + +For thread records, check against HFSPLUS_MIN_THREAD_SZ before reading +nodeName.length to avoid reading uninitialized data at call sites that +don't zero-initialize the entry structure. + +Also initialize the tmp variable in hfsplus_find_cat() as defensive +programming to ensure no uninitialized data even if validation is +bypassed. + +Reported-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Tested-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com +Reviewed-by: Viacheslav Dubeyko +Tested-by: Viacheslav Dubeyko +Suggested-by: Charalampos Mitrodimas +Link: https://lore.kernel.org/all/20260120051114.1281285-1-kartikey406@gmail.com/ [v1] +Link: https://lore.kernel.org/all/20260121063109.1830263-1-kartikey406@gmail.com/ [v2] +Link: https://lore.kernel.org/all/20260212014233.2422046-1-kartikey406@gmail.com/ [v3] +Link: https://lore.kernel.org/all/20260214002100.436125-1-kartikey406@gmail.com/T/ [v4] +Link: https://lore.kernel.org/all/20260221061626.15853-1-kartikey406@gmail.com/T/ [v5] +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260307010302.41547-1-kartikey406@gmail.com +Signed-off-by: Viacheslav Dubeyko +Stable-dep-of: 90c500e4fd83 ("hfsplus: fix held lock freed on hfsplus_fill_super()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/hfsplus/bfind.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ + fs/hfsplus/catalog.c | 4 +-- + fs/hfsplus/dir.c | 2 - + fs/hfsplus/hfsplus_fs.h | 9 ++++++++ + fs/hfsplus/super.c | 2 - + 5 files changed, 64 insertions(+), 4 deletions(-) + +--- a/fs/hfsplus/bfind.c ++++ b/fs/hfsplus/bfind.c +@@ -287,3 +287,54 @@ out: + fd->bnode = bnode; + return res; + } ++ ++/** ++ * hfsplus_brec_read_cat - read and validate a catalog record ++ * @fd: find data structure ++ * @entry: pointer to catalog entry to read into ++ * ++ * Reads a catalog record and validates its size matches the expected ++ * size based on the record type. ++ * ++ * Returns 0 on success, or negative error code on failure. ++ */ ++int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry) ++{ ++ int res; ++ u32 expected_size; ++ ++ res = hfs_brec_read(fd, entry, sizeof(hfsplus_cat_entry)); ++ if (res) ++ return res; ++ ++ /* Validate catalog record size based on type */ ++ switch (be16_to_cpu(entry->type)) { ++ case HFSPLUS_FOLDER: ++ expected_size = sizeof(struct hfsplus_cat_folder); ++ break; ++ case HFSPLUS_FILE: ++ expected_size = sizeof(struct hfsplus_cat_file); ++ break; ++ case HFSPLUS_FOLDER_THREAD: ++ case HFSPLUS_FILE_THREAD: ++ /* Ensure we have at least the fixed fields before reading nodeName.length */ ++ if (fd->entrylength < HFSPLUS_MIN_THREAD_SZ) { ++ pr_err("thread record too short (got %u)\n", fd->entrylength); ++ return -EIO; ++ } ++ expected_size = hfsplus_cat_thread_size(&entry->thread); ++ break; ++ default: ++ pr_err("unknown catalog record type %d\n", ++ be16_to_cpu(entry->type)); ++ return -EIO; ++ } ++ ++ if (fd->entrylength != expected_size) { ++ pr_err("catalog record size mismatch (type %d, got %u, expected %u)\n", ++ be16_to_cpu(entry->type), fd->entrylength, expected_size); ++ return -EIO; ++ } ++ ++ return 0; ++} +--- a/fs/hfsplus/catalog.c ++++ b/fs/hfsplus/catalog.c +@@ -194,12 +194,12 @@ static int hfsplus_fill_cat_thread(struc + int hfsplus_find_cat(struct super_block *sb, u32 cnid, + struct hfs_find_data *fd) + { +- hfsplus_cat_entry tmp; ++ hfsplus_cat_entry tmp = {0}; + int err; + u16 type; + + hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid); +- err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); ++ err = hfsplus_brec_read_cat(fd, &tmp); + if (err) + return err; + +--- a/fs/hfsplus/dir.c ++++ b/fs/hfsplus/dir.c +@@ -49,7 +49,7 @@ static struct dentry *hfsplus_lookup(str + if (unlikely(err < 0)) + goto fail; + again: +- err = hfs_brec_read(&fd, &entry, sizeof(entry)); ++ err = hfsplus_brec_read_cat(&fd, &entry); + if (err) { + if (err == -ENOENT) { + hfs_find_exit(&fd); +--- a/fs/hfsplus/hfsplus_fs.h ++++ b/fs/hfsplus/hfsplus_fs.h +@@ -535,6 +535,15 @@ int hfsplus_submit_bio(struct super_bloc + void **data, blk_opf_t opf); + int hfsplus_read_wrapper(struct super_block *sb); + ++static inline u32 hfsplus_cat_thread_size(const struct hfsplus_cat_thread *thread) ++{ ++ return offsetof(struct hfsplus_cat_thread, nodeName) + ++ offsetof(struct hfsplus_unistr, unicode) + ++ be16_to_cpu(thread->nodeName.length) * sizeof(hfsplus_unichr); ++} ++ ++int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry); ++ + /* + * time helpers: convert between 1904-base and 1970-base timestamps + * +--- a/fs/hfsplus/super.c ++++ b/fs/hfsplus/super.c +@@ -541,7 +541,7 @@ static int hfsplus_fill_super(struct sup + err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); + if (unlikely(err < 0)) + goto out_put_root; +- if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { ++ if (!hfsplus_brec_read_cat(&fd, &entry)) { + hfs_find_exit(&fd); + if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) { + err = -EIO; diff --git a/queue-6.1/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch b/queue-6.1/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch new file mode 100644 index 0000000000..1fc27a7226 --- /dev/null +++ b/queue-6.1/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch @@ -0,0 +1,92 @@ +From stable+bounces-263427-greg=kroah.com@vger.kernel.org Mon Jun 15 23:43:51 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 14:13:00 -0400 +Subject: hv_netvsc: use kmap_local_page in netvsc_copy_to_send_buf +To: stable@vger.kernel.org +Cc: Anton Leontev , Paolo Abeni , Sasha Levin +Message-ID: <20260615181300.2319407-1-sashal@kernel.org> + +From: Anton Leontev + +[ Upstream commit 004e9ecfe6c5384f9e0b2f6f6389d42ec22789af ] + +netvsc_copy_to_send_buf() copies page buffer entries into the VMBus +send buffer using phys_to_virt() on the entry PFN. Entries for the +RNDIS header and the skb linear data come from kmalloc'd memory and +are always in the kernel direct map, but entries for skb fragments +reference page cache or user pages, which on 32-bit x86 with +CONFIG_HIGHMEM=y can live above the LOWMEM boundary. For such a page +phys_to_virt() returns an address outside the direct map and the +subsequent memcpy() faults on the transmit softirq path, which is +fatal. + +Map the pages with kmap_local_page() instead, handling two properties +of the page buffer entries: + + - pb[i].pfn is a Hyper-V PFN at HV_HYP_PAGE_SIZE (4K) granularity, + not a native PFN. Reconstruct the physical address first and derive + the native page from it, so the mapping stays correct where + PAGE_SIZE > HV_HYP_PAGE_SIZE (e.g. arm64 with 64K pages). + + - Since commit 41a6328b2c55 ("hv_netvsc: Preserve contiguous PFN + grouping in the page buffer array"), an entry describes a full + physically contiguous fragment and pb[i].len can exceed PAGE_SIZE, + while kmap_local_page() maps a single page. Copy page by page, + splitting at native page boundaries. + +The copy path only handles packets smaller than the send section size +(6144 bytes by default); larger packets take the cp_partial path where +only the RNDIS header is copied. So entries here are bounded by the +section size and a copy is split at most once on 4K-page systems. On +!CONFIG_HIGHMEM configs kmap_local_page() folds to page_address() and +no mapping work is added. + +Fixes: c25aaf814a63 ("hyperv: Enable sendbuf mechanism on the send path") +Cc: stable@vger.kernel.org +Signed-off-by: Anton Leontev +Link: https://patch.msgid.link/20260604165938.32033-1-leontyevantony@gmail.com +Signed-off-by: Paolo Abeni +[ adapted `phys_to_page(paddr)` to `pfn_to_page(PHYS_PFN(paddr))` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/hyperv/netvsc.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -992,12 +993,22 @@ static void netvsc_copy_to_send_buf(stru + } + + for (i = 0; i < page_count; i++) { +- char *src = phys_to_virt(pb[i].pfn << HV_HYP_PAGE_SHIFT); +- u32 offset = pb[i].offset; ++ phys_addr_t paddr = (pb[i].pfn << HV_HYP_PAGE_SHIFT) + ++ pb[i].offset; + u32 len = pb[i].len; + +- memcpy(dest, (src + offset), len); +- dest += len; ++ while (len) { ++ struct page *page = pfn_to_page(PHYS_PFN(paddr)); ++ u32 off = offset_in_page(paddr); ++ u32 chunk = min_t(u32, len, PAGE_SIZE - off); ++ char *src = kmap_local_page(page); ++ ++ memcpy(dest, src + off, chunk); ++ kunmap_local(src); ++ dest += chunk; ++ paddr += chunk; ++ len -= chunk; ++ } + } + + if (padding) diff --git a/queue-6.1/ice-fix-vf-queue-configuration-with-low-mtu-values.patch b/queue-6.1/ice-fix-vf-queue-configuration-with-low-mtu-values.patch new file mode 100644 index 0000000000..2db4d2e3d7 --- /dev/null +++ b/queue-6.1/ice-fix-vf-queue-configuration-with-low-mtu-values.patch @@ -0,0 +1,63 @@ +From stable+bounces-256850-greg=kroah.com@vger.kernel.org Sat May 30 06:53:55 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 21:23:43 -0400 +Subject: ice: fix VF queue configuration with low MTU values +To: stable@vger.kernel.org +Cc: Jose Ignacio Tornos Martinez , Jacob Keller , Michal Swiatkowski , Paul Menzel , Rafal Romanowski , Tony Nguyen , Jakub Kicinski , Sasha Levin +Message-ID: <20260530012343.2600440-1-sashal@kernel.org> + +From: Jose Ignacio Tornos Martinez + +[ Upstream commit 3ba4dd024d26372733d1c02e13e076c6016e3320 ] + +The ice driver's VF queue configuration validation rejects +databuffer_size values below 1024 bytes, which prevents VFs from +using MTU values below 871 bytes. + +The iavf driver calculates databuffer_size based on the MTU using: + databuffer_size = ALIGN(MTU + LIBETH_RX_LL_LEN, 128) + +where LIBETH_RX_LL_LEN = 26 (ETH_HLEN + 2*VLAN_HLEN + ETH_FCS_LEN). + +For MTU values below 871: + MTU 870: 870 + 26 = 896, aligned to 128 = 896 (< 1024, rejected) + MTU 871: 871 + 26 = 897, aligned to 128 = 1024 (>= 1024, accepted) + +The 1024-byte minimum seems unnecessarily restrictive, because the hardware +supports databuffer_size as low as 128 bytes (the alignment boundary), +which should allow MTU values down to the standard minimum of 68 bytes. + +I haven't found the reason why the limit was configured in the commit +9c7dd7566d18 ("ice: add validation in OP_CONFIG_VSI_QUEUES VF message"), so +with no more information and since it is working, change the minimum +databuffer_size validation from 1024 to 128 bytes to allow standard low +MTU values while still preventing invalid configurations. + +Fixes: 9c7dd7566d18 ("ice: add validation in OP_CONFIG_VSI_QUEUES VF message") +cc: stable@vger.kernel.org +Signed-off-by: Jose Ignacio Tornos Martinez +Reviewed-by: Jacob Keller +Reviewed-by: Michal Swiatkowski +Reviewed-by: Paul Menzel +Tested-by: Rafal Romanowski +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260515182419.1597859-3-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +[ applied the change to ice_virtchnl.c ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/ice/ice_virtchnl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c ++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c +@@ -1648,7 +1648,7 @@ static int ice_vc_cfg_qs_msg(struct ice_ + + if (qpi->rxq.databuffer_size != 0 && + (qpi->rxq.databuffer_size > ((16 * 1024) - 128) || +- qpi->rxq.databuffer_size < 1024)) ++ qpi->rxq.databuffer_size < 128)) + goto error_param; + vsi->rx_buf_len = qpi->rxq.databuffer_size; + vsi->rx_rings[i]->rx_buf_len = vsi->rx_buf_len; diff --git a/queue-6.1/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch b/queue-6.1/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch new file mode 100644 index 0000000000..7af65782f2 --- /dev/null +++ b/queue-6.1/iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch @@ -0,0 +1,81 @@ +From stable+bounces-260504-greg=kroah.com@vger.kernel.org Thu Jun 4 19:33:20 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:45 -0400 +Subject: iio: adc: fix the return value handle for platform_get_irq() +To: stable@vger.kernel.org +Cc: Ruan Jinjie , Jonathan Cameron , Sasha Levin +Message-ID: <20260604135447.3493139-1-sashal@kernel.org> + +From: Ruan Jinjie + +[ Upstream commit c09ddcdd4dd32ee9768dc233ead4b3d726f26d38 ] + +There is no possible for platform_get_irq() to return 0 +and the return value of platform_get_irq() is more sensible +to show the error reason. + +Signed-off-by: Ruan Jinjie +Link: https://lore.kernel.org/r/20230727131607.2897937-1-ruanjinjie@huawei.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/adc/bcm_iproc_adc.c | 4 ++-- + drivers/iio/adc/lpc32xx_adc.c | 4 ++-- + drivers/iio/adc/npcm_adc.c | 4 ++-- + drivers/iio/adc/spear_adc.c | 4 ++-- + 4 files changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/iio/adc/bcm_iproc_adc.c ++++ b/drivers/iio/adc/bcm_iproc_adc.c +@@ -540,8 +540,8 @@ static int iproc_adc_probe(struct platfo + } + + adc_priv->irqno = platform_get_irq(pdev, 0); +- if (adc_priv->irqno <= 0) +- return -ENODEV; ++ if (adc_priv->irqno < 0) ++ return adc_priv->irqno; + + ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, + IPROC_ADC_AUXIN_SCAN_ENA, 0); +--- a/drivers/iio/adc/lpc32xx_adc.c ++++ b/drivers/iio/adc/lpc32xx_adc.c +@@ -173,8 +173,8 @@ static int lpc32xx_adc_probe(struct plat + } + + irq = platform_get_irq(pdev, 0); +- if (irq <= 0) +- return -ENXIO; ++ if (irq < 0) ++ return irq; + + retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, + LPC32XXAD_NAME, st); +--- a/drivers/iio/adc/npcm_adc.c ++++ b/drivers/iio/adc/npcm_adc.c +@@ -244,8 +244,8 @@ static int npcm_adc_probe(struct platfor + info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2); + + irq = platform_get_irq(pdev, 0); +- if (irq <= 0) { +- ret = -EINVAL; ++ if (irq < 0) { ++ ret = irq; + goto err_disable_clk; + } + +--- a/drivers/iio/adc/spear_adc.c ++++ b/drivers/iio/adc/spear_adc.c +@@ -311,8 +311,8 @@ static int spear_adc_probe(struct platfo + } + + irq = platform_get_irq(pdev, 0); +- if (irq <= 0) { +- ret = -EINVAL; ++ if (irq < 0) { ++ ret = irq; + goto errout2; + } + diff --git a/queue-6.1/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..3af4072deb --- /dev/null +++ b/queue-6.1/iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,60 @@ +From stable+bounces-260505-greg=kroah.com@vger.kernel.org Thu Jun 4 19:35:11 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:46 -0400 +Subject: iio: adc: npcm: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Jonathan Cameron" , "Sasha Levin" +Message-ID: <20260604135447.3493139-2-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 5253a5cc7709688b9a000f7928bfaa3366d0af98 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new() which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230919174931.1417681-18-u.kleine-koenig@pengutronix.de +Signed-off-by: Jonathan Cameron +Stable-dep-of: 0d42e2c0bd6c ("iio: adc: npcm: fix unbalanced clk_disable_unprepare()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/adc/npcm_adc.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/iio/adc/npcm_adc.c ++++ b/drivers/iio/adc/npcm_adc.c +@@ -320,7 +320,7 @@ err_disable_clk: + return ret; + } + +-static int npcm_adc_remove(struct platform_device *pdev) ++static void npcm_adc_remove(struct platform_device *pdev) + { + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct npcm_adc *info = iio_priv(indio_dev); +@@ -333,13 +333,11 @@ static int npcm_adc_remove(struct platfo + if (!IS_ERR(info->vref)) + regulator_disable(info->vref); + clk_disable_unprepare(info->adc_clk); +- +- return 0; + } + + static struct platform_driver npcm_adc_driver = { + .probe = npcm_adc_probe, +- .remove = npcm_adc_remove, ++ .remove_new = npcm_adc_remove, + .driver = { + .name = "npcm_adc", + .of_match_table = npcm_adc_match, diff --git a/queue-6.1/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch b/queue-6.1/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch new file mode 100644 index 0000000000..260c8e97e5 --- /dev/null +++ b/queue-6.1/iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch @@ -0,0 +1,112 @@ +From stable+bounces-260506-greg=kroah.com@vger.kernel.org Thu Jun 4 19:46:01 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:47 -0400 +Subject: iio: adc: npcm: fix unbalanced clk_disable_unprepare() +To: stable@vger.kernel.org +Cc: David Carlier , Andy Shevchenko , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604135447.3493139-3-sashal@kernel.org> + +From: David Carlier + +[ Upstream commit 0d42e2c0bd6ceb89e44c6e065f9bdf9b1df3ef0c ] + +The driver acquired the ADC clock with devm_clk_get() and read its +rate, but never called clk_prepare_enable(). The probe error path and +npcm_adc_remove() both called clk_disable_unprepare() unconditionally, +causing the clk framework's enable/prepare counts to underflow on +probe failure or module unbind. + +The issue went unnoticed because NPCM BMC firmware leaves the ADC +clock enabled at boot, so the driver happened to work in practice. + +Switch to devm_clk_get_enabled() so the clock is properly enabled +during probe and automatically released by the device-managed +cleanup, and drop the now-redundant clk_disable_unprepare() from +both the probe error path and remove(). + +While at it, drop the duplicate error message on devm_request_irq() +failure since the IRQ core already logs it. + +Fixes: 9bf85fbc9d8f ("iio: adc: add NPCM ADC driver") +Signed-off-by: David Carlier +Reviewed-by: Andy Shevchenko +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/adc/npcm_adc.c | 25 ++++++++----------------- + 1 file changed, 8 insertions(+), 17 deletions(-) + +--- a/drivers/iio/adc/npcm_adc.c ++++ b/drivers/iio/adc/npcm_adc.c +@@ -231,7 +231,7 @@ static int npcm_adc_probe(struct platfor + if (IS_ERR(info->reset)) + return PTR_ERR(info->reset); + +- info->adc_clk = devm_clk_get(&pdev->dev, NULL); ++ info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(info->adc_clk)) { + dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n"); + return PTR_ERR(info->adc_clk); +@@ -244,17 +244,13 @@ static int npcm_adc_probe(struct platfor + info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2); + + irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- ret = irq; +- goto err_disable_clk; +- } ++ if (irq < 0) ++ return irq; + + ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0, + "NPCM_ADC", indio_dev); +- if (ret < 0) { +- dev_err(dev, "failed requesting interrupt\n"); +- goto err_disable_clk; +- } ++ if (ret < 0) ++ return ret; + + reg_con = ioread32(info->regs + NPCM_ADCCON); + info->vref = devm_regulator_get_optional(&pdev->dev, "vref"); +@@ -262,7 +258,7 @@ static int npcm_adc_probe(struct platfor + ret = regulator_enable(info->vref); + if (ret) { + dev_err(&pdev->dev, "Can't enable ADC reference voltage\n"); +- goto err_disable_clk; ++ return ret; + } + + iowrite32(reg_con & ~NPCM_ADCCON_REFSEL, +@@ -272,10 +268,8 @@ static int npcm_adc_probe(struct platfor + * Any error which is not ENODEV indicates the regulator + * has been specified and so is a failure case. + */ +- if (PTR_ERR(info->vref) != -ENODEV) { +- ret = PTR_ERR(info->vref); +- goto err_disable_clk; +- } ++ if (PTR_ERR(info->vref) != -ENODEV) ++ return PTR_ERR(info->vref); + + /* Use internal reference */ + iowrite32(reg_con | NPCM_ADCCON_REFSEL, +@@ -314,8 +308,6 @@ err_iio_register: + iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON); + if (!IS_ERR(info->vref)) + regulator_disable(info->vref); +-err_disable_clk: +- clk_disable_unprepare(info->adc_clk); + + return ret; + } +@@ -332,7 +324,6 @@ static void npcm_adc_remove(struct platf + iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON); + if (!IS_ERR(info->vref)) + regulator_disable(info->vref); +- clk_disable_unprepare(info->adc_clk); + } + + static struct platform_driver npcm_adc_driver = { diff --git a/queue-6.1/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch b/queue-6.1/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch new file mode 100644 index 0000000000..0c03b8a7a5 --- /dev/null +++ b/queue-6.1/iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,38 @@ +From stable+bounces-260563-greg=kroah.com@vger.kernel.org Fri Jun 5 00:48:04 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 15:17:50 -0400 +Subject: iio: chemical: scd30: fix division by zero in write_raw +To: stable@vger.kernel.org +Cc: Antoniu Miclaus , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260604191751.743012-2-sashal@kernel.org> + +From: Antoniu Miclaus + +[ Upstream commit 5aba4f94b225617a55fed442a70329b2ee19c0a5 ] + +Add a zero check for val2 before using it as a divisor when setting the +sampling frequency. A user writing a zero fractional part to the +sampling_frequency sysfs attribute triggers a division by zero in the +kernel. + +Fixes: 64b3d8b1b0f5 ("iio: chemical: scd30: add core driver") +Signed-off-by: Antoniu Miclaus +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/chemical/scd30_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/iio/chemical/scd30_core.c ++++ b/drivers/iio/chemical/scd30_core.c +@@ -257,7 +257,7 @@ static int scd30_write_raw(struct iio_de + guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: +- if (val) ++ if (val || !val2) + return -EINVAL; + + val = 1000000000 / val2; diff --git a/queue-6.1/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch b/queue-6.1/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch new file mode 100644 index 0000000000..2f8e05ca7b --- /dev/null +++ b/queue-6.1/iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch @@ -0,0 +1,178 @@ +From stable+bounces-260562-greg=kroah.com@vger.kernel.org Fri Jun 5 00:48:03 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 15:17:49 -0400 +Subject: iio: chemical: scd30: Use guard(mutex) to allow early returns +To: stable@vger.kernel.org +Cc: Jonathan Cameron , David Lechner , Tomasz Duszynski , Sasha Levin +Message-ID: <20260604191751.743012-1-sashal@kernel.org> + +From: Jonathan Cameron + +[ Upstream commit 5feb5532870fbced5d6f450b8061a33f461b88ca ] + +Auto cleanup based release of the lock allows for simpler code flow in a +few functions with large multiplexing style switch statements and no +common operations following the switch. + +Suggested-by: David Lechner +Cc: Tomasz Duszynski +Reviewed-by: David Lechner +Link: https://patch.msgid.link/20250209180624.701140-3-jic23@kernel.org +Signed-off-by: Jonathan Cameron +Stable-dep-of: 5aba4f94b225 ("iio: chemical: scd30: fix division by zero in write_raw") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/chemical/scd30_core.c | 63 ++++++++++++++++---------------------- + 1 file changed, 28 insertions(+), 35 deletions(-) + +--- a/drivers/iio/chemical/scd30_core.c ++++ b/drivers/iio/chemical/scd30_core.c +@@ -5,6 +5,7 @@ + * Copyright (c) 2020 Tomasz Duszynski + */ + #include ++#include + #include + #include + #include +@@ -198,112 +199,104 @@ static int scd30_read_raw(struct iio_dev + int *val, int *val2, long mask) + { + struct scd30_state *state = iio_priv(indio_dev); +- int ret = -EINVAL; ++ int ret; + u16 tmp; + +- mutex_lock(&state->lock); ++ guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + if (chan->output) { + *val = state->pressure_comp; +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; + } + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) +- break; ++ return ret; + + ret = scd30_read(state); + if (ret) { + iio_device_release_direct_mode(indio_dev); +- break; ++ return ret; + } + + *val = state->meas[chan->address]; + iio_device_release_direct_mode(indio_dev); +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 1; +- ret = IIO_VAL_INT_PLUS_MICRO; +- break; ++ return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = scd30_command_read(state, CMD_MEAS_INTERVAL, &tmp); + if (ret) +- break; ++ return ret; + + *val = 0; + *val2 = 1000000000 / tmp; +- ret = IIO_VAL_INT_PLUS_NANO; +- break; ++ return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_CALIBBIAS: + ret = scd30_command_read(state, CMD_TEMP_OFFSET, &tmp); + if (ret) +- break; ++ return ret; + + *val = tmp; +- ret = IIO_VAL_INT; +- break; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; + } +- mutex_unlock(&state->lock); +- +- return ret; + } + + static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int val, int val2, long mask) + { + struct scd30_state *state = iio_priv(indio_dev); +- int ret = -EINVAL; ++ int ret; + +- mutex_lock(&state->lock); ++ guard(mutex)(&state->lock); + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val) +- break; ++ return -EINVAL; + + val = 1000000000 / val2; + if (val < SCD30_MEAS_INTERVAL_MIN_S || val > SCD30_MEAS_INTERVAL_MAX_S) +- break; ++ return -EINVAL; + + ret = scd30_command_write(state, CMD_MEAS_INTERVAL, val); + if (ret) +- break; ++ return ret; + + state->meas_interval = val; +- break; ++ return 0; + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_PRESSURE: + if (val < SCD30_PRESSURE_COMP_MIN_MBAR || + val > SCD30_PRESSURE_COMP_MAX_MBAR) +- break; ++ return -EINVAL; + + ret = scd30_command_write(state, CMD_START_MEAS, val); + if (ret) +- break; ++ return ret; + + state->pressure_comp = val; +- break; ++ return 0; + default: +- break; ++ return -EINVAL; + } +- break; + case IIO_CHAN_INFO_CALIBBIAS: + if (val < 0 || val > SCD30_TEMP_OFFSET_MAX) +- break; ++ return -EINVAL; + /* + * Manufacturer does not explicitly specify min/max sensible + * values hence check is omitted for simplicity. + */ +- ret = scd30_command_write(state, CMD_TEMP_OFFSET / 10, val); ++ return scd30_command_write(state, CMD_TEMP_OFFSET / 10, val); ++ default: ++ return -EINVAL; + } +- mutex_unlock(&state->lock); +- +- return ret; + } + + static int scd30_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, diff --git a/queue-6.1/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch b/queue-6.1/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch new file mode 100644 index 0000000000..fc17007487 --- /dev/null +++ b/queue-6.1/iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch @@ -0,0 +1,65 @@ +From stable+bounces-260596-greg=kroah.com@vger.kernel.org Fri Jun 5 06:30:09 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 20:59:16 -0400 +Subject: iio: dac: ad5686: fix ref bit initialization for single-channel parts +To: stable@vger.kernel.org +Cc: Rodrigo Alencar , Andy Shevchenko , Stable@vger.kernel.org, Jonathan Cameron , Sasha Levin +Message-ID: <20260605005916.2803184-1-sashal@kernel.org> + +From: Rodrigo Alencar + +[ Upstream commit ecae2ae606d493cf11457946436335bd0e726663 ] + +The reference bit position was ignored when writing the register at the +probe() function (!!val was used). When such bit is 1, internal voltage +reference is disabled so that an external one can be used. For +multi-channel devices, bit 0 of the Internal Reference Setup command +behaves the same way, so AD5686_REF_BIT_MSK is created. The issue exists +since support for single-channel devices were first introduced. + +Fixes: be1b24d24541 ("iio:dac:ad5686: Add AD5691R/AD5692R/AD5693/AD5693R support") +Reviewed-by: Andy Shevchenko +Signed-off-by: Rodrigo Alencar +Cc: +Signed-off-by: Jonathan Cameron +[ adapted `has_external_vref` to the in-tree equivalent `voltage_uv` variable in the `val =` computation ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/dac/ad5686.c | 6 +++--- + drivers/iio/dac/ad5686.h | 1 + + 2 files changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/iio/dac/ad5686.c ++++ b/drivers/iio/dac/ad5686.c +@@ -521,7 +521,7 @@ int ad5686_probe(struct device *dev, + break; + case AD5686_REGMAP: + cmd = AD5686_CMD_INTERNAL_REFER_SETUP; +- ref_bit_msk = 0; ++ ref_bit_msk = AD5686_REF_BIT_MSK; + break; + case AD5693_REGMAP: + cmd = AD5686_CMD_CONTROL_REG; +@@ -533,9 +533,9 @@ int ad5686_probe(struct device *dev, + goto error_disable_reg; + } + +- val = (voltage_uv | ref_bit_msk); ++ val = voltage_uv ? ref_bit_msk : 0; + +- ret = st->write(st, cmd, 0, !!val); ++ ret = st->write(st, cmd, 0, val); + if (ret) + goto error_disable_reg; + +--- a/drivers/iio/dac/ad5686.h ++++ b/drivers/iio/dac/ad5686.h +@@ -46,6 +46,7 @@ + + #define AD5310_REF_BIT_MSK BIT(8) + #define AD5683_REF_BIT_MSK BIT(12) ++#define AD5686_REF_BIT_MSK BIT(0) + #define AD5693_REF_BIT_MSK BIT(12) + + /** diff --git a/queue-6.1/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch b/queue-6.1/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch new file mode 100644 index 0000000000..b56280a2e3 --- /dev/null +++ b/queue-6.1/iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch @@ -0,0 +1,39 @@ +From stable+bounces-260561-greg=kroah.com@vger.kernel.org Fri Jun 5 00:33:51 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:57:19 -0400 +Subject: iio: gyro: adis16260: fix division by zero in write_raw +To: stable@vger.kernel.org +Cc: "Antoniu Miclaus" , "Nuno Sá" , Stable@vger.kernel.org, "Jonathan Cameron" , "Sasha Levin" +Message-ID: <20260604185720.605937-1-sashal@kernel.org> + +From: Antoniu Miclaus + +[ Upstream commit 761e8b489e6cf166c574034b70637f8a7eadd0ee ] + +Add a validation check for the sampling frequency value before using it +as a divisor. A user writing zero to the sampling_frequency sysfs +attribute triggers a division by zero in the kernel. + +Fixes: 089a41985c6c ("staging: iio: adis16260 digital gyro driver") +Signed-off-by: Antoniu Miclaus +Reviewed-by: Nuno Sá +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/gyro/adis16260.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/iio/gyro/adis16260.c ++++ b/drivers/iio/gyro/adis16260.c +@@ -288,6 +288,9 @@ static int adis16260_write_raw(struct ii + addr = adis16260_addresses[chan->scan_index][1]; + return adis_write_reg_16(adis, addr, val); + case IIO_CHAN_INFO_SAMP_FREQ: ++ if (val <= 0) ++ return -EINVAL; ++ + adis_dev_lock(adis); + if (spi_get_device_id(adis->spi)->driver_data) + t = 256 / val; diff --git a/queue-6.1/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch b/queue-6.1/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch new file mode 100644 index 0000000000..2f5e2a0192 --- /dev/null +++ b/queue-6.1/ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch @@ -0,0 +1,76 @@ +From stable+bounces-256844-greg=kroah.com@vger.kernel.org Sat May 30 06:27:06 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 20:50:58 -0400 +Subject: ipv6: ioam: add NULL check for idev in ipv6_hop_ioam() +To: stable@vger.kernel.org +Cc: Justin Iurman , Ido Schimmel , Jakub Kicinski , Sasha Levin +Message-ID: <20260530005058.2390235-1-sashal@kernel.org> + +From: Justin Iurman + +[ Upstream commit d4ea0dfd75011b78cebf3808f98ac4c4f51a6fb9 ] + +Reported by Sashiko: + +The function ipv6_hop_ioam() accesses +__in6_dev_get(skb->dev)->cnf.ioam6_enabled without validating the returned +idev pointer. Because addrconf_ifdown() can concurrently clear dev->ip6_ptr +via RCU, __in6_dev_get() can return NULL during interface teardown, which +could cause a NULL pointer dereference when processing an IOAM Hop-by-Hop +option. + +Let's add a check and use SKB_DROP_REASON_IPV6DISABLED accordingly. + +Fixes: 9ee11f0fff20 ("ipv6: ioam: Data plane support for Pre-allocated Trace") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260517183059.29140-1-justin.iurman@gmail.com +Signed-off-by: Jakub Kicinski +[ dropped READ_ONCE() wrapper from idev->cnf.ioam6_enabled ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/exthdrs.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -952,16 +952,27 @@ static bool ipv6_hop_ra(struct sk_buff * + + static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff) + { ++ enum skb_drop_reason drop_reason; + struct ioam6_trace_hdr *trace; + struct ioam6_namespace *ns; ++ struct inet6_dev *idev; + struct ioam6_hdr *hdr; + ++ drop_reason = SKB_DROP_REASON_IP_INHDR; ++ + /* Bad alignment (must be 4n-aligned) */ + if (optoff & 3) + goto drop; + ++ /* Does the device still have IPv6 configuration? */ ++ idev = __in6_dev_get(skb->dev); ++ if (!idev) { ++ drop_reason = SKB_DROP_REASON_IPV6DISABLED; ++ goto drop; ++ } ++ + /* Ignore if IOAM is not enabled on ingress */ +- if (!__in6_dev_get(skb->dev)->cnf.ioam6_enabled) ++ if (!idev->cnf.ioam6_enabled) + goto ignore; + + /* Truncated Option header */ +@@ -1011,7 +1022,7 @@ ignore: + return true; + + drop: +- kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); ++ kfree_skb_reason(skb, drop_reason); + return false; + } + diff --git a/queue-6.1/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch b/queue-6.1/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch new file mode 100644 index 0000000000..e65edf19b8 --- /dev/null +++ b/queue-6.1/mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch @@ -0,0 +1,114 @@ +From stable+bounces-263445-greg=kroah.com@vger.kernel.org Tue Jun 16 01:12:49 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 15:42:35 -0400 +Subject: mm/hugetlb: rename folio_putback_active_hugetlb() to folio_putback_hugetlb() +To: stable@vger.kernel.org +Cc: David Hildenbrand , Baolin Wang , "Matthew Wilcox (Oracle)" , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615194237.2391157-3-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit b235448e8cab7eea17d164efc7bf55505985ba65 ] + +Now that folio_putback_hugetlb() is only called on folios that were +previously isolated through folio_isolate_hugetlb(), let's rename it to +match folio_putback_lru(). + +Add some kernel doc to clarify how this function is supposed to be used. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-5-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Baolin Wang +Cc: Matthew Wilcox (Oracle) +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 4 ++-- + mm/hugetlb.c | 15 +++++++++++++-- + mm/migrate.c | 6 +++--- + 3 files changed, 18 insertions(+), 7 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -185,7 +185,7 @@ long hugetlb_unreserve_pages(struct inod + int folio_isolate_hugetlb(struct page *page, struct list_head *list); + int get_hwpoison_huge_page(struct page *page, bool *hugetlb); + int get_huge_page_for_hwpoison(unsigned long pfn, int flags); +-void putback_active_hugepage(struct page *page); ++void folio_putback_hugetlb(struct page *page); + void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason); + void free_huge_page(struct page *page); + void hugetlb_fix_reserve_counts(struct inode *inode); +@@ -443,7 +443,7 @@ static inline int get_huge_page_for_hwpo + return 0; + } + +-static inline void putback_active_hugepage(struct page *page) ++static inline void folio_putback_hugetlb(struct page *page) + { + } + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7458,7 +7458,7 @@ follow_huge_pgd(struct mm_struct *mm, un + * it is already isolated/non-migratable. + * + * On success, an additional page reference is taken that must be dropped +- * using putback_active_hugepage() to undo the isolation. ++ * using folio_putback_hugetlb() to undo the isolation. + * + * Return: 0 if isolation worked, otherwise -EBUSY. + */ +@@ -7509,7 +7509,18 @@ int get_huge_page_for_hwpoison(unsigned + return ret; + } + +-void putback_active_hugepage(struct page *page) ++/** ++ * folio_putback_hugetlb - unisolate a hugetlb page ++ * @page: the isolated hugetlb page ++ * ++ * Putback/un-isolate the hugetlb page that was previous isolated using ++ * folio_isolate_hugetlb(): marking it non-isolated/migratable and putting it ++ * back onto the active list. ++ * ++ * Will drop the additional page reference obtained through ++ * folio_isolate_hugetlb(). ++ */ ++void folio_putback_hugetlb(struct page *page) + { + spin_lock_irq(&hugetlb_lock); + SetHPageMigratable(page); +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -142,7 +142,7 @@ void putback_movable_pages(struct list_h + + list_for_each_entry_safe(page, page2, l, lru) { + if (unlikely(PageHuge(page))) { +- putback_active_hugepage(page); ++ folio_putback_hugetlb(page); + continue; + } + list_del(&page->lru); +@@ -1371,7 +1371,7 @@ static int unmap_and_move_huge_page(new_ + + if (folio_ref_count(src) == 1) { + /* page was freed from under us. So we are done. */ +- putback_active_hugepage(hpage); ++ folio_putback_hugetlb(hpage); + return MIGRATEPAGE_SUCCESS; + } + +@@ -1455,7 +1455,7 @@ out_unlock: + folio_unlock(src); + out: + if (rc == MIGRATEPAGE_SUCCESS) +- putback_active_hugepage(hpage); ++ folio_putback_hugetlb(hpage); + else if (rc != -EAGAIN) + list_move_tail(&src->lru, ret); + diff --git a/queue-6.1/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch b/queue-6.1/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch new file mode 100644 index 0000000000..104e83d281 --- /dev/null +++ b/queue-6.1/mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch @@ -0,0 +1,165 @@ +From stable+bounces-263443-greg=kroah.com@vger.kernel.org Tue Jun 16 01:12:46 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 15:42:33 -0400 +Subject: mm/hugetlb: rename isolate_hugetlb() to folio_isolate_hugetlb() +To: stable@vger.kernel.org +Cc: David Hildenbrand , "Matthew Wilcox (Oracle)" , Baolin Wang , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615194237.2391157-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 4c640f128074e0d4459ecf072595a44df5c2ae18 ] + +Let's make the function name match "folio_isolate_lru()", and add some +kernel doc. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-3-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Matthew Wilcox (Oracle) +Reviewed-by: Baolin Wang +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 4 ++-- + mm/gup.c | 2 +- + mm/hugetlb.c | 23 ++++++++++++++++++++--- + mm/memory-failure.c | 2 +- + mm/memory_hotplug.c | 2 +- + mm/mempolicy.c | 2 +- + mm/migrate.c | 4 ++-- + 7 files changed, 28 insertions(+), 11 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -182,7 +182,7 @@ bool hugetlb_reserve_pages(struct inode + vm_flags_t vm_flags); + long hugetlb_unreserve_pages(struct inode *inode, long start, long end, + long freed); +-int isolate_hugetlb(struct page *page, struct list_head *list); ++int folio_isolate_hugetlb(struct page *page, struct list_head *list); + int get_hwpoison_huge_page(struct page *page, bool *hugetlb); + int get_huge_page_for_hwpoison(unsigned long pfn, int flags); + void putback_active_hugepage(struct page *page); +@@ -428,7 +428,7 @@ static inline pte_t *huge_pte_offset(str + return NULL; + } + +-static inline int isolate_hugetlb(struct page *page, struct list_head *list) ++static inline int folio_isolate_hugetlb(struct page *page, struct list_head *list) + { + return -EBUSY; + } +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -1986,7 +1986,7 @@ static unsigned long collect_longterm_un + continue; + + if (folio_test_hugetlb(folio)) { +- isolate_hugetlb(&folio->page, movable_page_list); ++ folio_isolate_hugetlb(&folio->page, movable_page_list); + continue; + } + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2994,7 +2994,7 @@ retry: + * Fail with -EBUSY if not possible. + */ + spin_unlock_irq(&hugetlb_lock); +- ret = isolate_hugetlb(old_page, list); ++ ret = folio_isolate_hugetlb(old_page, list); + spin_lock_irq(&hugetlb_lock); + goto free_new; + } else if (!HPageFreed(old_page)) { +@@ -3070,7 +3070,7 @@ int isolate_or_dissolve_huge_page(struct + if (hstate_is_gigantic(h)) + return -ENOMEM; + +- if (page_count(head) && !isolate_hugetlb(head, list)) ++ if (page_count(head) && !folio_isolate_hugetlb(head, list)) + ret = 0; + else if (!page_count(head)) + ret = alloc_and_dissolve_huge_page(h, head, list); +@@ -7445,7 +7445,24 @@ follow_huge_pgd(struct mm_struct *mm, un + return pte_page(*(pte_t *)pgd) + ((address & ~PGDIR_MASK) >> PAGE_SHIFT); + } + +-int isolate_hugetlb(struct page *page, struct list_head *list) ++/** ++ * folio_isolate_hugetlb - try to isolate an allocated hugetlb page ++ * @page: the page to isolate ++ * @list: the list to add the page to on success ++ * ++ * Isolate an allocated (refcount > 0) hugetlb page, marking it as ++ * isolated/non-migratable, and moving it from the active list to the ++ * given list. ++ * ++ * Isolation will fail if @page is not an allocated hugetlb page, or if ++ * it is already isolated/non-migratable. ++ * ++ * On success, an additional page reference is taken that must be dropped ++ * using putback_active_hugepage() to undo the isolation. ++ * ++ * Return: 0 if isolation worked, otherwise -EBUSY. ++ */ ++int folio_isolate_hugetlb(struct page *page, struct list_head *list) + { + int ret = 0; + +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -2444,7 +2444,7 @@ static bool isolate_page(struct page *pa + bool isolated = false; + + if (PageHuge(page)) { +- isolated = !isolate_hugetlb(page, pagelist); ++ isolated = !folio_isolate_hugetlb(page, pagelist); + } else { + bool lru = !__PageMovable(page); + +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1641,7 +1641,7 @@ do_migrate_range(unsigned long start_pfn + + if (PageHuge(page)) { + pfn = page_to_pfn(head) + compound_nr(head) - 1; +- isolate_hugetlb(head, &source); ++ folio_isolate_hugetlb(head, &source); + continue; + } else if (PageTransHuge(page)) + pfn = page_to_pfn(head) + thp_nr_pages(page) - 1; +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -598,7 +598,7 @@ static int queue_pages_hugetlb(pte_t *pt + if (flags & (MPOL_MF_MOVE_ALL) || + (flags & MPOL_MF_MOVE && page_mapcount(page) == 1 && + !hugetlb_pmd_shared(pte))) { +- if (isolate_hugetlb(page, qp->pagelist) && ++ if (folio_isolate_hugetlb(page, qp->pagelist) && + (flags & MPOL_MF_STRICT)) + /* + * Failed to isolate page but allow migrating pages +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -133,7 +133,7 @@ static void putback_movable_page(struct + * + * This function shall be used whenever the isolated pageset has been + * built from lru, balloon, hugetlbfs page. See isolate_migratepages_range() +- * and isolate_hugetlb(). ++ * and folio_isolate_hugetlb(). + */ + void putback_movable_pages(struct list_head *l) + { +@@ -1995,7 +1995,7 @@ static int add_page_for_migration(struct + + if (PageHuge(page)) { + if (PageHead(page)) { +- err = isolate_hugetlb(page, pagelist); ++ err = folio_isolate_hugetlb(page, pagelist); + if (!err) + err = 1; + } diff --git a/queue-6.1/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch b/queue-6.1/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch new file mode 100644 index 0000000000..d56b086a29 --- /dev/null +++ b/queue-6.1/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch @@ -0,0 +1,79 @@ +From stable+bounces-247231-greg=kroah.com@vger.kernel.org Thu May 14 20:41:40 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 11:08:40 -0400 +Subject: mm/hugetlb_cma: round up per_node before logging it +To: stable@vger.kernel.org +Cc: Sang-Heon Jeon , Muchun Song , David Hildenbrand , Oscar Salvador , Andrew Morton , Sasha Levin +Message-ID: <20260514150840.275599-1-sashal@kernel.org> + +From: Sang-Heon Jeon + +[ Upstream commit 8f5ce56b76303c55b78a87af996e2e0f8535f979 ] + +When the user requests a total hugetlb CMA size without per-node +specification, hugetlb_cma_reserve() computes per_node from +hugetlb_cma_size and the number of nodes that have memory + + per_node = DIV_ROUND_UP(hugetlb_cma_size, + nodes_weight(hugetlb_bootmem_nodes)); + +The reservation loop later computes + + size = round_up(min(per_node, hugetlb_cma_size - reserved), + PAGE_SIZE << order); + +So the actually reserved per_node size is multiple of (PAGE_SIZE << +order), but the logged per_node is not rounded up, so it may be smaller +than the actual reserved size. + +For example, as the existing comment describes, if a 3 GB area is +requested on a machine with 4 NUMA nodes that have memory, 1 GB is +allocated on the first three nodes, but the printed log is + + hugetlb_cma: reserve 3072 MiB, up to 768 MiB per node + +Round per_node up to (PAGE_SIZE << order) before logging so that the +printed log always matches the actual reserved size. No functional change +to the actual reservation size, as the following case analysis shows + +1. remaining (hugetlb_cma_size - reserved) >= rounded per_node + - AS-IS: min() picks unrounded per_node; + round_up() returns rounded per_node + - TO-BE: min() picks rounded per_node; + round_up() returns rounded per_node (no-op) +2. remaining < unrounded per_node + - AS-IS: min() picks remaining; + round_up() returns round_up(remaining) + - TO-BE: min() picks remaining; + round_up() returns round_up(remaining) +3. unrounded per_node <= remaining < rounded per_node + - AS-IS: min() picks unrounded per_node; + round_up() returns rounded per_node + - TO-BE: min() picks remaining; + round_up() returns round_up(remaining) equals rounded per_node + +Link: https://lore.kernel.org/20260422143353.852257-1-ekffu200098@gmail.com +Fixes: cf11e85fc08c ("mm: hugetlb: optionally allocate gigantic hugepages using cma") # 5.7 +Signed-off-by: Sang-Heon Jeon +Reviewed-by: Muchun Song +Cc: David Hildenbrand +Cc: Oscar Salvador +Cc: +Signed-off-by: Andrew Morton +[ applied the single-line addition to mm/hugetlb.c since mm/hugetlb_cma.c didn't exist yet in 6.12 ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7705,6 +7705,7 @@ void __init hugetlb_cma_reserve(int orde + * let's allocate 1 GB on first three nodes and ignore the last one. + */ + per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes); ++ per_node = round_up(per_node, PAGE_SIZE << order); + pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", + hugetlb_cma_size / SZ_1M, per_node / SZ_1M); + } diff --git a/queue-6.1/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch b/queue-6.1/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch new file mode 100644 index 0000000000..fec3082490 --- /dev/null +++ b/queue-6.1/mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch @@ -0,0 +1,184 @@ +From stable+bounces-263447-greg=kroah.com@vger.kernel.org Tue Jun 16 01:12:54 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 15:42:37 -0400 +Subject: mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison +To: stable@vger.kernel.org +Cc: Wupeng Ma , "Oscar Salvador (SUSE)" , Muchun Song , Kefeng Wang , Miaohe Lin , David Hildenbrand , Liam Howlett , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Naoya Horiguchi , Suren Baghdasaryan , Vlastimil Babka , Andrew Morton , Sasha Levin +Message-ID: <20260615194237.2391157-5-sashal@kernel.org> + +From: Wupeng Ma + +[ Upstream commit 3c2d42b8ee345b17a4ba56b0f6492d1ff4c1178e ] + +Two concurrent madvise(MADV_HWPOISON) calls on the same hugetlb page can +trigger a recursive spinlock self-deadlock (AA deadlock) on hugetlb_lock +when racing with a concurrent unmap: + + thread#0 thread#1 + -------- -------- + madvise(folio, MADV_HWPOISON) + -> poisons the folio successfully + madvise(folio, MADV_HWPOISON) unmap(folio) + try_memory_failure_hugetlb + get_huge_page_for_hwpoison + spin_lock_irq(&hugetlb_lock) <- held + __get_huge_page_for_hwpoison + hugetlb_update_hwpoison() + -> MF_HUGETLB_FOLIO_PRE_POISONED + goto out: + folio_put() + refcount: 1 -> 0 + free_huge_folio() + spin_lock_irqsave(&hugetlb_lock) + -> AA DEADLOCK! + +The out: path in __get_huge_page_for_hwpoison() calls folio_put() to drop +the GUP reference while the hugetlb_lock is still held by the hugetlb.c +wrapper get_huge_page_for_hwpoison(). If concurrent unmap has released +the page table mapping reference, folio_put() drops the folio refcount to +zero, triggering free_huge_folio() which attempts to re-acquire the +non-recursive hugetlb_lock. + +Fix this by moving hugetlb_lock acquisition from the hugetlb.c wrapper +into get_huge_page_for_hwpoison(). Place spin_unlock_irq() before the +folio_put() at the out: label so the folio is always released outside the +lock. + +[akpm@linux-foundation.org: fix race, rename label per Miaohe] + Link: https://sashiko.dev/#/patchset/20260522010305.4099834-1-mawupeng1@huawei.com + Link: https://lore.kernel.org/f39f405e-4b4b-8f79-70fe-a2b5b62114eb@huawei.com +Link: https://lore.kernel.org/20260522010305.4099834-1-mawupeng1@huawei.com +Fixes: 405ce051236c ("mm/hwpoison: fix race between hugetlb free/demotion and memory_failure_hugetlb()") +Signed-off-by: Wupeng Ma +Acked-by: Oscar Salvador (SUSE) +Acked-by: Muchun Song +Reviewed-by: Kefeng Wang +Acked-by: Miaohe Lin +Cc: David Hildenbrand +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Naoya Horiguchi +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hugetlb.h | 6 ------ + include/linux/mm.h | 5 ----- + mm/hugetlb.c | 10 ---------- + mm/memory-failure.c | 19 ++++++++++--------- + 4 files changed, 10 insertions(+), 30 deletions(-) + +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -184,7 +184,6 @@ long hugetlb_unreserve_pages(struct inod + long freed); + int folio_isolate_hugetlb(struct page *page, struct list_head *list); + int get_hwpoison_huge_page(struct page *page, bool *hugetlb); +-int get_huge_page_for_hwpoison(unsigned long pfn, int flags); + void folio_putback_hugetlb(struct page *page); + void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason); + void free_huge_page(struct page *page); +@@ -437,11 +436,6 @@ static inline int get_hwpoison_huge_page + { + return 0; + } +- +-static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags) +-{ +- return 0; +-} + + static inline void folio_putback_hugetlb(struct page *page) + { +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -3429,15 +3429,10 @@ extern atomic_long_t num_poisoned_pages + extern int soft_offline_page(unsigned long pfn, int flags); + #ifdef CONFIG_MEMORY_FAILURE + extern void memory_failure_queue(unsigned long pfn, int flags); +-extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags); + #else + static inline void memory_failure_queue(unsigned long pfn, int flags) + { + } +-static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags) +-{ +- return 0; +-} + #endif + + #ifndef arch_memory_failure +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7499,16 +7499,6 @@ int get_hwpoison_huge_page(struct page * + return ret; + } + +-int get_huge_page_for_hwpoison(unsigned long pfn, int flags) +-{ +- int ret; +- +- spin_lock_irq(&hugetlb_lock); +- ret = __get_huge_page_for_hwpoison(pfn, flags); +- spin_unlock_irq(&hugetlb_lock); +- return ret; +-} +- + /** + * folio_putback_hugetlb - unisolate a hugetlb page + * @page: the isolated hugetlb page +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1812,19 +1812,18 @@ void hugetlb_clear_page_hwpoison(struct + free_raw_hwp_pages(hpage, true); + } + +-/* +- * Called from hugetlb code with hugetlb_lock held. +- */ +-int __get_huge_page_for_hwpoison(unsigned long pfn, int flags) ++static int get_huge_page_for_hwpoison(unsigned long pfn, int flags) + { + struct page *page = pfn_to_page(pfn); +- struct page *head = compound_head(page); ++ struct page *head; + bool count_increased = false; + int ret, rc; + ++ spin_lock_irq(&hugetlb_lock); ++ head = compound_head(page); + if (!PageHeadHuge(head)) { + ret = MF_HUGETLB_NON_HUGEPAGE; +- goto out; ++ goto out_unlock; + } else if (flags & MF_COUNT_INCREASED) { + ret = MF_HUGETLB_IN_USED; + count_increased = true; +@@ -1840,17 +1839,19 @@ int __get_huge_page_for_hwpoison(unsigne + } else { + ret = MF_HUGETLB_RETRY; + if (!(flags & MF_NO_RETRY)) +- goto out; ++ goto out_unlock; + } + + rc = hugetlb_update_hwpoison(head, page); + if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { + ret = rc; +- goto out; ++ goto out_unlock; + } + ++ spin_unlock_irq(&hugetlb_lock); + return ret; +-out: ++out_unlock: ++ spin_unlock_irq(&hugetlb_lock); + if (count_increased) + put_page(head); + return ret; diff --git a/queue-6.1/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch b/queue-6.1/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch new file mode 100644 index 0000000000..e9c3edcb6c --- /dev/null +++ b/queue-6.1/mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch @@ -0,0 +1,211 @@ +From stable+bounces-263446-greg=kroah.com@vger.kernel.org Tue Jun 16 01:12:48 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 15:42:36 -0400 +Subject: mm/memory-failure: fix missing ->mf_stats count in hugetlb poison +To: stable@vger.kernel.org +Cc: Jane Chu , Miaohe Lin , Chris Mason , David Hildenbrand , David Rientjes , Jiaqi Yan , "Liam R. Howlett" , Lorenzo Stoakes , "Matthew Wilcox (Oracle)" , Michal Hocko , Mike Rapoport , Muchun Song , Naoya Horiguchi , Oscar Salvador , Suren Baghdasaryan , William Roche , Andrew Morton , Sasha Levin +Message-ID: <20260615194237.2391157-4-sashal@kernel.org> + +From: Jane Chu + +[ Upstream commit a148a2040191b12b45b82cb29c281cb3036baf90 ] + +When a newly poisoned subpage ends up in an already poisoned hugetlb +folio, 'num_poisoned_pages' is incremented, but the per node ->mf_stats is +not. Fix the inconsistency by designating action_result() to update them +both. + +While at it, define __get_huge_page_for_hwpoison() return values in terms +of symbol names for better readibility. Also rename +folio_set_hugetlb_hwpoison() to hugetlb_update_hwpoison() since the +function does more than the conventional bit setting and the fact three +possible return values are expected. + +Link: https://lkml.kernel.org/r/20260120232234.3462258-1-jane.chu@oracle.com +Fixes: 18f41fa616ee ("mm: memory-failure: bump memory failure stats to pglist_data") +Signed-off-by: Jane Chu +Acked-by: Miaohe Lin +Cc: Chris Mason +Cc: David Hildenbrand +Cc: David Rientjes +Cc: Jiaqi Yan +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Matthew Wilcox (Oracle) +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Naoya Horiguchi +Cc: Oscar Salvador +Cc: Suren Baghdasaryan +Cc: William Roche +Cc: +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory-failure.c | 71 +++++++++++++++++++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 28 deletions(-) + +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1730,12 +1730,22 @@ static unsigned long __free_raw_hwp_page + return count; + } + +-static int hugetlb_set_page_hwpoison(struct page *hpage, struct page *page) ++#define MF_HUGETLB_FREED 0 /* freed hugepage */ ++#define MF_HUGETLB_IN_USED 1 /* in-use hugepage */ ++#define MF_HUGETLB_NON_HUGEPAGE 2 /* not a hugepage */ ++#define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */ ++#define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */ ++#define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */ ++/* ++ * Set hugetlb page as hwpoisoned, update page private raw hwpoison list ++ * to keep track of the poisoned pages. ++ */ ++static int hugetlb_update_hwpoison(struct page *hpage, struct page *page) + { + struct llist_head *head; + struct raw_hwp_page *raw_hwp; + struct llist_node *t, *tnode; +- int ret = TestSetPageHWPoison(hpage) ? -EHWPOISON : 0; ++ int ret = TestSetPageHWPoison(hpage) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0; + + /* + * Once the hwpoison hugepage has lost reliable raw error info, +@@ -1743,13 +1753,13 @@ static int hugetlb_set_page_hwpoison(str + * so skip to add additional raw error info. + */ + if (HPageRawHwpUnreliable(hpage)) +- return -EHWPOISON; ++ return MF_HUGETLB_FOLIO_PRE_POISONED; + head = raw_hwp_list_head(hpage); + llist_for_each_safe(tnode, t, head->first) { + struct raw_hwp_page *p = container_of(tnode, struct raw_hwp_page, node); + + if (p->page == page) +- return -EHWPOISON; ++ return MF_HUGETLB_PAGE_PRE_POISONED; + } + + raw_hwp = kmalloc(sizeof(struct raw_hwp_page), GFP_ATOMIC); +@@ -1804,41 +1814,38 @@ void hugetlb_clear_page_hwpoison(struct + + /* + * Called from hugetlb code with hugetlb_lock held. +- * +- * Return values: +- * 0 - free hugepage +- * 1 - in-use hugepage +- * 2 - not a hugepage +- * -EBUSY - the hugepage is busy (try to retry) +- * -EHWPOISON - the hugepage is already hwpoisoned + */ + int __get_huge_page_for_hwpoison(unsigned long pfn, int flags) + { + struct page *page = pfn_to_page(pfn); + struct page *head = compound_head(page); +- int ret = 2; /* fallback to normal page handling */ + bool count_increased = false; ++ int ret, rc; + +- if (!PageHeadHuge(head)) ++ if (!PageHeadHuge(head)) { ++ ret = MF_HUGETLB_NON_HUGEPAGE; + goto out; +- +- if (flags & MF_COUNT_INCREASED) { +- ret = 1; ++ } else if (flags & MF_COUNT_INCREASED) { ++ ret = MF_HUGETLB_IN_USED; + count_increased = true; + } else if (HPageFreed(head)) { +- ret = 0; ++ ret = MF_HUGETLB_FREED; + } else if (HPageMigratable(head)) { +- ret = get_page_unless_zero(head); +- if (ret) ++ if (get_page_unless_zero(head)) { ++ ret = MF_HUGETLB_IN_USED; + count_increased = true; ++ } else { ++ ret = MF_HUGETLB_FREED; ++ } + } else { +- ret = -EBUSY; ++ ret = MF_HUGETLB_RETRY; + if (!(flags & MF_NO_RETRY)) + goto out; + } + +- if (hugetlb_set_page_hwpoison(head, page)) { +- ret = -EHWPOISON; ++ rc = hugetlb_update_hwpoison(head, page); ++ if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { ++ ret = rc; + goto out; + } + +@@ -1854,6 +1861,12 @@ out: + * with basic operations like hugepage allocation/free/demotion. + * So some of prechecks for hwpoison (pinning, and testing/setting + * PageHWPoison) should be done in single hugetlb_lock range. ++ * Returns: ++ * 0 - not hugetlb, or recovered ++ * -EBUSY - not recovered ++ * -EOPNOTSUPP - hwpoison_filter'ed ++ * -EHWPOISON - folio or exact page already poisoned ++ * -EFAULT - kill_accessing_process finds current->mm null + */ + static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb) + { +@@ -1865,23 +1878,25 @@ static int try_memory_failure_hugetlb(un + *hugetlb = 1; + retry: + res = get_huge_page_for_hwpoison(pfn, flags); +- if (res == 2) { /* fallback to normal page handling */ ++ if (res == MF_HUGETLB_NON_HUGEPAGE) { /* fallback to normal page handling */ + *hugetlb = 0; + return 0; +- } else if (res == -EHWPOISON) { ++ } else if (res == MF_HUGETLB_FOLIO_PRE_POISONED || ++ res == MF_HUGETLB_PAGE_PRE_POISONED) { + pr_err("%#lx: already hardware poisoned\n", pfn); ++ res = -EHWPOISON; + if (flags & MF_ACTION_REQUIRED) { + head = compound_head(p); + res = kill_accessing_process(current, page_to_pfn(head), flags); + } + return res; +- } else if (res == -EBUSY) { ++ } else if (res == MF_HUGETLB_RETRY) { + if (!(flags & MF_NO_RETRY)) { + flags |= MF_NO_RETRY; + goto retry; + } + action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED); +- return res; ++ return -EBUSY; + } + + head = compound_head(p); +@@ -1890,7 +1905,7 @@ retry: + if (hwpoison_filter(p)) { + hugetlb_clear_page_hwpoison(head); + unlock_page(head); +- if (res == 1) ++ if (res == MF_HUGETLB_IN_USED) + put_page(head); + return -EOPNOTSUPP; + } +@@ -1899,7 +1914,7 @@ retry: + * Handling free hugepage. The possible race with hugepage allocation + * or demotion can be prevented by PageHWPoison flag. + */ +- if (res == 0) { ++ if (res == MF_HUGETLB_FREED) { + unlock_page(head); + if (__page_handle_poison(p) > 0) { + page_ref_inc(p); diff --git a/queue-6.1/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch b/queue-6.1/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch new file mode 100644 index 0000000000..bcf7eaaa27 --- /dev/null +++ b/queue-6.1/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch @@ -0,0 +1,192 @@ +From stable+bounces-256792-greg=kroah.com@vger.kernel.org Sat May 30 03:18:50 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 17:48:42 -0400 +Subject: mm/memory: fix spurious warning when unmapping device-private/exclusive pages +To: stable@vger.kernel.org +Cc: "Alistair Popple" , "Arsen Arsenović" , "Balbir Singh" , "David Hildenbrand" , "Jason Gunthorpe" , "John Hubbard" , "Leon Romanovsky" , "Liam R. Howlett" , "Lorenzo Stoakes" , "Peter Xu" , "Matthew Brost" , "Michal Hocko" , "Mike Rapoport" , "Shuah Khan" , "Suren Baghdasaryan" , "Thomas Hellström" , "Vlastimil Babka" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260529214842.1804656-1-sashal@kernel.org> + +From: Alistair Popple + +[ Upstream commit be3f38d05cc5a7c3f13e51994c5dd043ab604d28 ] + +Device private and exclusive entries are only supported for anonymous +folios. This condition is tested in __migrate_device_pages() and +make_device_exclusive() using folio_test_anon(). However the unmap path +tests this assumption using vma_is_anonymous(). + +This is wrong because whilst anonymous VMAs can only contain folios where +folio_test_anon() is true the opposite relation does not hold. A folio +for which folio_test_anon() is true does not imply vma_is_anonymous() is +true. Such a condition can occur if for example a folio is part of a +private filebacked mapping. + +In this case vma_is_anonymous() is false as the mapping is filebacked, but +folio_test_anon() may be true, thus permitting devices to migrate the +folio to device private memory. This can lead to the following spurious +warnings during process teardown: + +[ 772.737706] ------------[ cut here ]------------ +[ 772.739201] WARNING: mm/memory.c:1754 at unmap_page_range.cold+0x26/0x18a, CPU#17: hmm-tests/2041 +[ 772.742050] Modules linked in: test_hmm nvidia_uvm(O) nvidia(O) +[ 772.743959] CPU: 17 UID: 0 PID: 2041 Comm: hmm-tests Tainted: G W O 7.0.0+ #387 PREEMPT(full) +[ 772.747104] Tainted: [W]=WARN, [O]=OOT_MODULE +[ 772.748509] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 +[ 772.752117] RIP: 0010:unmap_page_range.cold+0x26/0x18a +[ 772.753780] Code: 7e fe ff ff 48 89 4c 24 78 4c 89 44 24 38 e8 f2 ff b1 00 48 8b 4c 24 78 4c 8b 44 24 38 48 8b 44 24 18 48 83 78 48 00 74 04 90 <0f> 0b 90 48 89 ca b8 ff ff 37 00 48 c1 ea 03 48 c1 e0 2a 80 3c 02 +[ 772.759602] RSP: 0018:ffff888112607550 EFLAGS: 00010286 +[ 772.761310] RAX: ffff88811bbf4dc0 RBX: dffffc0000000000 RCX: ffffea03e9bfffd8 +[ 772.763583] RDX: 1ffff1102377e9c1 RSI: 0000000000000008 RDI: ffff88811bbf4e08 +[ 772.765914] RBP: 0000000000000006 R08: ffff8881059f7448 R09: ffffed10224c0e68 +[ 772.768184] R10: ffff888112607347 R11: 0000000000000001 R12: 0000000000000001 +[ 772.770461] R13: ffffea03e9bfffc0 R14: ffff888112607908 R15: ffffea03e9bfffc0 +[ 772.772782] FS: 00007f327caa2780(0000) GS:ffff888427b7d000(0000) knlGS:0000000000000000 +[ 772.775328] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 772.777187] CR2: 00007f327ca89000 CR3: 00000001994d5000 CR4: 00000000000006f0 +[ 772.779135] Call Trace: +[ 772.779792] +[ 772.780317] ? dmirror_interval_invalidate+0x1a3/0x290 [test_hmm] +[ 772.781873] ? vm_normal_page_pud+0x2b0/0x2b0 +[ 772.782992] ? __rwlock_init+0x150/0x150 +[ 772.784006] ? lock_release+0x216/0x2b0 +[ 772.785008] ? __mmu_notifier_invalidate_range_start+0x505/0x6e0 +[ 772.786522] ? lock_release+0x216/0x2b0 +[ 772.787498] ? unmap_single_vma+0xb6/0x210 +[ 772.788573] unmap_vmas+0x27d/0x520 +[ 772.789506] ? unmap_single_vma+0x210/0x210 +[ 772.790607] ? mas_update_gap.part.0+0x620/0x620 +[ 772.791834] unmap_region+0x19e/0x350 +[ 772.792769] ? remove_vma+0x130/0x130 +[ 772.793684] ? mas_alloc_nodes+0x1f2/0x300 +[ 772.794730] vms_complete_munmap_vmas+0x8c1/0xe20 +[ 772.795926] ? unmap_region+0x350/0x350 +[ 772.796917] do_vmi_align_munmap+0x36a/0x4e0 +[ 772.798018] ? lock_release+0x216/0x2b0 +[ 772.799024] ? vma_shrink+0x620/0x620 +[ 772.799983] do_vmi_munmap+0x150/0x2c0 +[ 772.800939] __vm_munmap+0x161/0x2c0 +[ 772.801872] ? expand_downwards+0xd60/0xd60 +[ 772.802948] ? clockevents_program_event+0x1ef/0x540 +[ 772.804217] ? lock_release+0x216/0x2b0 +[ 772.805158] __x64_sys_munmap+0x59/0x80 +[ 772.805776] do_syscall_64+0xfc/0x670 +[ 772.806336] ? irqentry_exit+0xda/0x580 +[ 772.806976] entry_SYSCALL_64_after_hwframe+0x4b/0x53 +[ 772.807772] RIP: 0033:0x7f327cbb2717 +[ 772.808323] Code: 73 01 c3 48 8b 0d f9 76 0d 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 0b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c9 76 0d 00 f7 d8 64 89 01 48 +[ 772.811337] RSP: 002b:00007ffde7f57d38 EFLAGS: 00000202 ORIG_RAX: 000000000000000b +[ 772.812564] RAX: ffffffffffffffda RBX: 00007f327cc9c000 RCX: 00007f327cbb2717 +[ 772.813733] RDX: 0000000000000000 RSI: 0000000000400000 RDI: 00007f327c289000 +[ 772.814867] RBP: 0000000000421360 R08: 000000000000001a R09: 0000000000000000 +[ 772.815991] R10: 0000000000000003 R11: 0000000000000202 R12: 00007ffde7f57d74 +[ 772.817121] R13: 00007f327c689010 R14: 0000000000100000 R15: 00007f327c289000 +[ 772.818272] +[ 772.818614] irq event stamp: 0 +[ 772.819159] hardirqs last enabled at (0): [<0000000000000000>] 0x0 +[ 772.820174] hardirqs last disabled at (0): [] copy_process+0x19f3/0x6440 +[ 772.821511] softirqs last enabled at (0): [] copy_process+0x1a40/0x6440 +[ 772.822869] softirqs last disabled at (0): [<0000000000000000>] 0x0 +[ 772.823871] ---[ end trace 0000000000000000 ]--- + +Fix this by using the same check for folio_test_anon() in +zap_nonpresent_ptes(). Also add a hmm-test case for this. + +Link: https://lore.kernel.org/20260501065116.2057242-1-apopple@nvidia.com +Fixes: 999dad824c39 ("mm/shmem: persist uffd-wp bit across zapping for file-backed") +Signed-off-by: Alistair Popple +Reported-by: Arsen Arsenović +Reviewed-by: Balbir Singh +Cc: David Hildenbrand +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Leon Romanovsky +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Peter Xu +Cc: Matthew Brost +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Thomas Hellström +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +[ adapted `folio_test_anon(folio)` to `PageAnon(page)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory.c | 2 - + tools/testing/selftests/vm/hmm-tests.c | 50 +++++++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+), 1 deletion(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1471,7 +1471,7 @@ again: + * consider uffd-wp bit when zap. For more information, + * see zap_install_uffd_wp_if_needed(). + */ +- WARN_ON_ONCE(!vma_is_anonymous(vma)); ++ WARN_ON_ONCE(!PageAnon(page)); + rss[mm_counter(page)]--; + if (is_device_private_entry(entry)) + page_remove_rmap(page, vma, false); +--- a/tools/testing/selftests/vm/hmm-tests.c ++++ b/tools/testing/selftests/vm/hmm-tests.c +@@ -994,6 +994,56 @@ TEST_F(hmm, migrate) + } + + /* ++ * Migrate private file memory to device private memory. ++ */ ++TEST_F(hmm, migrate_file_private) ++{ ++ struct hmm_buffer *buffer; ++ unsigned long npages; ++ unsigned long size; ++ unsigned long i; ++ int *ptr; ++ int ret; ++ int fd; ++ ++ npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; ++ ASSERT_NE(npages, 0); ++ size = npages << self->page_shift; ++ ++ fd = hmm_create_file(size); ++ ASSERT_GE(fd, 0); ++ ++ buffer = malloc(sizeof(*buffer)); ++ ASSERT_NE(buffer, NULL); ++ ++ buffer->fd = fd; ++ buffer->size = size; ++ buffer->mirror = malloc(size); ++ ASSERT_NE(buffer->mirror, NULL); ++ ++ buffer->ptr = mmap(NULL, size, ++ PROT_READ | PROT_WRITE, ++ MAP_PRIVATE, ++ buffer->fd, 0); ++ ASSERT_NE(buffer->ptr, MAP_FAILED); ++ ++ /* Initialize buffer in system memory. */ ++ for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) ++ ptr[i] = i; ++ ++ /* Migrate memory to device. */ ++ ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages); ++ ASSERT_EQ(ret, 0); ++ ASSERT_EQ(buffer->cpages, npages); ++ ++ /* Check what the device read. */ ++ for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) ++ ASSERT_EQ(ptr[i], i); ++ ++ hmm_buffer_free(buffer); ++} ++ ++/* + * Migrate anonymous memory to device private memory and fault some of it back + * to system memory, then try migrating the resulting mix of system and device + * private memory to the device. diff --git a/queue-6.1/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch b/queue-6.1/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch new file mode 100644 index 0000000000..3ce9738d7a --- /dev/null +++ b/queue-6.1/mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch @@ -0,0 +1,83 @@ +From stable+bounces-263444-greg=kroah.com@vger.kernel.org Tue Jun 16 01:12:47 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 15:42:34 -0400 +Subject: mm/migrate: don't call folio_putback_active_hugetlb() on dst hugetlb folio +To: stable@vger.kernel.org +Cc: David Hildenbrand , Baolin Wang , "Matthew Wilcox (Oracle)" , Muchun Song , Sidhartha Kumar , Andrew Morton , Sasha Levin +Message-ID: <20260615194237.2391157-2-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit ba23f58de896842028b4b33b95530f08288396fe ] + +We replaced a simple put_page() by a putback_active_hugepage() call in +commit 3aaa76e125c1 ("mm: migrate: hugetlb: putback destination hugepage +to active list"), to set the "active" flag on the dst hugetlb folio. + +Nowadays, we decoupled the "active" list from the flag, by calling the +flag "migratable". + +Calling "putback" on something that wasn't allocated is weird and not +future proof, especially if we might reach that path when migration failed +and we just want to free the freshly allocated hugetlb folio. + +Let's simply handle the migratable flag and the active list flag in +move_hugetlb_state(), where we know that allocation succeeded and already +handle the temporary flag; use a simple folio_put() to return our +reference. + +Link: https://lkml.kernel.org/r/20250113131611.2554758-4-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Baolin Wang +Cc: Matthew Wilcox (Oracle) +Cc: Muchun Song +Cc: Sidhartha Kumar +Signed-off-by: Andrew Morton +Stable-dep-of: 3c2d42b8ee34 ("mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 10 ++++++++++ + mm/migrate.c | 8 ++++---- + 2 files changed, 14 insertions(+), 4 deletions(-) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7555,6 +7555,16 @@ void move_hugetlb_state(struct page *old + } + spin_unlock_irq(&hugetlb_lock); + } ++ ++ /* ++ * Our old page is isolated and has "migratable" cleared until it ++ * is putback. As migration succeeded, set the new page "migratable" ++ * and add it to the active list. ++ */ ++ spin_lock_irq(&hugetlb_lock); ++ SetHPageMigratable(newpage); ++ list_move_tail(&newpage->lru, &(page_hstate(newpage))->hugepage_activelist); ++ spin_unlock_irq(&hugetlb_lock); + } + + /* +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -1460,14 +1460,14 @@ out: + list_move_tail(&src->lru, ret); + + /* +- * If migration was not successful and there's a freeing callback, use +- * it. Otherwise, put_page() will drop the reference grabbed during +- * isolation. ++ * If migration was not successful and there's a freeing callback, ++ * return the folio to that special allocator. Otherwise, simply drop ++ * our additional reference. + */ + if (put_new_page) + put_new_page(new_hpage, private); + else +- putback_active_hugepage(new_hpage); ++ folio_put(dst); + + return rc; + } diff --git a/queue-6.1/mptcp-do-not-drop-partial-packets.patch b/queue-6.1/mptcp-do-not-drop-partial-packets.patch new file mode 100644 index 0000000000..2bec1ff537 --- /dev/null +++ b/queue-6.1/mptcp-do-not-drop-partial-packets.patch @@ -0,0 +1,76 @@ +From stable+bounces-257079-greg=kroah.com@vger.kernel.org Sat May 30 22:22:19 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 12:48:34 -0400 +Subject: mptcp: do not drop partial packets +To: stable@vger.kernel.org +Cc: Shardul Bankar , Paolo Abeni , "Matthieu Baerts (NGI0)" , Sasha Levin +Message-ID: <20260530164834.2992487-1-sashal@kernel.org> + +From: Shardul Bankar + +[ Upstream commit 50c2d91c5dfa0e465826ec1f8dbad9cdc254bd85 ] + +When a packet arrives with map_seq < ack_seq < end_seq, the beginning +of the packet has already been acknowledged but the end contains new +data. Currently the entire packet is dropped as "old data," forcing +the sender to retransmit. + +Instead, skip the already-acked bytes by adjusting the skb offset and +enqueue only the new portion. Update bytes_received and ack_seq to +reflect the new data consumed. + +A previous attempt at this fix has been sent by Paolo Abeni [1], but had +issues [2]: it also added a zero-window check and changed rcv_wnd_sent +initialization, which caused test regressions. This version addresses +only the partial packet handling without modifying receive window +accounting. + +Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/c9b426a4e163aa3c4fe8b80c79f1a610f47ae7d8.1763075056.git.pabeni@redhat.com [1] +Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/600 [2] +Signed-off-by: Shardul Bankar +[pabeni@redhat.com: update map] +Signed-off-by: Paolo Abeni +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-1-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +[ changed `skb_set_owner_r()` to `mptcp_set_owner_r()` and dropped the absent `msk->bytes_received` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/protocol.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -400,10 +400,25 @@ static bool __mptcp_move_skb(struct mptc + return false; + } + +- /* old data, keep it simple and drop the whole pkt, sender +- * will retransmit as needed, if needed. ++ /* Completely old data? */ ++ if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); ++ mptcp_drop(sk, skb); ++ return false; ++ } ++ ++ /* Partial packet: map_seq < ack_seq < end_seq. ++ * Skip the already-acked bytes and enqueue the new data. + */ +- MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); ++ copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq; ++ MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; ++ MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq - ++ MPTCP_SKB_CB(skb)->map_seq; ++ WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); ++ ++ mptcp_set_owner_r(skb, sk); ++ __skb_queue_tail(&sk->sk_receive_queue, skb); ++ return true; + drop: + mptcp_drop(sk, skb); + return false; diff --git a/queue-6.1/mptcp-fastclose-msk-when-linger-time-is-0.patch b/queue-6.1/mptcp-fastclose-msk-when-linger-time-is-0.patch new file mode 100644 index 0000000000..b854adebd9 --- /dev/null +++ b/queue-6.1/mptcp-fastclose-msk-when-linger-time-is-0.patch @@ -0,0 +1,56 @@ +From stable+bounces-249177-greg=kroah.com@vger.kernel.org Mon May 18 08:58:20 2026 +From: Sasha Levin +Date: Sun, 17 May 2026 23:28:15 -0400 +Subject: mptcp: fastclose msk when linger time is 0 +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Lance Tuller , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518032815.587921-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit f14d6e9c3678a067f304abba561e0c5446c7e845 ] + +The SO_LINGER socket option has been supported for a while with MPTCP +sockets [1], but it didn't cause the equivalent of a TCP reset as +expected when enabled and its time was set to 0. This was causing some +behavioural differences with TCP where some connections were not +promptly stopped as expected. + +To fix that, an extra condition is checked at close() time before +sending an MP_FASTCLOSE, the MPTCP equivalent of a TCP reset. + +Note that backporting up to [1] will be difficult as more changes are +needed to be able to send MP_FASTCLOSE. It seems better to stop at [2], +which was supposed to already imitate TCP. + +Validated with MPTCP packetdrill tests [3]. + +Fixes: 268b12387460 ("mptcp: setsockopt: support SO_LINGER") [1] +Fixes: d21f83485518 ("mptcp: use fastclose on more edge scenarios") [2] +Cc: stable@vger.kernel.org +Reported-by: Lance Tuller +Closes: https://github.com/lance0/xfr/pull/67 +Link: https://github.com/multipath-tcp/packetdrill/pull/196 [3] +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260427-net-mptcp-misc-fixes-7-1-rc2-v1-3-7432b7f279fa@kernel.org +Signed-off-by: Jakub Kicinski +[ kept `mptcp_check_readable()` name and explicit `inet_sk_state_store(sk, TCP_CLOSE)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/protocol.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -3158,7 +3158,8 @@ bool __mptcp_close(struct sock *sk, long + goto cleanup; + } + +- if (mptcp_check_readable(msk)) { ++ if (mptcp_check_readable(msk) || ++ (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { + /* the msk has read data, do the MPTCP equivalent of TCP reset */ + inet_sk_state_store(sk, TCP_CLOSE); + mptcp_do_fastclose(sk); diff --git a/queue-6.1/mptcp-pm-add_addr-rtx-allow-id-0.patch b/queue-6.1/mptcp-pm-add_addr-rtx-allow-id-0.patch new file mode 100644 index 0000000000..78df45eec6 --- /dev/null +++ b/queue-6.1/mptcp-pm-add_addr-rtx-allow-id-0.patch @@ -0,0 +1,44 @@ +From stable+bounces-249310-greg=kroah.com@vger.kernel.org Mon May 18 20:15:19 2026 +From: Sasha Levin +Date: Mon, 18 May 2026 10:33:51 -0400 +Subject: mptcp: pm: ADD_ADDR rtx: allow ID 0 +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518143351.1340874-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 03f324f3f1f7619a47b9c91282cb12775ab0a2f1 ] + +ADD_ADDR can be sent for the ID 0, which corresponds to the local +address and port linked to the initial subflow. + +Indeed, this address could be removed, and re-added later on, e.g. what +is done in the "delete re-add signal" MPTCP Join selftests. So no reason +to ignore it. + +Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout") +Cc: stable@vger.kernel.org +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-2-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ relocated the 3-line deletion from net/mptcp/pm.c to net/mptcp/pm_netlink.c ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -315,9 +315,6 @@ static void mptcp_pm_add_timer(struct ti + if (inet_sk_state_load(sk) == TCP_CLOSE) + return; + +- if (!entry->addr.id) +- return; +- + if (mptcp_pm_should_add_signal_addr(msk)) { + sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); + goto out; diff --git a/queue-6.1/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch b/queue-6.1/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch new file mode 100644 index 0000000000..5f5267bad4 --- /dev/null +++ b/queue-6.1/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch @@ -0,0 +1,55 @@ +From stable+bounces-249311-greg=kroah.com@vger.kernel.org Mon May 18 20:20:59 2026 +From: Sasha Levin +Date: Mon, 18 May 2026 10:33:55 -0400 +Subject: mptcp: pm: ADD_ADDR rtx: fix potential data-race +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518143355.1341039-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 5cd6e0ad79d2615264f63929f8b457ad97ae550d ] + +This mptcp_pm_add_timer() helper is executed as a timer callback in +softirq context. To avoid any data races, the socket lock needs to be +held with bh_lock_sock(). + +If the socket is in use, retry again soon after, similar to what is done +with the keepalive timer. + +Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout") +Cc: stable@vger.kernel.org +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-3-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -315,6 +315,13 @@ static void mptcp_pm_add_timer(struct ti + if (inet_sk_state_load(sk) == TCP_CLOSE) + return; + ++ bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) { ++ /* Try again later. */ ++ sk_reset_timer(sk, timer, jiffies + HZ / 20); ++ goto out; ++ } ++ + if (mptcp_pm_should_add_signal_addr(msk)) { + sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); + goto out; +@@ -343,6 +350,7 @@ static void mptcp_pm_add_timer(struct ti + mptcp_pm_subflow_established(msk); + + out: ++ bh_unlock_sock(sk); + __sock_put(sk); + } + diff --git a/queue-6.1/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch b/queue-6.1/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch new file mode 100644 index 0000000000..3840a6def8 --- /dev/null +++ b/queue-6.1/mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch @@ -0,0 +1,53 @@ +From stable+bounces-249577-greg=kroah.com@vger.kernel.org Tue May 19 18:18:56 2026 +From: Sasha Levin +Date: Tue, 19 May 2026 08:41:06 -0400 +Subject: mptcp: pm: ADD_ADDR rtx: resched blocked ADD_ADDR quicker +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260519124106.2431795-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 3cf12492891c4b5ff54dda404a2de4ec54c9e1b5 ] + +When an ADD_ADDR needs to be retransmitted and another one has already +been prepared -- e.g. multiple ADD_ADDRs have been sent in a row and +need to be retransmitted later -- this additional retransmission will +need to wait. + +In this case, the timer was reset to TCP_RTO_MAX / 8, which is ~15 +seconds. This delay is unnecessary long: it should just be rescheduled +at the next opportunity, e.g. after the retransmission timeout. + +Without this modification, some issues can be seen from time to time in +the selftests when multiple ADD_ADDRs are sent, and the host takes time +to process them, e.g. the "signal addresses, ADD_ADDR timeout" MPTCP +Join selftest, especially with a debug kernel config. + +Note that on older kernels, 'timeout' is not available. It should be +enough to replace it by one second (HZ). + +Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout") +Cc: stable@vger.kernel.org +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-6-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ replaced `TCP_RTO_MAX / 8` with `HZ` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -323,7 +323,7 @@ static void mptcp_pm_add_timer(struct ti + } + + if (mptcp_pm_should_add_signal_addr(msk)) { +- sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); ++ sk_reset_timer(sk, timer, jiffies + HZ); + goto out; + } + diff --git a/queue-6.1/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch b/queue-6.1/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch new file mode 100644 index 0000000000..aff752883a --- /dev/null +++ b/queue-6.1/mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch @@ -0,0 +1,144 @@ +From stable+bounces-256871-greg=kroah.com@vger.kernel.org Sat May 30 17:09:18 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 07:39:11 -0400 +Subject: mptcp: pm: fix ADD_ADDR timer infinite retry on option space insufficient +To: stable@vger.kernel.org +Cc: Li Xiasong , "Matthieu Baerts (NGI0)" , Paolo Abeni , Sasha Levin +Message-ID: <20260530113911.1938311-1-sashal@kernel.org> + +From: Li Xiasong + +[ Upstream commit 51e398a3b8961b26a8c0a4ba9a777c5339791707 ] + +When TCP option space is insufficient (e.g., when sending ADD_ADDR with an +IPv6 address and port while tcp_timestamps is enabled), the original code +jumped to out_unlock without clearing the addr_signal flag. This caused +mptcp_pm_add_timer to keep rescheduling indefinitely, not sending ADD_ADDR, +preventing subsequent addresses in the endpoint list from being announced. + +Handle this case by clearing the ADD_ADDR signal and skipping the matching +ADD_ADDR retransmission entry. The skip path cancels the matching timer +(with id check) and advances PM state progression, preserving forward +progress to subsequent PM work. + +This cancellation is inherently best-effort. A concurrent add_timer +callback may already be running and may acquire pm.lock before the +cancel path updates entry state. In that case, one final ADD_ADDR +transmit attempt can still be executed. + +Once the cancel path sets entry->retrans_times to ADD_ADDR_RETRANS_MAX, +the callback-side retrans_times check suppresses further ADD_ADDR +retransmissions. + +Note that when an ADD_ADDR is being prepared, a pure-ACK is queued. On +the output side, it means that it is fine to skip non-pure-ACK packets, +when drop_other_suboptions is set: a pure-ACK will be processed soon +after. + +Fixes: 00cfd77b9063 ("mptcp: retransmit ADD_ADDR when timeout") +Cc: stable@vger.kernel.org +Signed-off-by: Li Xiasong +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-2-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm.c | 34 +++++++++++++++++++++++++++------- + net/mptcp/pm_netlink.c | 16 +++++++++++++--- + 2 files changed, 40 insertions(+), 10 deletions(-) + +--- a/net/mptcp/pm.c ++++ b/net/mptcp/pm.c +@@ -340,6 +340,7 @@ bool mptcp_pm_add_addr_signal(struct mpt + struct mptcp_addr_info *addr, bool *echo, + bool *drop_other_suboptions) + { ++ bool skip_add_addr = false; + int ret = false; + u8 add_addr; + u8 family; +@@ -361,24 +362,43 @@ bool mptcp_pm_add_addr_signal(struct mpt + } + + *echo = mptcp_pm_should_add_signal_echo(msk); +- port = !!(*echo ? msk->pm.remote.port : msk->pm.local.port); +- +- family = *echo ? msk->pm.remote.family : msk->pm.local.family; +- if (remaining < mptcp_add_addr_len(family, *echo, port)) +- goto out_unlock; +- + if (*echo) { + *addr = msk->pm.remote; + add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_ECHO); ++ port = !!msk->pm.remote.port; ++ family = msk->pm.remote.family; + } else { + *addr = msk->pm.local; + add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_SIGNAL); ++ port = !!msk->pm.local.port; ++ family = msk->pm.local.family; + } +- WRITE_ONCE(msk->pm.addr_signal, add_addr); ++ ++ if (remaining < mptcp_add_addr_len(family, *echo, port)) { ++ if (!*drop_other_suboptions) ++ goto out_unlock; ++ ++ if (!*echo) ++ skip_add_addr = true; ++ goto drop_signal_mark; ++ } ++ + ret = true; + ++drop_signal_mark: ++ WRITE_ONCE(msk->pm.addr_signal, add_addr); ++ + out_unlock: + spin_unlock_bh(&msk->pm.lock); ++ ++ /* On pure-ACK option-space exhaustion, stop retrying this ADD_ADDR: ++ * clear the signal bit, cancel the matching retransmission timer, and ++ * let the PM state machine progress. ++ */ ++ if (skip_add_addr) { ++ mptcp_pm_del_add_timer(msk, addr, true); ++ mptcp_pm_subflow_established(msk); ++ } + return ret; + } + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -333,7 +333,13 @@ static void mptcp_pm_add_timer(struct ti + + spin_lock_bh(&msk->pm.lock); + +- if (!mptcp_pm_should_add_signal_addr(msk)) { ++ /* The cancel path (mptcp_pm_del_add_timer()) can race with this ++ * callback. Once cancel updates retrans_times to MAX, suppress further ++ * retransmissions here. If this callback acquires pm.lock first, one ++ * final transmit attempt is still possible. ++ */ ++ if (entry->retrans_times < ADD_ADDR_RETRANS_MAX && ++ !mptcp_pm_should_add_signal_addr(msk)) { + pr_debug("retransmit ADD_ADDR id=%d\n", entry->addr.id); + mptcp_pm_announce_addr(msk, &entry->addr, false); + mptcp_pm_add_addr_send_ack(msk); +@@ -377,8 +383,12 @@ mptcp_pm_del_add_timer(struct mptcp_sock + /* Note: entry might have been removed by another thread. + * We hold rcu_read_lock() to ensure it is not freed under us. + */ +- if (stop_timer) +- sk_stop_timer_sync(sk, &entry->add_timer); ++ if (stop_timer) { ++ if (check_id) ++ sk_stop_timer(sk, &entry->add_timer); ++ else ++ sk_stop_timer_sync(sk, &entry->add_timer); ++ } + + rcu_read_unlock(); + return entry; diff --git a/queue-6.1/mptcp-pm-kernel-correctly-retransmit-add_addr-id-0.patch b/queue-6.1/mptcp-pm-kernel-correctly-retransmit-add_addr-id-0.patch new file mode 100644 index 0000000000..74c2e774b8 --- /dev/null +++ b/queue-6.1/mptcp-pm-kernel-correctly-retransmit-add_addr-id-0.patch @@ -0,0 +1,71 @@ +From stable+bounces-249306-greg=kroah.com@vger.kernel.org Mon May 18 20:02:54 2026 +From: Sasha Levin +Date: Mon, 18 May 2026 10:23:40 -0400 +Subject: mptcp: pm: kernel: correctly retransmit ADD_ADDR ID 0 +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518142340.1308453-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit b12014d2d36eaed4e4bec5f1ac7e91110eeb100d ] + +When adding the ADD_ADDR to the list, the address including the IP, port +and ID are copied. On the other hand, when the endpoint corresponds to +the one from the initial subflow, the ID is set to 0, as specified by +the MPTCP protocol. + +The issue is that the ID was reset after having copied the ID in the +ADD_ADDR entry. So the retransmission was done, but using a different ID +than the initial one. + +Fixes: 8b8ed1b429f8 ("mptcp: pm: reuse ID 0 after delete and re-add") +Cc: stable@vger.kernel.org +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-1-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ applied to net/mptcp/pm_netlink.c instead of upstream's pm_kernel.c ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -595,6 +595,8 @@ static void mptcp_pm_create_subflow_or_s + + /* check first for announce */ + if (msk->pm.add_addr_signaled < add_addr_signal_max) { ++ u8 endp_id; ++ + /* due to racing events on both ends we can reach here while + * previous add address is still running: if we invoke now + * mptcp_pm_announce_addr(), that will fail and the +@@ -608,19 +610,20 @@ static void mptcp_pm_create_subflow_or_s + if (!select_signal_address(pernet, msk, &local)) + goto subflow; + ++ /* Special case for ID0: set the correct ID */ ++ endp_id = local.addr.id; ++ if (endp_id == msk->mpc_endpoint_id) ++ local.addr.id = 0; ++ + /* If the alloc fails, we are on memory pressure, not worth + * continuing, and trying to create subflows. + */ + if (!mptcp_pm_alloc_anno_list(msk, &local.addr)) + return; + +- __clear_bit(local.addr.id, msk->pm.id_avail_bitmap); ++ __clear_bit(endp_id, msk->pm.id_avail_bitmap); + msk->pm.add_addr_signaled++; + +- /* Special case for ID0: set the correct ID */ +- if (local.addr.id == msk->mpc_endpoint_id) +- local.addr.id = 0; +- + mptcp_pm_announce_addr(msk, &local.addr, false); + mptcp_pm_nl_addr_send_ack(msk); + diff --git a/queue-6.1/mptcp-pm-prio-skip-closed-subflows.patch b/queue-6.1/mptcp-pm-prio-skip-closed-subflows.patch new file mode 100644 index 0000000000..ad724c49d2 --- /dev/null +++ b/queue-6.1/mptcp-pm-prio-skip-closed-subflows.patch @@ -0,0 +1,46 @@ +From stable+bounces-249292-greg=kroah.com@vger.kernel.org Mon May 18 19:22:29 2026 +From: Sasha Levin +Date: Mon, 18 May 2026 09:45:31 -0400 +Subject: mptcp: pm: prio: skip closed subflows +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20260518134531.1135631-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 166b78344031bf7ac9f55cb5282776cfd85f220e ] + +When sending an MP_PRIO, closed subflows need to be skipped. + +This fixes the case where the initial subflow got closed, re-opened +later, then an MP_PRIO is needed for the same local address. + +Note that explicit MP_PRIO cannot be sent during the 3WHS, so it is fine +to use __mptcp_subflow_active(). + +Fixes: 067065422fcd ("mptcp: add the outgoing MP_PRIO support") +Cc: stable@vger.kernel.org +Fixes: b29fcfb54cd7 ("mptcp: full disconnect implementation") +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-9-fca8091060a4@kernel.org +Signed-off-by: Jakub Kicinski +[ applied to renamed function `mptcp_pm_nl_mp_prio_send_ack()` in `pm_netlink.c` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -924,6 +924,9 @@ int mptcp_pm_nl_mp_prio_send_ack(struct + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + struct mptcp_addr_info local, remote; + ++ if (!__mptcp_subflow_active(subflow)) ++ continue; ++ + mptcp_local_address((struct sock_common *)ssk, &local); + if (!mptcp_addresses_equal(&local, addr, addr->port)) + continue; diff --git a/queue-6.1/mptcp-reset-rcv-wnd-on-disconnect.patch b/queue-6.1/mptcp-reset-rcv-wnd-on-disconnect.patch new file mode 100644 index 0000000000..724d02d78e --- /dev/null +++ b/queue-6.1/mptcp-reset-rcv-wnd-on-disconnect.patch @@ -0,0 +1,47 @@ +From stable+bounces-257008-greg=kroah.com@vger.kernel.org Sat May 30 22:01:25 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 12:31:14 -0400 +Subject: mptcp: reset rcv wnd on disconnect +To: stable@vger.kernel.org +Cc: Paolo Abeni , "Matthieu Baerts (NGI0)" , Sasha Levin +Message-ID: <20260530163114.2911574-1-sashal@kernel.org> + +From: Paolo Abeni + +[ Upstream commit 0981f90e1a05773a4c29c6e720f5ea1e3c8f1876 ] + +If the MPTCP socket fallback to TCP before the MP handshake completion, +the IASN remain 0, and the rcv_wnd_sent field is not explicitly +initialized, just incremented over time with the data transfer. + +At disconnect time such value is not cleared. If the next connection falls +back to TCP before the MP handshake completion, the data transfer will +keep incrementing the receive window end sequence starting from the last +value used in the previous connection: the announced window will be +unrelated from the actual receiver buffer size and likely too big. + +Address the issue zeroing the field at disconnect time. + +Fixes: b29fcfb54cd7 ("mptcp: full disconnect implementation") +Cc: stable@vger.kernel.org +Signed-off-by: Paolo Abeni +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-4-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/protocol.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -3298,6 +3298,7 @@ static int mptcp_disconnect(struct sock + mptcp_pm_data_reset(msk); + mptcp_ca_reset(sk); + msk->fastclosing = 0; ++ atomic64_set(&msk->rcv_wnd_sent, 0); + + WRITE_ONCE(sk->sk_shutdown, 0); + sk_error_report(sk); diff --git a/queue-6.1/mtd-spi-nor-core-fix-implicit-declaration-warning.patch b/queue-6.1/mtd-spi-nor-core-fix-implicit-declaration-warning.patch new file mode 100644 index 0000000000..9c8b75da88 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-core-fix-implicit-declaration-warning.patch @@ -0,0 +1,41 @@ +From stable+bounces-247170-greg=kroah.com@vger.kernel.org Thu May 14 17:15:46 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:45:39 -0400 +Subject: mtd: spi-nor: core: fix implicit declaration warning +To: stable@vger.kernel.org +Cc: Zeng Heng , Tudor Ambarus , Sasha Levin +Message-ID: <20260514114540.178942-1-sashal@kernel.org> + +From: Zeng Heng + +[ Upstream commit 25e3f30601a368642678744fc8a9b1dce183c7bc ] + +spi-nor/core.c needs to include linux/delay.h, +or it would raise below compile warning: + +drivers/mtd/spi-nor/core.c: In function ‘spi_nor_soft_reset’: +drivers/mtd/spi-nor/core.c:2779:2: error: implicit declaration of function ‘usleep_range’ [-Werror=implicit-function-declaration] + 2779 | usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX); + | ^~~~~~~~~~~~ + +Fixes: d73ee7534cc5 ("mtd: spi-nor: core: perform a Soft Reset on shutdown") +Signed-off-by: Zeng Heng +Signed-off-by: Tudor Ambarus +Link: https://lore.kernel.org/r/20220923031457.56103-1-zengheng4@huawei.com +Stable-dep-of: e47029b977e7 ("mtd: spi-nor: debugfs: fix out-of-bounds read in spi_nor_params_show()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/core.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include diff --git a/queue-6.1/mtd-spi-nor-debugfs-fix-out-of-bounds-read-in-spi_nor_params_show.patch b/queue-6.1/mtd-spi-nor-debugfs-fix-out-of-bounds-read-in-spi_nor_params_show.patch new file mode 100644 index 0000000000..b0af2b17e8 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-debugfs-fix-out-of-bounds-read-in-spi_nor_params_show.patch @@ -0,0 +1,65 @@ +From stable+bounces-247172-greg=kroah.com@vger.kernel.org Thu May 14 17:19:48 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:45:40 -0400 +Subject: mtd: spi-nor: debugfs: fix out-of-bounds read in spi_nor_params_show() +To: stable@vger.kernel.org +Cc: Tudor Ambarus , Takahiro Kuwano , Michael Walle , Pratyush Yadav , Miquel Raynal , Sasha Levin +Message-ID: <20260514114540.178942-2-sashal@kernel.org> + +From: Tudor Ambarus + +[ Upstream commit e47029b977e747cb3a9174308fd55762cce70147 ] + +Sashiko noticed an out-of-bounds read [1]. + +In spi_nor_params_show(), the snor_f_names array is passed to +spi_nor_print_flags() using sizeof(snor_f_names). + +Since snor_f_names is an array of pointers, sizeof() returns the total +number of bytes occupied by the pointers + (element_count * sizeof(void *)) +rather than the element count itself. On 64-bit systems, this makes the +passed length 8x larger than intended. + +Inside spi_nor_print_flags(), the 'names_len' argument is used to +bounds-check the 'names' array access. An out-of-bounds read occurs +if a flag bit is set that exceeds the array's actual element count +but is within the inflated byte-size count. + +Correct this by using ARRAY_SIZE() to pass the actual number of +string pointers in the array. + +Cc: stable@vger.kernel.org +Fixes: 0257be79fc4a ("mtd: spi-nor: expose internal parameters via debugfs") +Closes: https://sashiko.dev/#/patchset/20260417-die-erase-fix-v2-1-73bb7004ebad%40infineon.com [1] +Signed-off-by: Tudor Ambarus +Reviewed-by: Takahiro Kuwano +Reviewed-by: Michael Walle +Reviewed-by: Pratyush Yadav +Signed-off-by: Miquel Raynal +[ adjusted include-block context to keep 6.1.y's existing non-alphabetical header order while still adding `#include ` at the top ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/debugfs.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/debugfs.c ++++ b/drivers/mtd/spi-nor/debugfs.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + ++#include + #include + #include + #include +@@ -91,7 +92,8 @@ static int spi_nor_params_show(struct se + seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes); + + seq_puts(s, "flags\t\t"); +- spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names)); ++ spi_nor_print_flags(s, nor->flags, snor_f_names, ++ ARRAY_SIZE(snor_f_names)); + seq_puts(s, "\n"); + + seq_puts(s, "\nopcodes\n"); diff --git a/queue-6.1/net-hsr-defer-node-table-free-until-after-rcu-readers.patch b/queue-6.1/net-hsr-defer-node-table-free-until-after-rcu-readers.patch new file mode 100644 index 0000000000..f5885a867f --- /dev/null +++ b/queue-6.1/net-hsr-defer-node-table-free-until-after-rcu-readers.patch @@ -0,0 +1,55 @@ +From stable+bounces-256836-greg=kroah.com@vger.kernel.org Sat May 30 05:25:19 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 19:55:12 -0400 +Subject: net: hsr: defer node table free until after RCU readers +To: stable@vger.kernel.org +Cc: Michael Bommarito , Jakub Kicinski , Sasha Levin +Message-ID: <20260529235512.1985956-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit aaec7096f9961eb223b5b149abe9495525c205d9 ] + +HSR node-list and node-status generic-netlink operations run under +rcu_read_lock(). They walk hsr->node_db through hsr_get_next_node() and +hsr_get_node_data(), but RTM_DELLINK teardown removes the same node table +with plain list_del() and frees each node immediately. + +That lets a generic-netlink reader hold a struct hsr_node pointer across +hsr_dellink(). In a KASAN build, widening the reader window after +hsr_get_next_node() obtains the node reproduces a slab-use-after-free +when the reader copies node->macaddress_A; the freeing stack is +hsr_del_nodes() from hsr_dellink(). + +Use list_del_rcu() and defer the free through the existing +hsr_free_node_rcu() callback. This matches the lifetime rule used by the +HSR prune paths, which already delete nodes with list_del_rcu() and +call_rcu(). + +Fixes: b9a1e627405d ("hsr: implement dellink to clean up resources") +Cc: stable@vger.kernel.org # v5.3+ +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260513233838.3064715-2-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +[ replaced `list_del`+`call_rcu(hsr_free_node_rcu)` with `list_del_rcu`+`kfree_rcu(node, rcu_head)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/hsr/hsr_framereg.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -121,8 +121,10 @@ void hsr_del_nodes(struct list_head *nod + struct hsr_node *node; + struct hsr_node *tmp; + +- list_for_each_entry_safe(node, tmp, node_db, mac_list) +- kfree(node); ++ list_for_each_entry_safe(node, tmp, node_db, mac_list) { ++ list_del_rcu(&node->mac_list); ++ kfree_rcu(node, rcu_head); ++ } + } + + void prp_handle_san_frame(bool san, enum hsr_port_type port, diff --git a/queue-6.1/net-ipv4-stop-checking-crypto_ahash_alignmask.patch b/queue-6.1/net-ipv4-stop-checking-crypto_ahash_alignmask.patch new file mode 100644 index 0000000000..c875aa6a42 --- /dev/null +++ b/queue-6.1/net-ipv4-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246946-greg=kroah.com@vger.kernel.org Wed May 13 22:34:26 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:52:53 -0400 +Subject: net: ipv4: stop checking crypto_ahash_alignmask +To: stable@vger.kernel.org +Cc: Eric Biggers , Herbert Xu , Sasha Levin +Message-ID: <20260513165255.3822003-1-sashal@kernel.org> + +From: Eric Biggers + +[ Upstream commit e77f5dd701381cef35b9ea8b6dea6e62c8a7f9f3 ] + +Now that the alignmask for ahash and shash algorithms is always 0, +crypto_ahash_alignmask() always returns 0 and will be removed. In +preparation for this, stop checking crypto_ahash_alignmask() in ah4.c. + +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ah4.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/net/ipv4/ah4.c ++++ b/net/ipv4/ah4.c +@@ -27,9 +27,7 @@ static void *ah_alloc_tmp(struct crypto_ + { + unsigned int len; + +- len = size + crypto_ahash_digestsize(ahash) + +- (crypto_ahash_alignmask(ahash) & +- ~(crypto_tfm_ctx_alignment() - 1)); ++ len = size + crypto_ahash_digestsize(ahash); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + +@@ -46,10 +44,9 @@ static inline u8 *ah_tmp_auth(void *tmp, + return tmp + offset; + } + +-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, +- unsigned int offset) ++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset) + { +- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); ++ return tmp + offset; + } + + static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, +@@ -129,7 +126,7 @@ static void ah_output_done(struct crypto + int ihl = ip_hdrlen(skb); + + iph = AH_SKB_CB(skb)->tmp; +- icv = ah_tmp_icv(ahp->ahash, iph, ihl); ++ icv = ah_tmp_icv(iph, ihl); + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + + top_iph->tos = iph->tos; +@@ -182,7 +179,7 @@ static int ah_output(struct xfrm_state * + if (!iph) + goto out; + seqhi = (__be32 *)((char *)iph + ihl); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; +@@ -279,7 +276,7 @@ static void ah_input_done(struct crypto_ + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, ihl); +- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) +@@ -374,7 +371,7 @@ static int ah_input(struct xfrm_state *x + + seqhi = (__be32 *)((char *)work_iph + ihl); + auth_data = ah_tmp_auth(seqhi, seqhi_len); +- icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; diff --git a/queue-6.1/net-ipv6-stop-checking-crypto_ahash_alignmask.patch b/queue-6.1/net-ipv6-stop-checking-crypto_ahash_alignmask.patch new file mode 100644 index 0000000000..e935ba5c11 --- /dev/null +++ b/queue-6.1/net-ipv6-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246947-greg=kroah.com@vger.kernel.org Wed May 13 22:54:20 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:52:54 -0400 +Subject: net: ipv6: stop checking crypto_ahash_alignmask +To: stable@vger.kernel.org +Cc: Eric Biggers , Herbert Xu , Sasha Levin +Message-ID: <20260513165255.3822003-2-sashal@kernel.org> + +From: Eric Biggers + +[ Upstream commit 0a6bfaa0e695facb072f2fedfb55df37c4483b50 ] + +Now that the alignmask for ahash and shash algorithms is always 0, +crypto_ahash_alignmask() always returns 0 and will be removed. In +preparation for this, stop checking crypto_ahash_alignmask() in ah6.c. + +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ah6.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -79,9 +79,7 @@ static void *ah_alloc_tmp(struct crypto_ + { + unsigned int len; + +- len = size + crypto_ahash_digestsize(ahash) + +- (crypto_ahash_alignmask(ahash) & +- ~(crypto_tfm_ctx_alignment() - 1)); ++ len = size + crypto_ahash_digestsize(ahash); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + +@@ -103,10 +101,9 @@ static inline u8 *ah_tmp_auth(u8 *tmp, u + return tmp + offset; + } + +-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, +- unsigned int offset) ++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset) + { +- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); ++ return tmp + offset; + } + + static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, +@@ -327,7 +324,7 @@ static void ah6_output_done(struct crypt + + iph_base = AH_SKB_CB(skb)->tmp; + iph_ext = ah_tmp_ext(iph_base); +- icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen); ++ icv = ah_tmp_icv(iph_ext, extlen); + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); +@@ -384,7 +381,7 @@ static int ah6_output(struct xfrm_state + + iph_ext = ah_tmp_ext(iph_base); + seqhi = (__be32 *)((char *)iph_ext + extlen); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; +@@ -480,7 +477,7 @@ static void ah6_input_done(struct crypto + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, hdr_len); +- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) +@@ -588,7 +585,7 @@ static int ah6_input(struct xfrm_state * + + auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len); + seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; diff --git a/queue-6.1/net-stmmac-avoid-shadowing-global-buf_sz.patch b/queue-6.1/net-stmmac-avoid-shadowing-global-buf_sz.patch new file mode 100644 index 0000000000..f2aa364dae --- /dev/null +++ b/queue-6.1/net-stmmac-avoid-shadowing-global-buf_sz.patch @@ -0,0 +1,51 @@ +From stable+bounces-245040-greg=kroah.com@vger.kernel.org Sun May 10 21:16:41 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:46:30 -0400 +Subject: net: stmmac: avoid shadowing global buf_sz +To: stable@vger.kernel.org +Cc: "Russell King (Oracle)" , Furong Xu <0x1207@gmail.com>, Jakub Kicinski , Sasha Levin +Message-ID: <20260510154632.158995-1-sashal@kernel.org> + +From: "Russell King (Oracle)" + +[ Upstream commit 876cfb20e8892143c0c967b3657074f9131f9b5f ] + +stmmac_rx() declares a local variable named "buf_sz" but there is also +a global variable for a module parameter which is called the same. To +avoid confusion, rename the local variable. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Furong Xu <0x1207@gmail.com> +Link: https://patch.msgid.link/E1tpswi-005U6C-Py@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0bb05e6adfa9 ("net: stmmac: Prevent NULL deref when RX memory exhausted") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -5235,10 +5235,10 @@ static int stmmac_rx(struct stmmac_priv + struct stmmac_xdp_buff ctx; + unsigned long flags; + int xdp_status = 0; +- int buf_sz; ++ int bufsz; + + dma_dir = page_pool_get_dma_dir(rx_q->page_pool); +- buf_sz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; ++ bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; + limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit); + + if (netif_msg_rx_status(priv)) { +@@ -5353,7 +5353,7 @@ read_again: + dma_sync_single_for_cpu(priv->device, buf->addr, + buf1_len, dma_dir); + +- xdp_init_buff(&ctx.xdp, buf_sz, &rx_q->xdp_rxq); ++ xdp_init_buff(&ctx.xdp, bufsz, &rx_q->xdp_rxq); + xdp_prepare_buff(&ctx.xdp, page_address(buf->page), + buf->page_offset, buf1_len, false); + diff --git a/queue-6.1/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch b/queue-6.1/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch new file mode 100644 index 0000000000..21e64b3b87 --- /dev/null +++ b/queue-6.1/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch @@ -0,0 +1,120 @@ +From stable+bounces-245042-greg=kroah.com@vger.kernel.org Sun May 10 21:16:45 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:46:32 -0400 +Subject: net: stmmac: Prevent NULL deref when RX memory exhausted +To: stable@vger.kernel.org +Cc: Sam Edwards , Russell King , Sam Edwards , Paolo Abeni , Sasha Levin +Message-ID: <20260510154632.158995-3-sashal@kernel.org> + +From: Sam Edwards + +[ Upstream commit 0bb05e6adfa99a2ea1fee1125cc0953409f83ed8 ] + +The CPU receives frames from the MAC through conventional DMA: the CPU +allocates buffers for the MAC, then the MAC fills them and returns +ownership to the CPU. For each hardware RX queue, the CPU and MAC +coordinate through a shared ring array of DMA descriptors: one +descriptor per DMA buffer. Each descriptor includes the buffer's +physical address and a status flag ("OWN") indicating which side owns +the buffer: OWN=0 for CPU, OWN=1 for MAC. The CPU is only allowed to set +the flag and the MAC is only allowed to clear it, and both must move +through the ring in sequence: thus the ring is used for both +"submissions" and "completions." + +In the stmmac driver, stmmac_rx() bookmarks its position in the ring +with the `cur_rx` index. The main receive loop in that function checks +for rx_descs[cur_rx].own=0, gives the corresponding buffer to the +network stack (NULLing the pointer), and increments `cur_rx` modulo the +ring size. After the loop exits, stmmac_rx_refill(), which bookmarks its +position with `dirty_rx`, allocates fresh buffers and rearms the +descriptors (setting OWN=1). If it fails any allocation, it simply stops +early (leaving OWN=0) and will retry where it left off when next called. + +This means descriptors have a three-stage lifecycle (terms my own): +- `empty` (OWN=1, buffer valid) +- `full` (OWN=0, buffer valid and populated) +- `dirty` (OWN=0, buffer NULL) + +But because stmmac_rx() only checks OWN, it confuses `full`/`dirty`. In +the past (see 'Fixes:'), there was a bug where the loop could cycle +`cur_rx` all the way back to the first descriptor it dirtied, resulting +in a NULL dereference when mistaken for `full`. The aforementioned +commit resolved that *specific* failure by capping the loop's iteration +limit at `dma_rx_size - 1`, but this is only a partial fix: if the +previous stmmac_rx_refill() didn't complete, then there are leftover +`dirty` descriptors that the loop might encounter without needing to +cycle fully around. The current code therefore panics (see 'Closes:') +when stmmac_rx_refill() is memory-starved long enough for `cur_rx` to +catch up to `dirty_rx`. + +Fix this by explicitly checking, before advancing `cur_rx`, if the next +entry is dirty; exit the loop if so. This prevents processing of the +final, used descriptor until stmmac_rx_refill() succeeds, but +fully prevents the `cur_rx == dirty_rx` ambiguity as the previous bugfix +intended: so remove the clamp as well. Since stmmac_rx_zc() is a +copy-paste-and-tweak of stmmac_rx() and the code structure is identical, +any fix to stmmac_rx() will also need a corresponding fix for +stmmac_rx_zc(). Therefore, apply the same check there. + +In stmmac_rx() (not stmmac_rx_zc()), a related bug remains: after the +MAC sets OWN=0 on the final descriptor, it will be unable to send any +further DMA-complete IRQs until it's given more `empty` descriptors. +Currently, the driver simply *hopes* that the next stmmac_rx_refill() +succeeds, risking an indefinite stall of the receive process if not. But +this is not a regression, so it can be addressed in a future change. + +Fixes: b6cb4541853c7 ("net: stmmac: avoid rx queue overrun") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221010 +Cc: stable@vger.kernel.org +Suggested-by: Russell King +Signed-off-by: Sam Edwards +Link: https://patch.msgid.link/20260422044503.5349-1-CFSworks@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -5103,9 +5103,12 @@ read_again: + break; + + /* Prefetch the next RX descriptor */ +- rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, +- priv->dma_conf.dma_rx_size); +- next_entry = rx_q->cur_rx; ++ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, ++ priv->dma_conf.dma_rx_size); ++ if (unlikely(next_entry == rx_q->dirty_rx)) ++ break; ++ ++ rx_q->cur_rx = next_entry; + + if (priv->extend_desc) + np = (struct dma_desc *)(rx_q->dma_erx + next_entry); +@@ -5239,7 +5242,6 @@ static int stmmac_rx(struct stmmac_priv + + dma_dir = page_pool_get_dma_dir(rx_q->page_pool); + bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; +- limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit); + + if (netif_msg_rx_status(priv)) { + void *rx_head; +@@ -5295,9 +5297,12 @@ read_again: + if (unlikely(status & dma_own)) + break; + +- rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, +- priv->dma_conf.dma_rx_size); +- next_entry = rx_q->cur_rx; ++ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, ++ priv->dma_conf.dma_rx_size); ++ if (unlikely(next_entry == rx_q->dirty_rx)) ++ break; ++ ++ rx_q->cur_rx = next_entry; + + if (priv->extend_desc) + np = (struct dma_desc *)(rx_q->dma_erx + next_entry); diff --git a/queue-6.1/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch b/queue-6.1/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch new file mode 100644 index 0000000000..745398961c --- /dev/null +++ b/queue-6.1/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch @@ -0,0 +1,181 @@ +From stable+bounces-245041-greg=kroah.com@vger.kernel.org Sun May 10 21:16:42 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:46:31 -0400 +Subject: net: stmmac: rename STMMAC_GET_ENTRY() -> STMMAC_NEXT_ENTRY() +To: stable@vger.kernel.org +Cc: "Russell King (Oracle)" , Jakub Kicinski , Sasha Levin +Message-ID: <20260510154632.158995-2-sashal@kernel.org> + +From: "Russell King (Oracle)" + +[ Upstream commit 6b4286e0550814cdc4b897f881ec1fa8b0313227 ] + +STMMAC_GET_ENTRY() doesn't describe what this macro is doing - it is +incrementing the provided index for the circular array of descriptors. +Replace "GET" with "NEXT" as this better describes the action here. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1w2vba-0000000DbWo-1oL5@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0bb05e6adfa9 ("net: stmmac: Prevent NULL deref when RX memory exhausted") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 2 - + drivers/net/ethernet/stmicro/stmmac/common.h | 2 - + drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 2 - + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 26 +++++++++++----------- + 4 files changed, 16 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c +@@ -47,7 +47,7 @@ static int jumbo_frm(struct stmmac_tx_qu + + while (len != 0) { + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + desc = tx_q->dma_tx + entry; + + if (len > bmax) { +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -53,7 +53,7 @@ + #define DMA_MIN_RX_SIZE 64 + #define DMA_MAX_RX_SIZE 1024 + #define DMA_DEFAULT_RX_SIZE 512 +-#define STMMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1)) ++#define STMMAC_NEXT_ENTRY(x, size) ((x + 1) & (size - 1)) + + #undef FRAME_FILTER_DEBUG + /* #define FRAME_FILTER_DEBUG */ +--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +@@ -51,7 +51,7 @@ static int jumbo_frm(struct stmmac_tx_qu + stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, + STMMAC_RING_MODE, 0, false, skb->len); + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + + if (priv->extend_desc) + desc = (struct dma_desc *)(tx_q->dma_etx + entry); +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct st + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + entry = tx_q->cur_tx; + } + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +@@ -2660,7 +2660,7 @@ static int stmmac_tx_clean(struct stmmac + + stmmac_release_tx_desc(priv, p, priv->mode); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + } + tx_q->dirty_tx = entry; + +@@ -3976,7 +3976,7 @@ static bool stmmac_vlan_insert(struct st + return false; + + stmmac_set_tx_owner(priv, p); +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + return true; + } + +@@ -4004,7 +4004,7 @@ static void stmmac_tso_allocator(struct + while (tmp_len > 0) { + dma_addr_t curr_addr; + +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, + priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + +@@ -4137,7 +4137,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + + stmmac_set_mss(priv, mss_desc, mss); + tx_q->mss = mss; +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, + priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + } +@@ -4262,7 +4262,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + + if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) { + netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n", +@@ -4420,7 +4420,7 @@ static netdev_tx_t stmmac_xmit(struct sk + int len = skb_frag_size(frag); + bool last_segment = (i == (nfrags - 1)); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[entry]); + + if (likely(priv->extend_desc)) +@@ -4490,7 +4490,7 @@ static netdev_tx_t stmmac_xmit(struct sk + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + if (netif_msg_pktdata(priv)) { +@@ -4660,7 +4660,7 @@ static inline void stmmac_rx_refill(stru + dma_wmb(); + stmmac_set_rx_owner(priv, p, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + rx_q->dirty_rx = entry; + rx_q->rx_tail_addr = rx_q->dma_rx_phy + +@@ -4787,7 +4787,7 @@ static int stmmac_xdp_xmit_xdpf(struct s + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + return STMMAC_XDP_TX; +@@ -5018,7 +5018,7 @@ static bool stmmac_rx_refill_zc(struct s + dma_wmb(); + stmmac_set_rx_owner(priv, rx_desc, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + + if (rx_desc) { +@@ -5103,7 +5103,7 @@ read_again: + break; + + /* Prefetch the next RX descriptor */ +- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, ++ rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, + priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + +@@ -5295,7 +5295,7 @@ read_again: + if (unlikely(status & dma_own)) + break; + +- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, ++ rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, + priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + diff --git a/queue-6.1/net-wwan-t7xx-validate-port_count-against-message-length-in-t7xx_port_enum_msg_handler.patch b/queue-6.1/net-wwan-t7xx-validate-port_count-against-message-length-in-t7xx_port_enum_msg_handler.patch new file mode 100644 index 0000000000..d521566e0b --- /dev/null +++ b/queue-6.1/net-wwan-t7xx-validate-port_count-against-message-length-in-t7xx_port_enum_msg_handler.patch @@ -0,0 +1,141 @@ +From stable+bounces-247262-greg=kroah.com@vger.kernel.org Thu May 14 23:28:20 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 13:58:13 -0400 +Subject: net: wwan: t7xx: validate port_count against message length in t7xx_port_enum_msg_handler +To: stable@vger.kernel.org +Cc: Pavitra Jha , Jakub Kicinski , Sasha Levin +Message-ID: <20260514175813.518419-1-sashal@kernel.org> + +From: Pavitra Jha + +[ Upstream commit 0e7c074cfcd9bd93765505f9eb8b42f03ed2a744 ] + +t7xx_port_enum_msg_handler() uses the modem-supplied port_count field as +a loop bound over port_msg->data[] without checking that the message buffer +contains sufficient data. A modem sending port_count=65535 in a 12-byte +buffer triggers a slab-out-of-bounds read of up to 262140 bytes. + +Add a sizeof(*port_msg) check before accessing the port message header +fields to guard against undersized messages. + +Add a struct_size() check after extracting port_count and before the loop. + +In t7xx_parse_host_rt_data(), guard the rt_feature header read with a +remaining-buffer check before accessing data_len, validate feat_data_len +against the actual remaining buffer to prevent OOB reads and signed +integer overflow on offset. + +Pass msg_len from both call sites: skb->len at the DPMAIF path after +skb_pull(), and the validated feat_data_len at the handshake path. + +Fixes: da45d2566a1d ("net: wwan: t7xx: Add control port") +Cc: stable@vger.kernel.org +Signed-off-by: Pavitra Jha +Link: https://patch.msgid.link/20260501110713.145563-1-jhapavitra98@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wwan/t7xx/t7xx_modem_ops.c | 17 +++++++++++++++-- + drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c | 18 ++++++++++++++++-- + drivers/net/wwan/t7xx/t7xx_port_proxy.h | 2 +- + 3 files changed, 32 insertions(+), 5 deletions(-) + +--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c ++++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c +@@ -415,8 +415,20 @@ static int t7xx_parse_host_rt_data(struc + + offset = sizeof(struct feature_query); + for (i = 0; i < FEATURE_COUNT && offset < data_length; i++) { ++ size_t remaining = data_length - offset; ++ size_t feat_data_len, feat_total; ++ ++ if (remaining < sizeof(*rt_feature)) ++ break; ++ + rt_feature = data + offset; +- offset += sizeof(*rt_feature) + le32_to_cpu(rt_feature->data_len); ++ feat_data_len = le32_to_cpu(rt_feature->data_len); ++ ++ if (feat_data_len > remaining - sizeof(*rt_feature)) ++ break; ++ ++ feat_total = sizeof(*rt_feature) + feat_data_len; ++ offset += feat_total; + + ft_spt_cfg = FIELD_GET(FEATURE_MSK, core->feature_set[i]); + if (ft_spt_cfg != MTK_FEATURE_MUST_BE_SUPPORTED) +@@ -427,7 +439,8 @@ static int t7xx_parse_host_rt_data(struc + return -EINVAL; + + if (i == RT_ID_MD_PORT_ENUM) +- t7xx_port_enum_msg_handler(ctl->md, rt_feature->data); ++ t7xx_port_enum_msg_handler(ctl->md, rt_feature->data, ++ feat_data_len); + } + + return 0; +--- a/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c ++++ b/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c +@@ -117,6 +117,7 @@ static int fsm_ee_message_handler(struct + * t7xx_port_enum_msg_handler() - Parse the port enumeration message to create/remove nodes. + * @md: Modem context. + * @msg: Message. ++ * @msg_len: Length of @msg in bytes. + * + * Used to control create/remove device node. + * +@@ -124,12 +125,18 @@ static int fsm_ee_message_handler(struct + * * 0 - Success. + * * -EFAULT - Message check failure. + */ +-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg) ++int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len) + { + struct device *dev = &md->t7xx_dev->pdev->dev; + unsigned int version, port_count, i; + struct port_msg *port_msg = msg; + ++ if (msg_len < sizeof(*port_msg)) { ++ dev_err(dev, "Port enum msg too short for header: need %zu, have %zu\n", ++ sizeof(*port_msg), msg_len); ++ return -EINVAL; ++ } ++ + version = FIELD_GET(PORT_MSG_VERSION, le32_to_cpu(port_msg->info)); + if (version != PORT_ENUM_VER || + le32_to_cpu(port_msg->head_pattern) != PORT_ENUM_HEAD_PATTERN || +@@ -141,6 +148,13 @@ int t7xx_port_enum_msg_handler(struct t7 + } + + port_count = FIELD_GET(PORT_MSG_PRT_CNT, le32_to_cpu(port_msg->info)); ++ ++ if (msg_len < struct_size(port_msg, data, port_count)) { ++ dev_err(dev, "Port enum msg too short: need %zu, have %zu\n", ++ struct_size(port_msg, data, port_count), msg_len); ++ return -EINVAL; ++ } ++ + for (i = 0; i < port_count; i++) { + u32 port_info = le32_to_cpu(port_msg->data[i]); + unsigned int ch_id; +@@ -187,7 +201,7 @@ static int control_msg_handler(struct t7 + + case CTL_ID_PORT_ENUM: + skb_pull(skb, sizeof(*ctrl_msg_h)); +- ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data); ++ ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data, skb->len); + if (!ret) + ret = port_ctl_send_msg_to_md(port, CTL_ID_PORT_ENUM, 0); + else +--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h ++++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h +@@ -91,7 +91,7 @@ void t7xx_port_proxy_reset(struct port_p + void t7xx_port_proxy_uninit(struct port_proxy *port_prox); + int t7xx_port_proxy_init(struct t7xx_modem *md); + void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state); +-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg); ++int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len); + int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id, + bool en_flag); + diff --git a/queue-6.1/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch b/queue-6.1/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch new file mode 100644 index 0000000000..0fb95a349c --- /dev/null +++ b/queue-6.1/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch @@ -0,0 +1,86 @@ +From stable+bounces-263390-greg=kroah.com@vger.kernel.org Mon Jun 15 21:57:56 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 12:17:29 -0400 +Subject: netfilter: nft_fib: fix stale stack leak via the OIFNAME register +To: stable@vger.kernel.org +Cc: Davide Ornaghi , Florian Westphal , Pablo Neira Ayuso , Sasha Levin +Message-ID: <20260615161729.2239291-1-sashal@kernel.org> + +From: Davide Ornaghi + +[ Upstream commit ab185e0c4fb82dfba6fb86f8271e06f931d9c64c ] + +For NFT_FIB_RESULT_OIFNAME the destination register is declared with +len = IFNAMSIZ (four 32-bit registers), but on the lookup-fail, +RTN_LOCAL and oif-mismatch paths nft_fib{4,6}_eval() only writes one +register via "*dest = 0". The remaining three registers are left as +whatever was on the stack in nft_do_chain()'s struct nft_regs, and a +downstream expression that loads the register span can leak that +uninitialised kernel stack to userspace. + +The NFTA_FIB_F_PRESENT existence check has the same shape: it is only +meaningful for NFT_FIB_RESULT_OIF, yet it was accepted for any result type +while the eval stores a single byte via nft_reg_store8(), leaving the rest +of the declared span stale. + +Fix both: + + - replace the bare "*dest = 0" in the eval with nft_fib_store_result(), + which strscpy_pad()s the whole IFNAMSIZ for OIFNAME (and is already + used on the other early-return path), and + + - restrict NFTA_FIB_F_PRESENT to NFT_FIB_RESULT_OIF and declare its + destination as a single u8, so the marked span matches the one byte + the eval writes. + +Fixes: f6d0cbcf09c5 ("netfilter: nf_tables: add fib expression") +Suggested-by: Florian Westphal +Cc: stable@vger.kernel.org +Signed-off-by: Davide Ornaghi +Signed-off-by: Pablo Neira Ayuso +[ kept the tree's existing `ip6_route_lookup`/`rt6_info` machinery (missing `fib6_lookup` refactor) and changed only `*dest = 0;` to `nft_fib_store_result(dest, priv, NULL)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/netfilter/nft_fib_ipv4.c | 2 +- + net/ipv6/netfilter/nft_fib_ipv6.c | 2 +- + net/netfilter/nft_fib.c | 6 ++++++ + 3 files changed, 8 insertions(+), 2 deletions(-) + +--- a/net/ipv4/netfilter/nft_fib_ipv4.c ++++ b/net/ipv4/netfilter/nft_fib_ipv4.c +@@ -122,7 +122,7 @@ void nft_fib4_eval(const struct nft_expr + fl4.saddr = get_saddr(iph->daddr); + } + +- *dest = 0; ++ nft_fib_store_result(dest, priv, NULL); + + if (fib_lookup(nft_net(pkt), &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE)) + return; +--- a/net/ipv6/netfilter/nft_fib_ipv6.c ++++ b/net/ipv6/netfilter/nft_fib_ipv6.c +@@ -193,7 +193,7 @@ void nft_fib6_eval(const struct nft_expr + } + } + +- *dest = 0; ++ nft_fib_store_result(dest, priv, NULL); + rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb, + lookup_flags); + if (rt->dst.error) +--- a/net/netfilter/nft_fib.c ++++ b/net/netfilter/nft_fib.c +@@ -107,6 +107,12 @@ int nft_fib_init(const struct nft_ctx *c + return -EINVAL; + } + ++ if (priv->flags & NFTA_FIB_F_PRESENT) { ++ if (priv->result != NFT_FIB_RESULT_OIF) ++ return -EINVAL; ++ len = sizeof(u8); ++ } ++ + err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg, + NULL, NFT_DATA_VALUE, len); + if (err < 0) diff --git a/queue-6.1/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch b/queue-6.1/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch new file mode 100644 index 0000000000..afaa7c2a3c --- /dev/null +++ b/queue-6.1/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch @@ -0,0 +1,57 @@ +From sashal@kernel.org Sat May 30 20:07:43 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 10:37:38 -0400 +Subject: octeontx2-af: CGX: add bounds check to cgx_speed_mbps index +To: stable@vger.kernel.org +Cc: Sam Daly , Sunil Goutham , Linu Cherian , Geetha sowjanya , hariprasad , Subbaraya Sundeep , Andrew Lunn , stable , Greg Kroah-Hartman , Jakub Kicinski , Sasha Levin +Message-ID: <20260530143738.2474980-2-sashal@kernel.org> + +From: Sam Daly + +[ Upstream commit c0bf0a4f3f1f5f57aa83e1400ba4f56f0abfd542 ] + +cgx_speed_mbps has 13 elements but RESP_LINKSTAT_SPEED can yield values +0-15. If it returns a value >= 13, this causes an out-of-bounds array +access. Add a bounds check and default to speed 0 if the index is out of +range. + +Fixes: 61071a871ea6 ("octeontx2-af: Forward CGX link notifications to PFs") +Cc: Sunil Goutham +Cc: Linu Cherian +Cc: Geetha sowjanya +Cc: hariprasad +Cc: Subbaraya Sundeep +Cc: Andrew Lunn +Cc: stable +Signed-off-by: Sam Daly +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026051352-refined-demise-e88d@gregkh +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -1228,13 +1228,18 @@ static inline void link_status_user_form + struct cgx_link_user_info *linfo, + struct cgx *cgx, u8 lmac_id) + { ++ unsigned int speed; ++ + linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); + linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); +- linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)]; + linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat); + linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat); + linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id); + ++ speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat); ++ linfo->speed = speed < ARRAY_SIZE(cgx_speed_mbps) ? ++ cgx_speed_mbps[speed] : 0; ++ + if (linfo->lmac_type_id >= LMAC_MODE_MAX) { + dev_err(&cgx->pdev->dev, "Unknown lmac_type_id %d reported by firmware on cgx port%d:%d", + linfo->lmac_type_id, cgx->cgx_id, lmac_id); diff --git a/queue-6.1/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch b/queue-6.1/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch new file mode 100644 index 0000000000..b09dca9f28 --- /dev/null +++ b/queue-6.1/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch @@ -0,0 +1,68 @@ +From stable+bounces-256913-greg=kroah.com@vger.kernel.org Sat May 30 20:11:54 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 10:37:37 -0400 +Subject: octeontx2-af: replace deprecated strncpy with strscpy +To: stable@vger.kernel.org +Cc: Justin Stitt , Kees Cook , Jakub Kicinski , Sasha Levin +Message-ID: <20260530143738.2474980-1-sashal@kernel.org> + +From: Justin Stitt + +[ Upstream commit 473f8f2d1bfe1103f20140fdc80cad406b4d68c0 ] + +`strncpy` is deprecated for use on NUL-terminated destination strings +[1] and as such we should prefer more robust and less ambiguous string +interfaces. + +We can see that linfo->lmac_type is expected to be NUL-terminated based +on the `... - 1`'s present in the current code. Presumably making room +for a NUL-byte at the end of the buffer. + +Considering the above, a suitable replacement is `strscpy` [2] due to +the fact that it guarantees NUL-termination on the destination buffer +without unnecessarily NUL-padding. + +Let's also prefer the more idiomatic strscpy usage of (dest, src, +sizeof(dest)) rather than (dest, src, SOME_LEN). + +Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] +Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] +Link: https://github.com/KSPP/linux/issues/90 +Signed-off-by: Justin Stitt +Reviewed-by: Kees Cook +Link: https://lore.kernel.org/r/20231010-strncpy-drivers-net-ethernet-marvell-octeontx2-af-cgx-c-v1-1-a443e18f9de8@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c0bf0a4f3f1f ("octeontx2-af: CGX: add bounds check to cgx_speed_mbps index") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -1228,8 +1228,6 @@ static inline void link_status_user_form + struct cgx_link_user_info *linfo, + struct cgx *cgx, u8 lmac_id) + { +- const char *lmac_string; +- + linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); + linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); + linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)]; +@@ -1240,12 +1238,12 @@ static inline void link_status_user_form + if (linfo->lmac_type_id >= LMAC_MODE_MAX) { + dev_err(&cgx->pdev->dev, "Unknown lmac_type_id %d reported by firmware on cgx port%d:%d", + linfo->lmac_type_id, cgx->cgx_id, lmac_id); +- strncpy(linfo->lmac_type, "Unknown", LMACTYPE_STR_LEN - 1); ++ strscpy(linfo->lmac_type, "Unknown", sizeof(linfo->lmac_type)); + return; + } + +- lmac_string = cgx_lmactype_string[linfo->lmac_type_id]; +- strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1); ++ strscpy(linfo->lmac_type, cgx_lmactype_string[linfo->lmac_type_id], ++ sizeof(linfo->lmac_type)); + } + + /* Hardware event handlers */ diff --git a/queue-6.1/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch b/queue-6.1/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch new file mode 100644 index 0000000000..9752161dd1 --- /dev/null +++ b/queue-6.1/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch @@ -0,0 +1,62 @@ +From stable+bounces-259294-greg=kroah.com@vger.kernel.org Sun May 31 01:37:49 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 16:07:07 -0400 +Subject: octeontx2-pf: avoid double free of pool->stack on AQ init failure +To: stable@vger.kernel.org +Cc: Dawei Feng , Zilin Guan , Simon Horman , Jakub Kicinski , Sasha Levin +Message-ID: <20260530200707.3281847-1-sashal@kernel.org> + +From: Dawei Feng + +[ Upstream commit 9b244c242bec48b37e82b89787afd6a4c43457e1 ] + +otx2_pool_aq_init() frees pool->stack when mailbox sync or retry +allocation fails, but leaves the pointer unchanged. Later, +otx2_sq_aura_pool_init() unwinds the partial setup through +otx2_aura_pool_free(), which frees pool->stack again. The CN20K-specific +cn20k_pool_aq_init() implementation has the same bug in +its corresponding error path. + +Set pool->stack to NULL immediately after the local free so the shared +cleanup path does not free the same stack again while cleaning up +partially initialized pool state. + +The bug was first flagged by an experimental analysis tool we are +developing for kernel memory-management bugs while analyzing +v6.13-rc1. The tool is still under development and is not yet publicly +available. Manual inspection confirms that the bug is still present in +v7.1-rc3. + +Runtime validation was not performed because reproducing this path +requires OcteonTX2/CN20K hardware. + +Fixes: caa2da34fd25 ("octeontx2-pf: Initialize and config queues") +Fixes: d322fbd17203 ("octeontx2-pf: Initialize cn20k specific aura and pool contexts") +Cc: stable@vger.kernel.org +Signed-off-by: Zilin Guan +Signed-off-by: Dawei Feng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260515151826.1005397-1-dawei.feng@seu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -1374,11 +1374,13 @@ int otx2_pool_init(struct otx2_nic *pfvf + err = otx2_sync_mbox_msg(&pfvf->mbox); + if (err) { + qmem_free(pfvf->dev, pool->stack); ++ pool->stack = NULL; + return err; + } + aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox); + if (!aq) { + qmem_free(pfvf->dev, pool->stack); ++ pool->stack = NULL; + return -ENOMEM; + } + } diff --git a/queue-6.1/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch b/queue-6.1/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch new file mode 100644 index 0000000000..bf7b0018a2 --- /dev/null +++ b/queue-6.1/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch @@ -0,0 +1,51 @@ +From sashal@kernel.org Mon Jun 1 16:21:07 2026 +From: Sasha Levin +Date: Mon, 1 Jun 2026 06:51:02 -0400 +Subject: phy: tegra: xusb: Disable trk clk when not in use +To: stable@vger.kernel.org +Cc: Wayne Chang , Jon Hunter , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260601105103.376449-1-sashal@kernel.org> + +From: Wayne Chang + +[ Upstream commit 71d9e899584e11bbd7eaf9934a619c69a15060d8 ] + +Pad tracking is a one-time calibration for Tegra186 and Tegra194. +Clk should be disabled after calibration. + +Disable clk after calibration. +While at it add 100us delay for HW recording the calibration value. + +Signed-off-by: Wayne Chang +Signed-off-by: Jon Hunter +Link: https://lore.kernel.org/r/20230111110450.24617-5-jonathanh@nvidia.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: da110228b54f ("phy: tegra: xusb: Fix per-pad high-speed termination calibration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/tegra/xusb-tegra186.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/phy/tegra/xusb-tegra186.c ++++ b/drivers/phy/tegra/xusb-tegra186.c +@@ -612,6 +612,10 @@ static void tegra186_utmi_bias_pad_power + value &= ~USB2_PD_TRK; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + ++ udelay(100); ++ ++ clk_disable_unprepare(priv->usb2_trk_clk); ++ + mutex_unlock(&padctl->lock); + } + +@@ -636,8 +640,6 @@ static void tegra186_utmi_bias_pad_power + value |= USB2_PD_TRK; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + +- clk_disable_unprepare(priv->usb2_trk_clk); +- + mutex_unlock(&padctl->lock); + } + diff --git a/queue-6.1/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch b/queue-6.1/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch new file mode 100644 index 0000000000..a8b7c157f0 --- /dev/null +++ b/queue-6.1/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch @@ -0,0 +1,144 @@ +From stable+bounces-259519-greg=kroah.com@vger.kernel.org Mon Jun 1 16:28:14 2026 +From: Sasha Levin +Date: Mon, 1 Jun 2026 06:51:03 -0400 +Subject: phy: tegra: xusb: Fix per-pad high-speed termination calibration +To: stable@vger.kernel.org +Cc: Wayne Chang , Wei-Cheng Chen , Jon Hunter , Vinod Koul , Sasha Levin +Message-ID: <20260601105103.376449-2-sashal@kernel.org> + +From: Wayne Chang + +[ Upstream commit da110228b54f2e2143d97ea7151e0dc22e539d67 ] + +The existing code reads a single hs_term_range_adj value from bit field +[10:7] of FUSE_SKU_CALIB_0 and applies it to all USB2 pads uniformly. +However, on SoCs that support per-pad termination, each pad has its own +hs_term_range_adj field: pad 0 in FUSE_SKU_CALIB_0[10:7], and pads 1-3 +in FUSE_USB_CALIB_EXT_0 at bit offsets [8:5], [12:9], and [16:13] +respectively. + +Fix the calibration by reading per-pad values from the appropriate fuse +registers. For SoCs that do not support per-pad termination, replicate +pad 0's value to all pads to maintain existing behavior. + +Add a has_per_pad_term flag to the SoC data to indicate whether per-pad +termination values are available in FUSE_USB_CALIB_EXT_0. + +Fixes: 1ef535c6ba8e ("phy: tegra: xusb: Add Tegra194 support") +Cc: stable@vger.kernel.org +Signed-off-by: Wayne Chang +Signed-off-by: Wei-Cheng Chen +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/phy/tegra/xusb-tegra186.c | 32 +++++++++++++++++++++++++------- + drivers/phy/tegra/xusb.h | 1 + + 2 files changed, 26 insertions(+), 7 deletions(-) + +--- a/drivers/phy/tegra/xusb-tegra186.c ++++ b/drivers/phy/tegra/xusb-tegra186.c +@@ -20,8 +20,8 @@ + /* FUSE USB_CALIB registers */ + #define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0) + #define HS_CURR_LEVEL_PAD_MASK 0x3f +-#define HS_TERM_RANGE_ADJ_SHIFT 7 +-#define HS_TERM_RANGE_ADJ_MASK 0xf ++#define HS_TERM_RANGE_ADJ_PADX_SHIFT(x) ((x) ? (5 + (x - 1) * 4) : 7) ++#define HS_TERM_RANGE_ADJ_PAD_MASK 0xf + #define HS_SQUELCH_SHIFT 29 + #define HS_SQUELCH_MASK 0x7 + +@@ -238,7 +238,7 @@ + struct tegra_xusb_fuse_calibration { + u32 *hs_curr_level; + u32 hs_squelch; +- u32 hs_term_range_adj; ++ u32 *hs_term_range_adj; + u32 rpd_ctrl; + }; + +@@ -868,7 +868,7 @@ static int tegra186_utmi_phy_power_on(st + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value &= ~TERM_RANGE_ADJ(~0); +- value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj); ++ value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj[index]); + value &= ~RPD_CTRL(~0); + value |= RPD_CTRL(priv->calib.rpd_ctrl); + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); +@@ -1403,17 +1403,23 @@ static const char * const tegra186_usb3_ + static int + tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) + { ++ const struct tegra_xusb_padctl_soc *soc = padctl->base.soc; + struct device *dev = padctl->base.dev; + unsigned int i, count; + u32 value, *level; ++ u32 *hs_term_range_adj; + int err; + +- count = padctl->base.soc->ports.usb2.count; ++ count = soc->ports.usb2.count; + + level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); + if (!level) + return -ENOMEM; + ++ hs_term_range_adj = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); ++ if (!hs_term_range_adj) ++ return -ENOMEM; ++ + err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); + if (err) + return dev_err_probe(dev, err, +@@ -1429,8 +1435,8 @@ tegra186_xusb_read_fuse_calibration(stru + + padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) & + HS_SQUELCH_MASK; +- padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) & +- HS_TERM_RANGE_ADJ_MASK; ++ hs_term_range_adj[0] = (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(0)) & ++ HS_TERM_RANGE_ADJ_PAD_MASK; + + err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); + if (err) { +@@ -1442,6 +1448,17 @@ tegra186_xusb_read_fuse_calibration(stru + + padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK; + ++ for (i = 1; i < count; i++) { ++ if (soc->has_per_pad_term) ++ hs_term_range_adj[i] = ++ (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(i)) & ++ HS_TERM_RANGE_ADJ_PAD_MASK; ++ else ++ hs_term_range_adj[i] = hs_term_range_adj[0]; ++ } ++ ++ padctl->calib.hs_term_range_adj = hs_term_range_adj; ++ + return 0; + } + +@@ -1645,6 +1662,7 @@ const struct tegra_xusb_padctl_soc tegra + .supply_names = tegra194_xusb_padctl_supply_names, + .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names), + .supports_gen2 = true, ++ .has_per_pad_term = true, + }; + EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc); + #endif +--- a/drivers/phy/tegra/xusb.h ++++ b/drivers/phy/tegra/xusb.h +@@ -433,6 +433,7 @@ struct tegra_xusb_padctl_soc { + unsigned int num_supplies; + bool supports_gen2; + bool need_fake_usb3_port; ++ bool has_per_pad_term; + }; + + struct tegra_xusb_padctl { diff --git a/queue-6.1/platform-x86-intel-vsec-add-private-data-for-per-device-data.patch b/queue-6.1/platform-x86-intel-vsec-add-private-data-for-per-device-data.patch new file mode 100644 index 0000000000..6a77727fa8 --- /dev/null +++ b/queue-6.1/platform-x86-intel-vsec-add-private-data-for-per-device-data.patch @@ -0,0 +1,63 @@ +From stable+bounces-257325-greg=kroah.com@vger.kernel.org Sat May 30 22:34:15 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 13:03:28 -0400 +Subject: platform/x86/intel/vsec: Add private data for per-device data +To: stable@vger.kernel.org +Cc: "David E. Box" , "Ilpo Järvinen" , "Sasha Levin" +Message-ID: <20260530170331.3037528-1-sashal@kernel.org> + +From: "David E. Box" + +[ Upstream commit dc957ab6aa05c118c3da0542428a4d6602aa2d2d ] + +Introduce a new private structure, struct vsec_priv, to hold a pointer to +the platform-specific information. Although the driver didn’t previously +require this per-device data, adding it now lays the groundwork for +upcoming patches that will manage such data. No functional changes. + +Signed-off-by: David E. Box +Link: https://lore.kernel.org/r/20250703022832.1302928-3-david.e.box@linux.intel.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 348ccc754d89 ("platform/x86/intel/vsec: Fix enable_cnt imbalance on PCIe error recovery") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/vsec.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/platform/x86/intel/vsec.c ++++ b/drivers/platform/x86/intel/vsec.c +@@ -73,6 +73,10 @@ static enum intel_vsec_id intel_vsec_all + VSEC_ID_SDSI, + }; + ++struct vsec_priv { ++ struct intel_vsec_platform_info *info; ++}; ++ + static const char *intel_vsec_name(enum intel_vsec_id id) + { + switch (id) { +@@ -375,6 +379,7 @@ static bool intel_vsec_walk_vsec(struct + static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + struct intel_vsec_platform_info *info; ++ struct vsec_priv *priv; + bool have_devices = false; + int ret; + +@@ -387,6 +392,13 @@ static int intel_vsec_pci_probe(struct p + if (!info) + return -EINVAL; + ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->info = info; ++ pci_set_drvdata(pdev, priv); ++ + if (intel_vsec_walk_dvsec(pdev, info)) + have_devices = true; + diff --git a/queue-6.1/platform-x86-intel-vsec-create-wrapper-to-walk-pci-config-space.patch b/queue-6.1/platform-x86-intel-vsec-create-wrapper-to-walk-pci-config-space.patch new file mode 100644 index 0000000000..781c2f2c22 --- /dev/null +++ b/queue-6.1/platform-x86-intel-vsec-create-wrapper-to-walk-pci-config-space.patch @@ -0,0 +1,87 @@ +From stable+bounces-257327-greg=kroah.com@vger.kernel.org Sat May 30 22:38:32 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 13:03:29 -0400 +Subject: platform/x86/intel/vsec: Create wrapper to walk PCI config space +To: stable@vger.kernel.org +Cc: "David E. Box" , "Ilpo Järvinen" , "Sasha Levin" +Message-ID: <20260530170331.3037528-2-sashal@kernel.org> + +From: "David E. Box" + +[ Upstream commit b0631f8a5740c55b52d02174cc4c9c84cc7a16a1 ] + +Combine three PCI config space walkers — intel_vsec_walk_dvsec(), +intel_vsec_walk_vsec(), and intel_vsec_walk_header() — into a new wrapper +function, intel_vsec_feature_walk(). This refactoring simplifies the probe +logic and lays the groundwork for future patches that will loop over these +calls. No functional changes. + +Signed-off-by: David E. Box +Link: https://lore.kernel.org/r/20250703022832.1302928-4-david.e.box@linux.intel.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 348ccc754d89 ("platform/x86/intel/vsec: Fix enable_cnt imbalance on PCIe error recovery") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/vsec.c | 38 ++++++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 12 deletions(-) + +--- a/drivers/platform/x86/intel/vsec.c ++++ b/drivers/platform/x86/intel/vsec.c +@@ -376,11 +376,35 @@ static bool intel_vsec_walk_vsec(struct + return have_devices; + } + ++static bool intel_vsec_get_features(struct pci_dev *pdev, ++ struct intel_vsec_platform_info *info) ++{ ++ bool found = false; ++ ++ /* ++ * Both DVSEC and VSEC capabilities can exist on the same device, ++ * so both intel_vsec_walk_dvsec() and intel_vsec_walk_vsec() must be ++ * called independently. Additionally, intel_vsec_walk_header() is ++ * needed for devices that do not have VSEC/DVSEC but provide the ++ * information via device_data. ++ */ ++ if (intel_vsec_walk_dvsec(pdev, info)) ++ found = true; ++ ++ if (intel_vsec_walk_vsec(pdev, info)) ++ found = true; ++ ++ if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && ++ intel_vsec_walk_header(pdev, info)) ++ found = true; ++ ++ return found; ++} ++ + static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + struct intel_vsec_platform_info *info; + struct vsec_priv *priv; +- bool have_devices = false; + int ret; + + ret = pcim_enable_device(pdev); +@@ -399,17 +423,7 @@ static int intel_vsec_pci_probe(struct p + priv->info = info; + pci_set_drvdata(pdev, priv); + +- if (intel_vsec_walk_dvsec(pdev, info)) +- have_devices = true; +- +- if (intel_vsec_walk_vsec(pdev, info)) +- have_devices = true; +- +- if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && +- intel_vsec_walk_header(pdev, info)) +- have_devices = true; +- +- if (!have_devices) ++ if (!intel_vsec_get_features(pdev, info)) + return -ENODEV; + + return 0; diff --git a/queue-6.1/platform-x86-intel-vsec-fix-enable_cnt-imbalance-on-pcie-error-recovery.patch b/queue-6.1/platform-x86-intel-vsec-fix-enable_cnt-imbalance-on-pcie-error-recovery.patch new file mode 100644 index 0000000000..7313c7ced6 --- /dev/null +++ b/queue-6.1/platform-x86-intel-vsec-fix-enable_cnt-imbalance-on-pcie-error-recovery.patch @@ -0,0 +1,95 @@ +From stable+bounces-257329-greg=kroah.com@vger.kernel.org Sat May 30 22:43:22 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 13:03:31 -0400 +Subject: platform/x86/intel/vsec: Fix enable_cnt imbalance on PCIe error recovery +To: stable@vger.kernel.org +Cc: "Lukas Wunner" , "Ilpo Järvinen" , "Sasha Levin" +Message-ID: <20260530170331.3037528-4-sashal@kernel.org> + +From: Lukas Wunner + +[ Upstream commit 348ccc754d8939e21ca5956ff45720b81d6e407f ] + +After a PCIe Uncorrectable Error has been reported by a device with +Intel Vendor Specific Extended Capabilities and has been recovered +through a Secondary Bus Reset, its driver calls intel_vsec_pci_probe() +to rescan and reinitialize VSECs. + +intel_vsec_pci_probe() invokes pcim_enable_device() and thereby adds +another devm action which calls pcim_disable_device() on driver unbind. + +So once the driver unbinds, pcim_disable_device() will be called as many +times as an Uncorrectable Error occurred, plus one. This will lead to +an enable_cnt imbalance on driver unbind. + +Additionally, since commit dc957ab6aa05 ("platform/x86/intel/vsec: Add +private data for per-device data"), a devm_kzalloc() allocation is +leaked on every Uncorrectable Error. + +Avoid by splitting the VSEC rescan out of intel_vsec_pci_probe() into a +separate helper and calling that on PCIe error recovery. + +Fixes: 936874b77dd0 ("platform/x86/intel/vsec: Add PCI error recovery support to Intel PMT") +Signed-off-by: Lukas Wunner +Cc: stable@vger.kernel.org # v6.0+ +Link: https://patch.msgid.link/bd594d09fa866dc51dddc9a447c3b23f9b1402cc.1778736835.git.lukas@wunner.de +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/vsec.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +--- a/drivers/platform/x86/intel/vsec.c ++++ b/drivers/platform/x86/intel/vsec.c +@@ -401,6 +401,17 @@ static bool intel_vsec_get_features(stru + return found; + } + ++static int intel_vsec_pci_init(struct pci_dev *pdev) ++{ ++ struct vsec_priv *priv = pci_get_drvdata(pdev); ++ const struct intel_vsec_platform_info *info = priv->info; ++ ++ if (!intel_vsec_get_features(pdev, info)) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + const struct intel_vsec_platform_info *info; +@@ -423,10 +434,7 @@ static int intel_vsec_pci_probe(struct p + priv->info = info; + pci_set_drvdata(pdev, priv); + +- if (!intel_vsec_get_features(pdev, info)) +- return -ENODEV; +- +- return 0; ++ return intel_vsec_pci_init(pdev); + } + + /* TGL info */ +@@ -489,7 +497,6 @@ static pci_ers_result_t intel_vsec_pci_s + { + struct intel_vsec_device *intel_vsec_dev; + pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT; +- const struct pci_device_id *pci_dev_id; + unsigned long index; + + dev_info(&pdev->dev, "Resetting PCI slot\n"); +@@ -510,10 +517,8 @@ static pci_ers_result_t intel_vsec_pci_s + devm_release_action(&pdev->dev, intel_vsec_remove_aux, + &intel_vsec_dev->auxdev); + } +- pci_disable_device(pdev); + pci_restore_state(pdev); +- pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev); +- intel_vsec_pci_probe(pdev, pci_dev_id); ++ intel_vsec_pci_init(pdev); + + out: + return status; diff --git a/queue-6.1/platform-x86-intel-vsec-make-driver_data-info-const.patch b/queue-6.1/platform-x86-intel-vsec-make-driver_data-info-const.patch new file mode 100644 index 0000000000..1d5196cbcc --- /dev/null +++ b/queue-6.1/platform-x86-intel-vsec-make-driver_data-info-const.patch @@ -0,0 +1,119 @@ +From stable+bounces-257328-greg=kroah.com@vger.kernel.org Sat May 30 22:38:34 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 13:03:30 -0400 +Subject: platform/x86/intel/vsec: Make driver_data info const +To: stable@vger.kernel.org +Cc: "David E. Box" , "Michael J. Ruhl" , "Ilpo Järvinen" , "Sasha Levin" +Message-ID: <20260530170331.3037528-3-sashal@kernel.org> + +From: "David E. Box" + +[ Upstream commit 9577c74c96f88d807d1ba005adbf5952e7127e55 ] + +Treat PCI id->driver_data (intel_vsec_platform_info) as read-only by making +vsec_priv->info a const pointer and updating all function signatures to +accept const intel_vsec_platform_info *. + +This improves const-correctness and clarifies that the platform info data +from the driver_data table is not meant to be modified at runtime. + +No functional changes intended. + +Signed-off-by: David E. Box +Reviewed-by: Michael J. Ruhl +Link: https://patch.msgid.link/20260313015202.3660072-3-david.e.box@linux.intel.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 348ccc754d89 ("platform/x86/intel/vsec: Fix enable_cnt imbalance on PCIe error recovery") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/vsec.c | 16 ++++++++-------- + drivers/platform/x86/intel/vsec.h | 2 +- + 2 files changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/platform/x86/intel/vsec.c ++++ b/drivers/platform/x86/intel/vsec.c +@@ -74,7 +74,7 @@ static enum intel_vsec_id intel_vsec_all + }; + + struct vsec_priv { +- struct intel_vsec_platform_info *info; ++ const struct intel_vsec_platform_info *info; + }; + + static const char *intel_vsec_name(enum intel_vsec_id id) +@@ -203,7 +203,7 @@ int intel_vsec_add_aux(struct pci_dev *p + EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC); + + static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, +- struct intel_vsec_platform_info *info) ++ const struct intel_vsec_platform_info *info) + { + struct intel_vsec_device *intel_vsec_dev; + struct resource *res, *tmp; +@@ -263,7 +263,7 @@ static int intel_vsec_add_dev(struct pci + } + + static bool intel_vsec_walk_header(struct pci_dev *pdev, +- struct intel_vsec_platform_info *info) ++ const struct intel_vsec_platform_info *info) + { + struct intel_vsec_header **header = info->capabilities; + bool have_devices = false; +@@ -282,7 +282,7 @@ static bool intel_vsec_walk_header(struc + } + + static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, +- struct intel_vsec_platform_info *info) ++ const struct intel_vsec_platform_info *info) + { + bool have_devices = false; + int pos = 0; +@@ -332,7 +332,7 @@ static bool intel_vsec_walk_dvsec(struct + } + + static bool intel_vsec_walk_vsec(struct pci_dev *pdev, +- struct intel_vsec_platform_info *info) ++ const struct intel_vsec_platform_info *info) + { + bool have_devices = false; + int pos = 0; +@@ -377,7 +377,7 @@ static bool intel_vsec_walk_vsec(struct + } + + static bool intel_vsec_get_features(struct pci_dev *pdev, +- struct intel_vsec_platform_info *info) ++ const struct intel_vsec_platform_info *info) + { + bool found = false; + +@@ -403,7 +403,7 @@ static bool intel_vsec_get_features(stru + + static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { +- struct intel_vsec_platform_info *info; ++ const struct intel_vsec_platform_info *info; + struct vsec_priv *priv; + int ret; + +@@ -412,7 +412,7 @@ static int intel_vsec_pci_probe(struct p + return ret; + + pci_save_state(pdev); +- info = (struct intel_vsec_platform_info *)id->driver_data; ++ info = (const struct intel_vsec_platform_info *)id->driver_data; + if (!info) + return -EINVAL; + +--- a/drivers/platform/x86/intel/vsec.h ++++ b/drivers/platform/x86/intel/vsec.h +@@ -36,7 +36,7 @@ struct intel_vsec_device { + struct pci_dev *pcidev; + struct resource *resource; + struct ida *ida; +- struct intel_vsec_platform_info *info; ++ const struct intel_vsec_platform_info *info; + int num_resources; + int id; /* xa */ + void *priv_data; diff --git a/queue-6.1/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch b/queue-6.1/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch new file mode 100644 index 0000000000..5b17bcabd6 --- /dev/null +++ b/queue-6.1/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch @@ -0,0 +1,72 @@ +From stable+bounces-247837-greg=kroah.com@vger.kernel.org Fri May 15 21:16:11 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 11:35:51 -0400 +Subject: pmdomain: core: Fix detach procedure for virtual devices in genpd +To: stable@vger.kernel.org +Cc: Ulf Hansson , Geert Uytterhoeven , Geert Uytterhoeven , Sasha Levin +Message-ID: <20260515153551.3299759-1-sashal@kernel.org> + +From: Ulf Hansson + +[ Upstream commit 26735dfdd8930d9ef1fa92e590a9bf77726efdf6 ] + +If a device is attached to a PM domain through genpd_dev_pm_attach_by_id(), +genpd calls pm_runtime_enable() for the corresponding virtual device that +it registers. While this avoids boilerplate code in drivers, there is no +corresponding call to pm_runtime_disable() in genpd_dev_pm_detach(). + +This means these virtual devices are typically detached from its genpd, +while runtime PM remains enabled for them, which is not how things are +designed to work. In worst cases it may lead to critical errors, like a +NULL pointer dereference bug in genpd_runtime_suspend(), which was recently +reported. For another case, we may end up keeping an unnecessary vote for a +performance state for the device. + +To fix these problems, let's add this missing call to pm_runtime_disable() +in genpd_dev_pm_detach(). + +Reported-by: Geert Uytterhoeven +Closes: https://lore.kernel.org/all/CAMuHMdWapT40hV3c+CSBqFOW05aWcV1a6v_NiJYgoYi0i9_PDQ@mail.gmail.com/ +Fixes: 3c095f32a92b ("PM / Domains: Add support for multi PM domains per device to genpd") +Cc: stable@vger.kernel.org +Tested-by: Geert Uytterhoeven +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/power/domain.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/base/power/domain.c ++++ b/drivers/base/power/domain.c +@@ -2667,6 +2667,7 @@ static struct bus_type genpd_bus_type = + static void genpd_dev_pm_detach(struct device *dev, bool power_off) + { + struct generic_pm_domain *pd; ++ bool is_virt_dev; + unsigned int i; + int ret = 0; + +@@ -2676,6 +2677,13 @@ static void genpd_dev_pm_detach(struct d + + dev_dbg(dev, "removing from PM domain %s\n", pd->name); + ++ /* Check if the device was created by genpd at attach. */ ++ is_virt_dev = dev->bus == &genpd_bus_type; ++ ++ /* Disable runtime PM if we enabled it at attach. */ ++ if (is_virt_dev) ++ pm_runtime_disable(dev); ++ + /* Drop the default performance state */ + if (dev_gpd_data(dev)->default_pstate) { + dev_pm_genpd_set_performance_state(dev, 0); +@@ -2701,7 +2709,7 @@ static void genpd_dev_pm_detach(struct d + genpd_queue_power_off_work(pd); + + /* Unregister the device if it was created by genpd. */ +- if (dev->bus == &genpd_bus_type) ++ if (is_virt_dev) + device_unregister(dev); + } + diff --git a/queue-6.1/printk-add-print_hex_dump_devel.patch b/queue-6.1/printk-add-print_hex_dump_devel.patch new file mode 100644 index 0000000000..1aadcf1b07 --- /dev/null +++ b/queue-6.1/printk-add-print_hex_dump_devel.patch @@ -0,0 +1,49 @@ +From stable+bounces-245028-greg=kroah.com@vger.kernel.org Sun May 10 19:53:03 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 10:22:49 -0400 +Subject: printk: add print_hex_dump_devel() +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , John Ogness , Sasha Levin +Message-ID: <20260510142250.4179491-1-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit d134feeb5df33fbf77f482f52a366a44642dba09 ] + +Add print_hex_dump_devel() as the hex dump equivalent of pr_devel(), +which emits output only when DEBUG is enabled, but keeps call sites +compiled otherwise. + +Suggested-by: Herbert Xu +Signed-off-by: Thorsten Blum +Reviewed-by: John Ogness +Signed-off-by: Herbert Xu +Stable-dep-of: 177730a273b1 ("crypto: caam - guard HMAC key hex dumps in hash_digest_key") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/printk.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -747,6 +747,19 @@ static inline void print_hex_dump_debug( + } + #endif + ++#if defined(DEBUG) ++#define print_hex_dump_devel(prefix_str, prefix_type, rowsize, \ ++ groupsize, buf, len, ascii) \ ++ print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ ++ groupsize, buf, len, ascii) ++#else ++static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, ++ int rowsize, int groupsize, ++ const void *buf, size_t len, bool ascii) ++{ ++} ++#endif ++ + /** + * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default + * params diff --git a/queue-6.1/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch b/queue-6.1/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch new file mode 100644 index 0000000000..3015b1c074 --- /dev/null +++ b/queue-6.1/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch @@ -0,0 +1,497 @@ +From stable+bounces-263494-greg=kroah.com@vger.kernel.org Tue Jun 16 05:50:01 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 20:19:49 -0400 +Subject: RDMA: Move DMA block iterator logic into dedicated files +To: stable@vger.kernel.org +Cc: Leon Romanovsky , Sasha Levin +Message-ID: <20260616001950.2587230-2-sashal@kernel.org> + +From: Leon Romanovsky + +[ Upstream commit 6094ea64c69520ed1e770e7c79c43412de202bfa ] + +The DMA iterator logic was mixed into verbs and umem-specific code, +forcing all users to include rdma/ib_umem.h. Move the block iterator +logic into iter.c and rdma/iter.h so that rdma/ib_umem.h and +rdma/ib_verbs.h can be separated in a follow-up patch. + +Link: https://patch.msgid.link/20260213-refactor-umem-v1-1-f3be85847922@nvidia.com +Signed-off-by: Leon Romanovsky +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/Makefile | 2 + drivers/infiniband/core/iter.c | 43 +++++++++++++ + drivers/infiniband/core/verbs.c | 38 ----------- + drivers/infiniband/hw/bnxt_re/qplib_res.c | 2 + drivers/infiniband/hw/cxgb4/mem.c | 2 + drivers/infiniband/hw/efa/efa_verbs.c | 2 + drivers/infiniband/hw/erdma/erdma_verbs.c | 2 + drivers/infiniband/hw/hns/hns_roce_alloc.c | 2 + drivers/infiniband/hw/irdma/main.h | 2 + drivers/infiniband/hw/mlx4/mr.c | 1 + drivers/infiniband/hw/mlx5/mem.c | 1 + drivers/infiniband/hw/mlx5/umr.c | 1 + drivers/infiniband/hw/mthca/mthca_provider.c | 2 + drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 + drivers/infiniband/hw/qedr/verbs.c | 2 + drivers/infiniband/hw/vmw_pvrdma/pvrdma.h | 2 + include/rdma/ib_umem.h | 32 --------- + include/rdma/ib_verbs.h | 48 -------------- + include/rdma/iter.h | 88 +++++++++++++++++++++++++++ + 19 files changed, 145 insertions(+), 129 deletions(-) + create mode 100644 drivers/infiniband/core/iter.c + create mode 100644 include/rdma/iter.h + +--- a/drivers/infiniband/core/Makefile ++++ b/drivers/infiniband/core/Makefile +@@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verb + roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ + multicast.o mad.o smi.o agent.o mad_rmpp.o \ + nldev.o restrack.o counters.o ib_core_uverbs.o \ +- trace.o lag.o ++ trace.o lag.o iter.o + + ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o + ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o +--- /dev/null ++++ b/drivers/infiniband/core/iter.c +@@ -0,0 +1,43 @@ ++// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB ++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */ ++ ++#include ++#include ++ ++void __rdma_block_iter_start(struct ib_block_iter *biter, ++ struct scatterlist *sglist, unsigned int nents, ++ unsigned long pgsz) ++{ ++ memset(biter, 0, sizeof(struct ib_block_iter)); ++ biter->__sg = sglist; ++ biter->__sg_nents = nents; ++ ++ /* Driver provides best block size to use */ ++ biter->__pg_bit = __fls(pgsz); ++} ++EXPORT_SYMBOL(__rdma_block_iter_start); ++ ++bool __rdma_block_iter_next(struct ib_block_iter *biter) ++{ ++ unsigned int block_offset; ++ unsigned int delta; ++ ++ if (!biter->__sg_nents || !biter->__sg) ++ return false; ++ ++ biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; ++ block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); ++ delta = BIT_ULL(biter->__pg_bit) - block_offset; ++ ++ while (biter->__sg_nents && biter->__sg && ++ sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { ++ delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; ++ biter->__sg_advance = 0; ++ biter->__sg = sg_next(biter->__sg); ++ biter->__sg_nents--; ++ } ++ biter->__sg_advance += delta; ++ ++ return true; ++} ++EXPORT_SYMBOL(__rdma_block_iter_next); +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -2943,44 +2943,6 @@ int rdma_init_netdev(struct ib_device *d + } + EXPORT_SYMBOL(rdma_init_netdev); + +-void __rdma_block_iter_start(struct ib_block_iter *biter, +- struct scatterlist *sglist, unsigned int nents, +- unsigned long pgsz) +-{ +- memset(biter, 0, sizeof(struct ib_block_iter)); +- biter->__sg = sglist; +- biter->__sg_nents = nents; +- +- /* Driver provides best block size to use */ +- biter->__pg_bit = __fls(pgsz); +-} +-EXPORT_SYMBOL(__rdma_block_iter_start); +- +-bool __rdma_block_iter_next(struct ib_block_iter *biter) +-{ +- unsigned int block_offset; +- unsigned int delta; +- +- if (!biter->__sg_nents || !biter->__sg) +- return false; +- +- biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; +- block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); +- delta = BIT_ULL(biter->__pg_bit) - block_offset; +- +- while (biter->__sg_nents && biter->__sg && +- sg_dma_len(biter->__sg) - biter->__sg_advance <= delta) { +- delta -= sg_dma_len(biter->__sg) - biter->__sg_advance; +- biter->__sg_advance = 0; +- biter->__sg = sg_next(biter->__sg); +- biter->__sg_nents--; +- } +- biter->__sg_advance += delta; +- +- return true; +-} +-EXPORT_SYMBOL(__rdma_block_iter_next); +- + /** + * rdma_alloc_hw_stats_struct - Helper function to allocate dynamic struct + * for the drivers. +--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c +@@ -46,7 +46,7 @@ + #include + #include + #include +-#include ++#include + + #include "roce_hsi.h" + #include "qplib_res.h" +--- a/drivers/infiniband/hw/cxgb4/mem.c ++++ b/drivers/infiniband/hw/cxgb4/mem.c +@@ -32,9 +32,9 @@ + + #include + #include +-#include + #include + #include ++#include + + #include "iw_cxgb4.h" + +--- a/drivers/infiniband/hw/efa/efa_verbs.c ++++ b/drivers/infiniband/hw/efa/efa_verbs.c +@@ -9,9 +9,9 @@ + #include + + #include +-#include + #include + #include ++#include + #include + + #include "efa.h" +--- a/drivers/infiniband/hw/erdma/erdma_verbs.c ++++ b/drivers/infiniband/hw/erdma/erdma_verbs.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include "erdma.h" +--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c ++++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c +@@ -32,7 +32,7 @@ + */ + + #include +-#include ++#include + #include "hns_roce_device.h" + + void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf) +--- a/drivers/infiniband/hw/irdma/main.h ++++ b/drivers/infiniband/hw/irdma/main.h +@@ -37,8 +37,8 @@ + #include + #include + #include +-#include + #include ++#include + #include + #include "osdep.h" + #include "defs.h" +--- a/drivers/infiniband/hw/mlx4/mr.c ++++ b/drivers/infiniband/hw/mlx4/mr.c +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + #include "mlx4_ib.h" + +--- a/drivers/infiniband/hw/mlx5/mem.c ++++ b/drivers/infiniband/hw/mlx5/mem.c +@@ -32,6 +32,7 @@ + + #include + #include ++#include + #include "mlx5_ib.h" + #include + +--- a/drivers/infiniband/hw/mlx5/umr.c ++++ b/drivers/infiniband/hw/mlx5/umr.c +@@ -2,6 +2,7 @@ + /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */ + + #include ++#include + #include "mlx5_ib.h" + #include "umr.h" + #include "wr.h" +--- a/drivers/infiniband/hw/mthca/mthca_provider.c ++++ b/drivers/infiniband/hw/mthca/mthca_provider.c +@@ -35,8 +35,8 @@ + */ + + #include +-#include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c ++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +@@ -45,9 +45,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include "ocrdma.h" +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -39,9 +39,9 @@ + #include + #include + #include +-#include + #include + #include ++#include + #include + + #include +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h +@@ -53,8 +53,8 @@ + #include + #include + #include +-#include + #include ++#include + #include + + #include "pvrdma_ring.h" +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -71,38 +71,6 @@ static inline size_t ib_umem_num_pages(s + { + return ib_umem_num_dma_blocks(umem, PAGE_SIZE); + } +- +-static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter, +- struct ib_umem *umem, +- unsigned long pgsz) +-{ +- __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl, +- umem->sgt_append.sgt.nents, pgsz); +- biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1); +- biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz); +-} +- +-static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter) +-{ +- return __rdma_block_iter_next(biter) && biter->__sg_numblocks--; +-} +- +-/** +- * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem +- * @umem: umem to iterate over +- * @biter: block iterator variable +- * @pgsz: Page size to split the list into +- * +- * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The +- * returned DMA blocks will be aligned to pgsz and span the range: +- * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz) +- * +- * Performs exactly ib_umem_num_dma_blocks() iterations. +- */ +-#define rdma_umem_for_each_dma_block(umem, biter, pgsz) \ +- for (__rdma_umem_block_iter_start(biter, umem, pgsz); \ +- __rdma_umem_block_iter_next(biter);) +- + #ifdef CONFIG_INFINIBAND_USER_MEM + + struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, +--- a/include/rdma/ib_verbs.h ++++ b/include/rdma/ib_verbs.h +@@ -2826,22 +2826,6 @@ struct ib_client { + u8 no_kverbs_req:1; + }; + +-/* +- * IB block DMA iterator +- * +- * Iterates the DMA-mapped SGL in contiguous memory blocks aligned +- * to a HW supported page size. +- */ +-struct ib_block_iter { +- /* internal states */ +- struct scatterlist *__sg; /* sg holding the current aligned block */ +- dma_addr_t __dma_addr; /* unaligned DMA address of this block */ +- size_t __sg_numblocks; /* ib_umem_num_dma_blocks() */ +- unsigned int __sg_nents; /* number of SG entries */ +- unsigned int __sg_advance; /* number of bytes to advance in sg in next step */ +- unsigned int __pg_bit; /* alignment of current block */ +-}; +- + struct ib_device *_ib_alloc_device(size_t size); + #define ib_alloc_device(drv_struct, member) \ + container_of(_ib_alloc_device(sizeof(struct drv_struct) + \ +@@ -2863,38 +2847,6 @@ void ib_unregister_device_queued(struct + int ib_register_client (struct ib_client *client); + void ib_unregister_client(struct ib_client *client); + +-void __rdma_block_iter_start(struct ib_block_iter *biter, +- struct scatterlist *sglist, +- unsigned int nents, +- unsigned long pgsz); +-bool __rdma_block_iter_next(struct ib_block_iter *biter); +- +-/** +- * rdma_block_iter_dma_address - get the aligned dma address of the current +- * block held by the block iterator. +- * @biter: block iterator holding the memory block +- */ +-static inline dma_addr_t +-rdma_block_iter_dma_address(struct ib_block_iter *biter) +-{ +- return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1); +-} +- +-/** +- * rdma_for_each_block - iterate over contiguous memory blocks of the sg list +- * @sglist: sglist to iterate over +- * @biter: block iterator holding the memory block +- * @nents: maximum number of sg entries to iterate over +- * @pgsz: best HW supported page size to use +- * +- * Callers may use rdma_block_iter_dma_address() to get each +- * blocks aligned DMA address. +- */ +-#define rdma_for_each_block(sglist, biter, nents, pgsz) \ +- for (__rdma_block_iter_start(biter, sglist, nents, \ +- pgsz); \ +- __rdma_block_iter_next(biter);) +- + /** + * ib_get_client_data - Get IB client context + * @device:Device to get context for +--- /dev/null ++++ b/include/rdma/iter.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ ++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */ ++ ++#ifndef _RDMA_ITER_H_ ++#define _RDMA_ITER_H_ ++ ++#include ++#include ++ ++/** ++ * IB block DMA iterator ++ * ++ * Iterates the DMA-mapped SGL in contiguous memory blocks aligned ++ * to a HW supported page size. ++ */ ++struct ib_block_iter { ++ /* internal states */ ++ struct scatterlist *__sg; /* sg holding the current aligned block */ ++ dma_addr_t __dma_addr; /* unaligned DMA address of this block */ ++ size_t __sg_numblocks; /* ib_umem_num_dma_blocks() */ ++ unsigned int __sg_nents; /* number of SG entries */ ++ unsigned int __sg_advance; /* number of bytes to advance in sg in next step */ ++ unsigned int __pg_bit; /* alignment of current block */ ++}; ++ ++void __rdma_block_iter_start(struct ib_block_iter *biter, ++ struct scatterlist *sglist, ++ unsigned int nents, ++ unsigned long pgsz); ++bool __rdma_block_iter_next(struct ib_block_iter *biter); ++ ++/** ++ * rdma_block_iter_dma_address - get the aligned dma address of the current ++ * block held by the block iterator. ++ * @biter: block iterator holding the memory block ++ */ ++static inline dma_addr_t ++rdma_block_iter_dma_address(struct ib_block_iter *biter) ++{ ++ return biter->__dma_addr & ~(BIT_ULL(biter->__pg_bit) - 1); ++} ++ ++/** ++ * rdma_for_each_block - iterate over contiguous memory blocks of the sg list ++ * @sglist: sglist to iterate over ++ * @biter: block iterator holding the memory block ++ * @nents: maximum number of sg entries to iterate over ++ * @pgsz: best HW supported page size to use ++ * ++ * Callers may use rdma_block_iter_dma_address() to get each ++ * blocks aligned DMA address. ++ */ ++#define rdma_for_each_block(sglist, biter, nents, pgsz) \ ++ for (__rdma_block_iter_start(biter, sglist, nents, \ ++ pgsz); \ ++ __rdma_block_iter_next(biter);) ++ ++static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter, ++ struct ib_umem *umem, ++ unsigned long pgsz) ++{ ++ __rdma_block_iter_start(biter, umem->sgt_append.sgt.sgl, ++ umem->sgt_append.sgt.nents, pgsz); ++ biter->__sg_advance = ib_umem_offset(umem) & ~(pgsz - 1); ++ biter->__sg_numblocks = ib_umem_num_dma_blocks(umem, pgsz); ++} ++ ++static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter) ++{ ++ return __rdma_block_iter_next(biter) && biter->__sg_numblocks--; ++} ++ ++/** ++ * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem ++ * @umem: umem to iterate over ++ * @pgsz: Page size to split the list into ++ * ++ * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The ++ * returned DMA blocks will be aligned to pgsz and span the range: ++ * ALIGN_DOWN(umem->address, pgsz) to ALIGN(umem->address + umem->length, pgsz) ++ * ++ * Performs exactly ib_umem_num_dma_blocks() iterations. ++ */ ++#define rdma_umem_for_each_dma_block(umem, biter, pgsz) \ ++ for (__rdma_umem_block_iter_start(biter, umem, pgsz); \ ++ __rdma_umem_block_iter_next(biter);) ++ ++#endif /* _RDMA_ITER_H_ */ diff --git a/queue-6.1/rdma-umem-fix-kernel-doc-warnings.patch b/queue-6.1/rdma-umem-fix-kernel-doc-warnings.patch new file mode 100644 index 0000000000..53dee4677b --- /dev/null +++ b/queue-6.1/rdma-umem-fix-kernel-doc-warnings.patch @@ -0,0 +1,60 @@ +From stable+bounces-263493-greg=kroah.com@vger.kernel.org Tue Jun 16 05:50:00 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 20:19:48 -0400 +Subject: RDMA/umem: fix kernel-doc warnings +To: stable@vger.kernel.org +Cc: Randy Dunlap , Leon Romanovsky , Sasha Levin +Message-ID: <20260616001950.2587230-1-sashal@kernel.org> + +From: Randy Dunlap + +[ Upstream commit ff46d1392750444fab5ae5a0194764ffdc4ac0d2 ] + +Add or correct kernel-doc comments to eliminate warnings: + +Warning: include/rdma/ib_umem.h:104 function parameter 'biter' not + described in 'rdma_umem_for_each_dma_block' +Warning: include/rdma/ib_umem.h:140 function parameter 'pgsz_bitmap' not + described in 'ib_umem_find_best_pgoff' +Warning: include/rdma/ib_umem.h:141 No description found for return + value of 'ib_umem_find_best_pgoff' + +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260224003120.3173892-1-rdunlap@infradead.org +Signed-off-by: Leon Romanovsky +Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/rdma/ib_umem.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -90,6 +90,7 @@ static inline bool __rdma_umem_block_ite + /** + * rdma_umem_for_each_dma_block - iterate over contiguous DMA blocks of the umem + * @umem: umem to iterate over ++ * @biter: block iterator variable + * @pgsz: Page size to split the list into + * + * pgsz must be <= PAGE_SIZE or computed by ib_umem_find_best_pgsz(). The +@@ -117,7 +118,7 @@ unsigned long ib_umem_find_best_pgsz(str + * ib_umem_find_best_pgoff - Find best HW page size + * + * @umem: umem struct +- * @pgsz_bitmap bitmap of HW supported page sizes ++ * @pgsz_bitmap: bitmap of HW supported page sizes + * @pgoff_bitmask: Mask of bits that can be represented with an offset + * + * This is very similar to ib_umem_find_best_pgsz() except instead of accepting +@@ -130,6 +131,9 @@ unsigned long ib_umem_find_best_pgsz(str + * + * If the pgoff_bitmask requires either alignment in the low bit or an + * unavailable page size for the high bits, this function returns 0. ++ * ++ * Returns: best HW page size for the parameters or 0 if none available ++ * for the given parameters. + */ + static inline unsigned long ib_umem_find_best_pgoff(struct ib_umem *umem, + unsigned long pgsz_bitmap, diff --git a/queue-6.1/rdma-umem-fix-truncation-for-block-sizes-4g.patch b/queue-6.1/rdma-umem-fix-truncation-for-block-sizes-4g.patch new file mode 100644 index 0000000000..e462bc40a2 --- /dev/null +++ b/queue-6.1/rdma-umem-fix-truncation-for-block-sizes-4g.patch @@ -0,0 +1,44 @@ +From stable+bounces-263495-greg=kroah.com@vger.kernel.org Tue Jun 16 05:50:06 2026 +From: Sasha Levin +Date: Mon, 15 Jun 2026 20:19:50 -0400 +Subject: RDMA/umem: Fix truncation for block sizes >= 4G +To: stable@vger.kernel.org +Cc: Jason Gunthorpe , Sasha Levin +Message-ID: <20260616001950.2587230-3-sashal@kernel.org> + +From: Jason Gunthorpe + +[ Upstream commit 15fe76e23615f502d051ef0768f86babaf08746c ] + +When the iommu is used the linearization of the mapping can give a single +block that is very large split across multiple SG entries. + +When __rdma_block_iter_next() reassembles the split SG entries it is +overflowing the 32 bit stack values and computed the wrong DMA addresses +for blocks after the truncation. + +Use the right types to hold DMA addresses. + +Link: https://patch.msgid.link/r/1-v1-88303e9e509f+f7-ib_umem_types_jgg@nvidia.com +Cc: stable@vger.kernel.org +Fixes: a808273a495c ("RDMA/verbs: Add a DMA iterator to return aligned contiguous memory blocks") +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/iter.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/infiniband/core/iter.c ++++ b/drivers/infiniband/core/iter.c +@@ -19,8 +19,8 @@ EXPORT_SYMBOL(__rdma_block_iter_start); + + bool __rdma_block_iter_next(struct ib_block_iter *biter) + { +- unsigned int block_offset; +- unsigned int delta; ++ dma_addr_t block_offset; ++ dma_addr_t delta; + + if (!biter->__sg_nents || !biter->__sg) + return false; diff --git a/queue-6.1/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-6.1/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch new file mode 100644 index 0000000000..f01095ca8f --- /dev/null +++ b/queue-6.1/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch @@ -0,0 +1,124 @@ +From stable+bounces-260877-greg=kroah.com@vger.kernel.org Sat Jun 6 18:03:49 2026 +From: Sasha Levin +Date: Sat, 6 Jun 2026 08:32:06 -0400 +Subject: scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd() +To: stable@vger.kernel.org +Cc: Michael Bommarito , John Garry , "Martin K. Petersen" , Sasha Levin +Message-ID: <20260606123206.2861187-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit 778c2ab142c625a8a8afa570e0f9b7873f445d99 ] + +Two latent bugs in the Text-phase handler, both present since the +original LIO integration in commit e48354ce078c ("iscsi-target: Add +iSCSI fabric support for target v4.1"): + +1) DataDigest CRC buffer overread (4 bytes past text_in). + + text_in is kzalloc()'d at ALIGN(payload_length, 4). rx_size is then + incremented by ISCSI_CRC_LEN to make room for the received DataDigest + in the iovec, but the same (now-bumped) rx_size is passed as the + buffer length to iscsit_crc_buf(): + + if (conn->conn_ops->DataDigest) { + ... + rx_size += ISCSI_CRC_LEN; + } + ... + if (conn->conn_ops->DataDigest) { + data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL); + + iscsit_crc_buf() walks rx_size bytes of text_in with crc32c(), so + when DataDigest is negotiated it reads 4 bytes past the end of the + text_in allocation. KASAN reproduces this directly on the unpatched + mainline tree as slab-out-of-bounds in crc32c() called from the Text + PDU path. The OOB bytes feed crc32c() and are then compared against + the initiator-supplied checksum, so the value does not flow back to + the attacker, but the kernel does read past the buffer on every Text + PDU with DataDigest=CRC32C. + + Fix by passing the actual padded payload length + (ALIGN(payload_length, 4)) that was used for the kzalloc(). + +2) Stale cmd->text_in_ptr re-free (double-free) on ERL>0 bad DataDigest + drop. + + On DataDigest mismatch with ErrorRecoveryLevel > 0 the handler + silently drops the PDU and lets the initiator plug the CmdSN gap: + + kfree(text_in); + return 0; + + cmd->text_in_ptr still points at the freed buffer. The next Text + Request on the same ITT re-enters iscsit_setup_text_cmd(), which + unconditionally does + + kfree(cmd->text_in_ptr); + cmd->text_in_ptr = NULL; + + freeing the same pointer a second time. Session teardown via + iscsit_release_cmd() has the same shape and hits the same double-free + if the connection is dropped before a second Text Request arrives. + + On an unmodified mainline tree the bug-1 CRC overread fires first on + the initial valid Text Request and perturbs the subsequent state, so + #4 was isolated by building a kernel with only the bug-1 hunk of this + patch applied plus temporary printk() observability around the three + relevant kfree() sites. The observability prints are not part of + this patch. On that build, a three-PDU Text Request sequence after + login produces two back-to-back splats: + + BUG: KASAN: double-free in iscsit_setup_text_cmd+0x?? + BUG: KASAN: double-free in iscsit_release_cmd+0x?? + + showing the same pointer freed in the ERL>0 drop path and again in + iscsit_setup_text_cmd() (next Text Request on the same ITT) and once + more in iscsit_release_cmd() (session teardown). On distro kernels + with CONFIG_SLAB_FREELIST_HARDENED=y (default) the double-free + becomes a remote kernel BUG(); on non-hardened kernels it corrupts + the slab freelist. + + Fix by clearing cmd->text_in_ptr after the kfree() in the ERL>0 drop + path. With both hunks applied #4 is directly observable on the stock + tree without observability printks; fixing bug-1 alone would mask #4 + less, not more, so the hunks are submitted together. + +Both fixes are one-liners. The Text PDU state machine is unchanged and +the wire protocol is unaffected. + +Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/iscsi/iscsi_target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -2336,8 +2336,9 @@ iscsit_handle_text_cmd(struct iscsit_con + + if (conn->conn_ops->DataDigest) { + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, +- text_in, rx_size, 0, NULL, +- &data_crc); ++ text_in, ++ ALIGN(payload_length, 4), ++ 0, NULL, &data_crc); + + if (checksum != data_crc) { + pr_err("Text data CRC32C DataDigest" +@@ -2357,6 +2358,7 @@ iscsit_handle_text_cmd(struct iscsit_con + " Command CmdSN: 0x%08x due to" + " DataCRC error.\n", hdr->cmdsn); + kfree(text_in); ++ cmd->text_in_ptr = NULL; + return 0; + } + } else { diff --git a/queue-6.1/selftests-mptcp-drop-nanoseconds-width-specifier.patch b/queue-6.1/selftests-mptcp-drop-nanoseconds-width-specifier.patch new file mode 100644 index 0000000000..020e4cace2 --- /dev/null +++ b/queue-6.1/selftests-mptcp-drop-nanoseconds-width-specifier.patch @@ -0,0 +1,69 @@ +From stable+bounces-256911-greg=kroah.com@vger.kernel.org Sat May 30 19:58:59 2026 +From: Sasha Levin +Date: Sat, 30 May 2026 10:28:35 -0400 +Subject: selftests: mptcp: drop nanoseconds width specifier +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Paolo Abeni , Sasha Levin +Message-ID: <20260530142835.2434049-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 01ff78e4b3d98689184c52d97f9575dfbdc3b10f ] + +Using the format specifier +%s%3N with GNU date is honoured, and only +prints 3 digits of the nanoseconds portion of the seconds since epoch, +which corresponds to the milliseconds. + +The uutils implementation of date currently does not honour this, and +always prints all 9 digits. This is a known issue [1], but can be worked +around by adapting this test to use nanoseconds instead of microseconds, +and then divide it by 1e6. + +This fix is similar to what has been done on systemd side [2], and it is +needed to run the selftests on Ubuntu 26.04, containing uutils 0.8.0. + +Note that the Fixes tag is there even if this patch doesn't fix an issue +in the kernel selftests, but it is useful for those using uutils 0.8.0. + +Fixes: 048d19d444be ("mptcp: add basic kselftest for mptcp") +Cc: stable@vger.kernel.org +Link: https://github.com/uutils/coreutils/issues/11658 [1] +Link: https://github.com/systemd/systemd/pull/41627 [2] +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-6-701e96419f2f@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/net/mptcp/mptcp_connect.sh | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh +@@ -450,7 +450,7 @@ do_transfer() + wait_local_port_listen "${listener_ns}" "${port}" + + local start +- start=$(date +%s%3N) ++ start=$(date +%s%N) + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ +@@ -463,7 +463,7 @@ do_transfer() + local rets=$? + + local stop +- stop=$(date +%s%3N) ++ stop=$(date +%s%N) + + if $capture; then + sleep 1 +@@ -479,7 +479,7 @@ do_transfer() + fi + + local duration +- duration=$((stop-start)) ++ duration=$(((stop-start) / 1000000)) + printf "(duration %05sms) " "${duration}" + if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then + echo "[ FAIL ] client exit code $retc, server $rets" 1>&2 diff --git a/queue-6.1/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch b/queue-6.1/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch new file mode 100644 index 0000000000..1d4ca3ab7f --- /dev/null +++ b/queue-6.1/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch @@ -0,0 +1,42 @@ +From stable+bounces-260847-greg=kroah.com@vger.kernel.org Sat Jun 6 08:17:19 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 22:47:09 -0400 +Subject: serial: qcom-geni: fix UART_RX_PAR_EN bit position +To: stable@vger.kernel.org +Cc: Prasanna S , stable , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606024709.2514691-3-sashal@kernel.org> + +From: Prasanna S + +[ Upstream commit ca2584d841b69391ffc4144840563d2e1a0018df ] + +UART_RX_PAR_EN is incorrectly defined as bit 3, which triggers false +framing errors (S_GP_IRQ_1_EN) and causes received data to be dropped +when parity is enabled and the parity bit is 0. + +Define UART_RX_PAR_EN as bit 4 of the SE_UART_RX_TRANS_CFG register, as +specified in the reference manual. + +Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") +Cc: stable +Signed-off-by: Prasanna S +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/qcom_geni_serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -47,7 +47,7 @@ + #define TX_STOP_BIT_LEN_2 2 + + /* SE_UART_RX_TRANS_CFG */ +-#define UART_RX_PAR_EN BIT(3) ++#define UART_RX_PAR_EN BIT(4) + + /* SE_UART_RX_WORD_LEN */ + #define RX_WORD_LEN_MASK GENMASK(9, 0) diff --git a/queue-6.1/serial-samsung_tty-use-port-lock-wrappers.patch b/queue-6.1/serial-samsung_tty-use-port-lock-wrappers.patch new file mode 100644 index 0000000000..23bfbb1ebe --- /dev/null +++ b/queue-6.1/serial-samsung_tty-use-port-lock-wrappers.patch @@ -0,0 +1,254 @@ +From stable+bounces-260726-greg=kroah.com@vger.kernel.org Fri Jun 5 21:15:43 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:31:02 -0400 +Subject: serial: samsung_tty: Use port lock wrappers +To: stable@vger.kernel.org +Cc: Thomas Gleixner , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605153104.1929085-1-sashal@kernel.org> + +From: Thomas Gleixner + +[ Upstream commit 97d7a9aeba1d424c2359f1686d02c75d798ad184 ] + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-54-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 50 +++++++++++++++++++-------------------- + 1 file changed, 25 insertions(+), 25 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -251,7 +251,7 @@ static void s3c24xx_serial_rx_enable(str + unsigned int ucon, ufcon; + int count = 10000; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); +@@ -265,7 +265,7 @@ static void s3c24xx_serial_rx_enable(str + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 1; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_rx_disable(struct uart_port *port) +@@ -274,14 +274,14 @@ static void s3c24xx_serial_rx_disable(st + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 0; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_stop_tx(struct uart_port *port) +@@ -349,7 +349,7 @@ static void s3c24xx_serial_tx_dma_comple + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + port->icount.tx += count; +@@ -359,7 +359,7 @@ static void s3c24xx_serial_tx_dma_comple + uart_write_wakeup(port); + + s3c24xx_serial_start_next_tx(ourport); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void enable_tx_dma(struct s3c24xx_uart_port *ourport) +@@ -625,7 +625,7 @@ static void s3c24xx_serial_rx_dma_comple + received = dma->rx_bytes_requested - state.residue; + async_tx_ack(dma->rx_desc); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (received) + s3c24xx_uart_copy_rx_to_tty(ourport, t, received); +@@ -637,7 +637,7 @@ static void s3c24xx_serial_rx_dma_comple + + s3c64xx_start_rx_dma(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) +@@ -728,7 +728,7 @@ static irqreturn_t s3c24xx_serial_rx_cha + utrstat = rd_regl(port, S3C2410_UTRSTAT); + rd_regl(port, S3C2410_UFSTAT); + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) { + s3c64xx_start_rx_dma(ourport); +@@ -757,7 +757,7 @@ static irqreturn_t s3c24xx_serial_rx_cha + wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT); + + finish: +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -854,9 +854,9 @@ static irqreturn_t s3c24xx_serial_rx_cha + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + s3c24xx_serial_rx_drain_fifo(ourport); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -938,11 +938,11 @@ static irqreturn_t s3c24xx_serial_tx_irq + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + s3c24xx_serial_tx_chars(ourport); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_HANDLED; + } + +@@ -1038,7 +1038,7 @@ static void s3c24xx_serial_break_ctl(str + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + +@@ -1049,7 +1049,7 @@ static void s3c24xx_serial_break_ctl(str + + wr_regl(port, S3C2410_UCON, ucon); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) +@@ -1308,7 +1308,7 @@ static int s3c64xx_serial_startup(struct + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1318,7 +1318,7 @@ static int s3c64xx_serial_startup(struct + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); +@@ -1346,7 +1346,7 @@ static int apple_s5l_serial_startup(stru + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1356,7 +1356,7 @@ static int apple_s5l_serial_startup(stru + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); +@@ -1633,7 +1633,7 @@ static void s3c24xx_serial_set_termios(s + ulcon |= S3C2410_LCON_PNONE; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", +@@ -1691,7 +1691,7 @@ static void s3c24xx_serial_set_termios(s + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *s3c24xx_serial_type(struct uart_port *port) +@@ -2476,14 +2476,14 @@ s3c24xx_serial_console_write(struct cons + if (cons_uart->sysrq) + locked = false; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&cons_uart->lock, flags); ++ locked = uart_port_trylock_irqsave(cons_uart, &flags); + else +- spin_lock_irqsave(&cons_uart->lock, flags); ++ uart_port_lock_irqsave(cons_uart, &flags); + + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); + + if (locked) +- spin_unlock_irqrestore(&cons_uart->lock, flags); ++ uart_port_unlock_irqrestore(cons_uart, flags); + } + + /* Shouldn't be __init, as it can be instantiated from other module */ diff --git a/queue-6.1/series b/queue-6.1/series index 07c1839b59..b6d5ef9912 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -354,3 +354,136 @@ net-qrtr-ns-limit-the-total-number-of-nodes.patch net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch spi-fix-resource-leaks-on-device-setup-failure.patch fbdev-defio-disconnect-deferred-i-o-from-the-lifetime-of-struct-fb_info.patch +xfs-fix-a-resource-leak-in-xfs_alloc_buftarg.patch +udf-fix-partition-descriptor-append-bookkeeping.patch +hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch +hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch +crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch +crypto-nx-migrate-to-scomp-api.patch +crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch +erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch +ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch +printk-add-print_hex_dump_devel.patch +crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch +net-stmmac-avoid-shadowing-global-buf_sz.patch +net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch +net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch +tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch +wifi-mac80211-remove-station-if-connection-prep-fails.patch +wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch +usb-dwc3-move-guid-programming-after-phy-initialization.patch +net-ipv4-stop-checking-crypto_ahash_alignmask.patch +net-ipv6-stop-checking-crypto_ahash_alignmask.patch +xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch +xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch +spi-synquacer-convert-to-platform-remove-callback-returning-void.patch +spi-synquacer-switch-to-use-modern-name.patch +spi-syncuacer-fix-controller-deregistration.patch +spi-sun4i-convert-to-platform-remove-callback-returning-void.patch +spi-sun4i-switch-to-use-modern-name.patch +spi-sun4i-fix-controller-deregistration.patch +spi-convert-to-spi_controller_half_duplex.patch +spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch +spi-spi-ti-qspi-switch-to-use-modern-name.patch +spi-ti-qspi-fix-controller-deregistration.patch +spi-zynq-qspi-convert-to-platform-remove-callback-returning-void.patch +spi-spi-zynq-do-not-check-for-0-return-after-calling-platform_get_irq.patch +spi-zynq-qspi-switch-to-use-modern-name.patch +spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch +spi-zynq-qspi-fix-controller-deregistration.patch +spi-sun6i-fix-controller-deregistration.patch +spi-s3c64xx-use-devm_clk_get_enabled.patch +spi-s3c64xx-fix-null-deref-on-driver-unbind.patch +mtd-spi-nor-core-fix-implicit-declaration-warning.patch +mtd-spi-nor-debugfs-fix-out-of-bounds-read-in-spi_nor_params_show.patch +spi-tegra114-fix-controller-deregistration.patch +spi-tegra20-sflash-fix-controller-deregistration.patch +spi-uniphier-convert-to-platform-remove-callback-returning-void.patch +spi-uniphier-switch-to-use-modern-name.patch +spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch +spi-uniphier-fix-controller-deregistration.patch +mm-hugetlb_cma-round-up-per_node-before-logging-it.patch +net-wwan-t7xx-validate-port_count-against-message-length-in-t7xx_port_enum_msg_handler.patch +spi-microchip-core-qspi-convert-to-platform-remove-callback-returning-void.patch +spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch +spi-microchip-core-qspi-fix-controller-deregistration.patch +fbcon-avoid-oob-font-access-if-console-rotation-fails.patch +spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch +btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch +tracing-probes-limit-size-of-event-probe-to-3k.patch +btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_space_info_type.patch +btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch +pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch +smb-client-validate-dacloffset-before-building-dacl-pointers.patch +smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch +btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch +mptcp-fastclose-msk-when-linger-time-is-0.patch +mptcp-pm-prio-skip-closed-subflows.patch +mptcp-pm-kernel-correctly-retransmit-add_addr-id-0.patch +mptcp-pm-add_addr-rtx-allow-id-0.patch +mptcp-pm-add_addr-rtx-fix-potential-data-race.patch +mptcp-pm-add_addr-rtx-resched-blocked-add_addr-quicker.patch +f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch +f2fs-fix-false-alarm-of-lockdep-on-cp_global_sem-lock.patch +spi-st-ssc4-switch-to-use-modern-name.patch +spi-st-ssc4-fix-controller-deregistration.patch +spi-lantiq-ssc-fix-controller-deregistration.patch +cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch +genetlink-use-internal-flags-for-multicast-groups.patch +smb-client-require-net-admin-for-cifs-swn-netlink.patch +bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch +mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch +bluetooth-init-sk_peer_-on-bt_sock_alloc.patch +bluetooth-serialize-accept_q-access.patch +net-hsr-defer-node-table-free-until-after-rcu-readers.patch +ipv6-ioam-add-null-check-for-idev-in-ipv6_hop_ioam.patch +ice-fix-vf-queue-configuration-with-low-mtu-values.patch +mptcp-pm-fix-add_addr-timer-infinite-retry-on-option-space-insufficient.patch +selftests-mptcp-drop-nanoseconds-width-specifier.patch +octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch +octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch +mptcp-reset-rcv-wnd-on-disconnect.patch +mptcp-do-not-drop-partial-packets.patch +platform-x86-intel-vsec-add-private-data-for-per-device-data.patch +platform-x86-intel-vsec-create-wrapper-to-walk-pci-config-space.patch +platform-x86-intel-vsec-make-driver_data-info-const.patch +platform-x86-intel-vsec-fix-enable_cnt-imbalance-on-pcie-error-recovery.patch +octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch +spi-qup-switch-to-use-modern-name.patch +spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch +arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch +phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch +phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch +iio-adc-fix-the-return-value-handle-for-platform_get_irq.patch +iio-adc-npcm-convert-to-platform-remove-callback-returning-void.patch +iio-adc-npcm-fix-unbalanced-clk_disable_unprepare.patch +iio-gyro-adis16260-fix-division-by-zero-in-write_raw.patch +iio-chemical-scd30-use-guard-mutex-to-allow-early-returns.patch +iio-chemical-scd30-fix-division-by-zero-in-write_raw.patch +usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch +iio-dac-ad5686-fix-ref-bit-initialization-for-single-channel-parts.patch +alsa-firewire-motu-protect-register-dsp-event-queue-positions.patch +serial-samsung_tty-use-port-lock-wrappers.patch +tty-serial-samsung-use-u32-for-register-interactions.patch +tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch +usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch +usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch +usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch +usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch +usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch +thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch +tty-serial-qcom-geni-serial-remove-unused-symbols.patch +tty-serial-qcom-geni-serial-align-define-values.patch +serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch +scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch +usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch +netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch +hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch +mm-hugetlb-rename-isolate_hugetlb-to-folio_isolate_hugetlb.patch +mm-migrate-don-t-call-folio_putback_active_hugetlb-on-dst-hugetlb-folio.patch +mm-hugetlb-rename-folio_putback_active_hugetlb-to-folio_putback_hugetlb.patch +mm-memory-failure-fix-missing-mf_stats-count-in-hugetlb-poison.patch +mm-memory-failure-fix-hugetlb_lock-aa-deadlock-in-get_huge_page_for_hwpoison.patch +rdma-umem-fix-kernel-doc-warnings.patch +rdma-move-dma-block-iterator-logic-into-dedicated-files.patch +rdma-umem-fix-truncation-for-block-sizes-4g.patch diff --git a/queue-6.1/smb-client-require-net-admin-for-cifs-swn-netlink.patch b/queue-6.1/smb-client-require-net-admin-for-cifs-swn-netlink.patch new file mode 100644 index 0000000000..7289ae46fc --- /dev/null +++ b/queue-6.1/smb-client-require-net-admin-for-cifs-swn-netlink.patch @@ -0,0 +1,62 @@ +From stable+bounces-256668-greg=kroah.com@vger.kernel.org Fri May 29 22:49:35 2026 +From: Sasha Levin +Date: Fri, 29 May 2026 13:06:10 -0400 +Subject: smb: client: require net admin for CIFS SWN netlink +To: stable@vger.kernel.org +Cc: Michael Bommarito , Steve French , Sasha Levin +Message-ID: <20260529170610.1279657-2-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit d1ebfce2c1d161186a82e77590bf7da2ea1bce91 ] + +CIFS_GENL_CMD_SWN_NOTIFY is the userspace witness-notify command. The +intended sender is the cifs.witness helper, but the generic-netlink +operation currently has no capability flag, so any local process can send +RESOURCE_CHANGE or CLIENT_MOVE notifications to the in-kernel witness +handler. + +The same family exposes CIFS_GENL_MCGRP_SWN without multicast-group +capability flags. Register messages sent to that group include the witness +registration id and, for NTLM-authenticated mounts, the username, domain, +and password attributes copied from the CIFS session. An unprivileged +local process should not be able to join that group and receive those +messages. + +Require CAP_NET_ADMIN for incoming SWN_NOTIFY commands with +GENL_ADMIN_PERM, and require CAP_NET_ADMIN over the network namespace for +joining the SWN multicast group with GENL_MCAST_CAP_NET_ADMIN. The +cifs.witness service runs with the privileges needed for both operations. + +Fixes: fed979a7e082 ("cifs: Set witness notification handler for messages from userspace daemon") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/netlink.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/smb/client/netlink.c ++++ b/fs/smb/client/netlink.c +@@ -33,13 +33,17 @@ static const struct nla_policy cifs_genl + static const struct genl_ops cifs_genl_ops[] = { + { + .cmd = CIFS_GENL_CMD_SWN_NOTIFY, ++ .flags = GENL_ADMIN_PERM, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = cifs_swn_notify, + }, + }; + + static const struct genl_multicast_group cifs_genl_mcgrps[] = { +- [CIFS_GENL_MCGRP_SWN] = { .name = CIFS_GENL_MCGRP_SWN_NAME }, ++ [CIFS_GENL_MCGRP_SWN] = { ++ .name = CIFS_GENL_MCGRP_SWN_NAME, ++ .flags = GENL_MCAST_CAP_NET_ADMIN, ++ }, + }; + + struct genl_family cifs_genl_family = { diff --git a/queue-6.1/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch b/queue-6.1/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch new file mode 100644 index 0000000000..d9c6165bff --- /dev/null +++ b/queue-6.1/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch @@ -0,0 +1,154 @@ +From stable+bounces-249112-greg=kroah.com@vger.kernel.org Sun May 17 21:18:41 2026 +From: Sasha Levin +Date: Sun, 17 May 2026 11:48:33 -0400 +Subject: smb: client: Use FullSessionKey for AES-256 encryption key derivation +To: stable@vger.kernel.org +Cc: Piyush Sachdeva , Bharath SM , Piyush Sachdeva , Steve French , Sasha Levin +Message-ID: <20260517154833.296848-1-sashal@kernel.org> + +From: Piyush Sachdeva + +[ Upstream commit 5be7a0cef3229fb3b63a07c0d289daf752545424 ] + +When Kerberos authentication is used with AES-256 encryption (AES-256-CCM +or AES-256-GCM), the SMB3 encryption and decryption keys must be derived +using the full session key (Session.FullSessionKey) rather than just the +first 16 bytes (Session.SessionKey). + +Per MS-SMB2 section 3.2.5.3.1, when Connection.Dialect is "3.1.1" and +Connection.CipherId is AES-256-CCM or AES-256-GCM, Session.FullSessionKey +must be set to the full cryptographic key from the GSS authentication +context. The encryption and decryption key derivation (SMBC2SCipherKey, +SMBS2CCipherKey) must use this FullSessionKey as the KDF input. The +signing key derivation continues to use Session.SessionKey (first 16 +bytes) in all cases. + +Previously, generate_key() hardcoded SMB2_NTLMV2_SESSKEY_SIZE (16) as the +HMAC-SHA256 key input length for all derivations. When Kerberos with +AES-256 provides a 32-byte session key, the KDF for encryption/decryption +was using only the first 16 bytes, producing keys that did not match the +server's, causing mount failures with sec=krb5 and require_gcm_256=1. + +Add a full_key_size parameter to generate_key() and pass the appropriate +size from generate_smb3signingkey(): + - Signing: always SMB2_NTLMV2_SESSKEY_SIZE (16 bytes) + - Encryption/Decryption: ses->auth_key.len when AES-256, otherwise 16 + +Also fix cifs_dump_full_key() to report the actual session key length for +AES-256 instead of hardcoded CIFS_SESS_KEY_SIZE, so that userspace tools +like Wireshark receive the correct key for decryption. + +Cc: +Reviewed-by: Bharath SM +Signed-off-by: Piyush Sachdeva +Signed-off-by: Piyush Sachdeva +Signed-off-by: Steve French +[ adapted upstream's void/hmac_sha256_init_usingrawkey-based generate_key() to 6.12's int-return crypto_shash_* form while threading full_key_size through all callers. ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/ioctl.c | 2 +- + fs/smb/client/smb2transport.c | 32 +++++++++++++++++++++++++------- + 2 files changed, 26 insertions(+), 8 deletions(-) + +--- a/fs/smb/client/ioctl.c ++++ b/fs/smb/client/ioctl.c +@@ -279,7 +279,7 @@ search_end: + break; + case SMB2_ENCRYPTION_AES256_CCM: + case SMB2_ENCRYPTION_AES256_GCM: +- out.session_key_length = CIFS_SESS_KEY_SIZE; ++ out.session_key_length = ses->auth_key.len; + out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE; + break; + default: +--- a/fs/smb/client/smb2transport.c ++++ b/fs/smb/client/smb2transport.c +@@ -307,7 +307,8 @@ out: + } + + static int generate_key(struct cifs_ses *ses, struct kvec label, +- struct kvec context, __u8 *key, unsigned int key_size) ++ struct kvec context, __u8 *key, unsigned int key_size, ++ unsigned int full_key_size) + { + unsigned char zero = 0x0; + __u8 i[4] = {0, 0, 0, 1}; +@@ -328,7 +329,7 @@ static int generate_key(struct cifs_ses + } + + rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm, +- ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); ++ ses->auth_key.response, full_key_size); + if (rc) { + cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); + goto smb3signkey_ret; +@@ -403,6 +404,7 @@ generate_smb3signingkey(struct cifs_ses + struct TCP_Server_Info *server, + const struct derivation_triplet *ptriplet) + { ++ unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE; + int rc; + bool is_binding = false; + int chan_index = 0; +@@ -431,17 +433,31 @@ generate_smb3signingkey(struct cifs_ses + rc = generate_key(ses, ptriplet->signing.label, + ptriplet->signing.context, + ses->chans[chan_index].signkey, +- SMB3_SIGN_KEY_SIZE); ++ SMB3_SIGN_KEY_SIZE, ++ SMB2_NTLMV2_SESSKEY_SIZE); + if (rc) + return rc; + } else { + rc = generate_key(ses, ptriplet->signing.label, + ptriplet->signing.context, + ses->smb3signingkey, +- SMB3_SIGN_KEY_SIZE); ++ SMB3_SIGN_KEY_SIZE, ++ SMB2_NTLMV2_SESSKEY_SIZE); + if (rc) + return rc; + ++ /* ++ * Per MS-SMB2 3.2.5.3.1, signing key always uses Session.SessionKey ++ * (first 16 bytes). Encryption/decryption keys use ++ * Session.FullSessionKey when dialect is 3.1.1 and cipher is ++ * AES-256-CCM or AES-256-GCM, otherwise Session.SessionKey. ++ */ ++ ++ if (server->dialect == SMB311_PROT_ID && ++ (server->cipher_type == SMB2_ENCRYPTION_AES256_CCM || ++ server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) ++ full_key_size = ses->auth_key.len; ++ + /* safe to access primary channel, since it will never go away */ + spin_lock(&ses->chan_lock); + memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey, +@@ -451,13 +467,15 @@ generate_smb3signingkey(struct cifs_ses + rc = generate_key(ses, ptriplet->encryption.label, + ptriplet->encryption.context, + ses->smb3encryptionkey, +- SMB3_ENC_DEC_KEY_SIZE); ++ SMB3_ENC_DEC_KEY_SIZE, ++ full_key_size); + if (rc) + return rc; + rc = generate_key(ses, ptriplet->decryption.label, + ptriplet->decryption.context, + ses->smb3decryptionkey, +- SMB3_ENC_DEC_KEY_SIZE); ++ SMB3_ENC_DEC_KEY_SIZE, ++ full_key_size); + if (rc) + return rc; + } +@@ -472,7 +490,7 @@ generate_smb3signingkey(struct cifs_ses + &ses->Suid); + cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type); + cifs_dbg(VFS, "Session Key %*ph\n", +- SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); ++ (int)ses->auth_key.len, ses->auth_key.response); + cifs_dbg(VFS, "Signing Key %*ph\n", + SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); + if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || diff --git a/queue-6.1/smb-client-validate-dacloffset-before-building-dacl-pointers.patch b/queue-6.1/smb-client-validate-dacloffset-before-building-dacl-pointers.patch new file mode 100644 index 0000000000..31619e68d7 --- /dev/null +++ b/queue-6.1/smb-client-validate-dacloffset-before-building-dacl-pointers.patch @@ -0,0 +1,120 @@ +From stable+bounces-248925-greg=kroah.com@vger.kernel.org Sat May 16 03:06:06 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 17:36:00 -0400 +Subject: smb: client: validate dacloffset before building DACL pointers +To: stable@vger.kernel.org +Cc: Michael Bommarito , Steve French , Sasha Levin +Message-ID: <20260515213600.3513360-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit f98b48151cc502ada59d9778f0112d21f2586ca3 ] + +parse_sec_desc(), build_sec_desc(), and the chown path in +id_mode_to_cifs_acl() all add the server-supplied dacloffset to pntsd +before proving a DACL header fits inside the returned security +descriptor. + +On 32-bit builds a malicious server can return dacloffset near +U32_MAX, wrap the derived DACL pointer below end_of_acl, and then slip +past the later pointer-based bounds checks. build_sec_desc() and +id_mode_to_cifs_acl() can then dereference DACL fields from the wrapped +pointer in the chmod/chown rewrite paths. + +Validate dacloffset numerically before building any DACL pointer and +reuse the same helper at the three DACL entry points. + +Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Signed-off-by: Steve French +[ renamed smb_ntsd/smb_acl structs to cifs_ntsd/cifs_acl and kept existing inline ACL size check instead of using missing validate_dacl() helper ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/cifsacl.c | 35 ++++++++++++++++++++++++++++++++--- + 1 file changed, 32 insertions(+), 3 deletions(-) + +--- a/fs/smb/client/cifsacl.c ++++ b/fs/smb/client/cifsacl.c +@@ -1254,6 +1254,17 @@ static int parse_sid(struct cifs_sid *ps + return 0; + } + ++static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset) ++{ ++ if (acl_len < sizeof(struct cifs_acl)) ++ return false; ++ ++ if (dacloffset < sizeof(struct cifs_ntsd)) ++ return false; ++ ++ return dacloffset <= acl_len - sizeof(struct cifs_acl); ++} ++ + + /* Convert CIFS ACL to POSIX form */ + static int parse_sec_desc(struct cifs_sb_info *cifs_sb, +@@ -1274,7 +1285,6 @@ static int parse_sec_desc(struct cifs_sb + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + + le32_to_cpu(pntsd->gsidoffset)); + dacloffset = le32_to_cpu(pntsd->dacloffset); +- dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); + cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", + pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), + le32_to_cpu(pntsd->gsidoffset), +@@ -1305,11 +1315,18 @@ static int parse_sec_desc(struct cifs_sb + return rc; + } + +- if (dacloffset) ++ if (dacloffset) { ++ if (!dacl_offset_valid(acl_len, dacloffset)) { ++ cifs_dbg(VFS, "Server returned illegal DACL offset\n"); ++ return -EINVAL; ++ } ++ ++ dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); + parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, + group_sid_ptr, fattr, get_mode_from_special_sid); +- else ++ } else { + cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */ ++ } + + return rc; + } +@@ -1332,6 +1349,11 @@ static int build_sec_desc(struct cifs_nt + + dacloffset = le32_to_cpu(pntsd->dacloffset); + if (dacloffset) { ++ if (!dacl_offset_valid(secdesclen, dacloffset)) { ++ cifs_dbg(VFS, "Server returned illegal DACL offset\n"); ++ return -EINVAL; ++ } ++ + dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, end_of_acl); + if (rc) +@@ -1698,6 +1720,12 @@ id_mode_to_cifs_acl(struct inode *inode, + nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2); + dacloffset = le32_to_cpu(pntsd->dacloffset); + if (dacloffset) { ++ if (!dacl_offset_valid(secdesclen, dacloffset)) { ++ cifs_dbg(VFS, "Server returned illegal DACL offset\n"); ++ rc = -EINVAL; ++ goto id_mode_to_cifs_acl_exit; ++ } ++ + dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen); + if (rc) { +@@ -1740,6 +1768,7 @@ id_mode_to_cifs_acl(struct inode *inode, + rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag); + cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); + } ++id_mode_to_cifs_acl_exit: + cifs_put_tlink(tlink); + + kfree(pnntsd); diff --git a/queue-6.1/spi-convert-to-spi_controller_half_duplex.patch b/queue-6.1/spi-convert-to-spi_controller_half_duplex.patch new file mode 100644 index 0000000000..d9809ea059 --- /dev/null +++ b/queue-6.1/spi-convert-to-spi_controller_half_duplex.patch @@ -0,0 +1,167 @@ +From stable+bounces-247003-greg=kroah.com@vger.kernel.org Wed May 13 23:58:16 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:14 -0400 +Subject: spi: Convert to SPI_CONTROLLER_HALF_DUPLEX +To: stable@vger.kernel.org +Cc: Andy Shevchenko , Mark Brown , Sasha Levin +Message-ID: <20260513182017.3918352-1-sashal@kernel.org> + +From: Andy Shevchenko + +[ Upstream commit 7a2b552c8e0e5bb280558f6c120140f5f06323bc ] + +Convert the users under SPI subsystem to SPI_CONTROLLER_HALF_DUPLEX. + +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20230710154932.68377-15-andriy.shevchenko@linux.intel.com +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-amd.c | 2 +- + drivers/spi/spi-cavium-thunderx.c | 2 +- + drivers/spi/spi-falcon.c | 2 +- + drivers/spi/spi-lp8841-rtc.c | 2 +- + drivers/spi/spi-mxs.c | 2 +- + drivers/spi/spi-omap-uwire.c | 2 +- + drivers/spi/spi-pic32-sqi.c | 2 +- + drivers/spi/spi-qcom-qspi.c | 2 +- + drivers/spi/spi-rockchip-sfc.c | 2 +- + drivers/spi/spi-sprd-adi.c | 2 +- + drivers/spi/spi-ti-qspi.c | 2 +- + drivers/spi/spi-xcomm.c | 2 +- + 12 files changed, 12 insertions(+), 12 deletions(-) + +--- a/drivers/spi/spi-amd.c ++++ b/drivers/spi/spi-amd.c +@@ -404,7 +404,7 @@ static int amd_spi_probe(struct platform + master->bus_num = 0; + master->num_chipselect = 4; + master->mode_bits = 0; +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->max_speed_hz = AMD_SPI_MAX_HZ; + master->min_speed_hz = AMD_SPI_MIN_HZ; + master->setup = amd_spi_master_setup; +--- a/drivers/spi/spi-cavium-thunderx.c ++++ b/drivers/spi/spi-cavium-thunderx.c +@@ -64,7 +64,7 @@ static int thunderx_spi_probe(struct pci + p->sys_freq = SYS_FREQ_DEFAULT; + dev_info(dev, "Set system clock to %u\n", p->sys_freq); + +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->num_chipselect = 4; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | + SPI_LSB_FIRST | SPI_3WIRE; +--- a/drivers/spi/spi-falcon.c ++++ b/drivers/spi/spi-falcon.c +@@ -401,7 +401,7 @@ static int falcon_sflash_probe(struct pl + priv->master = master; + + master->mode_bits = SPI_MODE_3; +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->setup = falcon_sflash_setup; + master->transfer_one_message = falcon_sflash_xfer_one; + master->dev.of_node = pdev->dev.of_node; +--- a/drivers/spi/spi-lp8841-rtc.c ++++ b/drivers/spi/spi-lp8841-rtc.c +@@ -191,7 +191,7 @@ spi_lp8841_rtc_probe(struct platform_dev + return -ENOMEM; + platform_set_drvdata(pdev, master); + +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->mode_bits = SPI_CS_HIGH | SPI_3WIRE | SPI_LSB_FIRST; + + master->bus_num = pdev->id; +--- a/drivers/spi/spi-mxs.c ++++ b/drivers/spi/spi-mxs.c +@@ -573,7 +573,7 @@ static int mxs_spi_probe(struct platform + master->mode_bits = SPI_CPOL | SPI_CPHA; + master->num_chipselect = 3; + master->dev.of_node = np; +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->auto_runtime_pm = true; + + spi = spi_master_get_devdata(master); +--- a/drivers/spi/spi-omap-uwire.c ++++ b/drivers/spi/spi-omap-uwire.c +@@ -491,7 +491,7 @@ static int uwire_probe(struct platform_d + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + + master->bus_num = 2; /* "official" */ + master->num_chipselect = 4; +--- a/drivers/spi/spi-pic32-sqi.c ++++ b/drivers/spi/spi-pic32-sqi.c +@@ -648,7 +648,7 @@ static int pic32_sqi_probe(struct platfo + master->dev.of_node = pdev->dev.of_node; + master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL | + SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD; +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->can_dma = pic32_sqi_can_dma; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->transfer_one_message = pic32_sqi_one_message; +--- a/drivers/spi/spi-qcom-qspi.c ++++ b/drivers/spi/spi-qcom-qspi.c +@@ -523,7 +523,7 @@ static int qcom_qspi_probe(struct platfo + master->mode_bits = SPI_MODE_0 | + SPI_TX_DUAL | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_RX_QUAD; +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->prepare_message = qcom_qspi_prepare_message; + master->transfer_one = qcom_qspi_transfer_one; + master->handle_err = qcom_qspi_handle_err; +--- a/drivers/spi/spi-rockchip-sfc.c ++++ b/drivers/spi/spi-rockchip-sfc.c +@@ -566,7 +566,7 @@ static int rockchip_sfc_probe(struct pla + if (!master) + return -ENOMEM; + +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->mem_ops = &rockchip_sfc_mem_ops; + master->dev.of_node = pdev->dev.of_node; + master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL; +--- a/drivers/spi/spi-sprd-adi.c ++++ b/drivers/spi/spi-sprd-adi.c +@@ -570,7 +570,7 @@ static int sprd_adi_probe(struct platfor + ctlr->dev.of_node = pdev->dev.of_node; + ctlr->bus_num = pdev->id; + ctlr->num_chipselect = num_chipselect; +- ctlr->flags = SPI_MASTER_HALF_DUPLEX; ++ ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; + ctlr->bits_per_word_mask = 0; + ctlr->transfer_one = sprd_adi_transfer_one; + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -770,7 +770,7 @@ static int ti_qspi_probe(struct platform + + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; + +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->setup = ti_qspi_setup; + master->auto_runtime_pm = true; + master->transfer_one_message = ti_qspi_start_transfer_one; +--- a/drivers/spi/spi-xcomm.c ++++ b/drivers/spi/spi-xcomm.c +@@ -219,7 +219,7 @@ static int spi_xcomm_probe(struct i2c_cl + master->num_chipselect = 16; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE; + master->bits_per_word_mask = SPI_BPW_MASK(8); +- master->flags = SPI_MASTER_HALF_DUPLEX; ++ master->flags = SPI_CONTROLLER_HALF_DUPLEX; + master->transfer_one_message = spi_xcomm_transfer_one; + master->dev.of_node = i2c->dev.of_node; + i2c_set_clientdata(i2c, master); diff --git a/queue-6.1/spi-lantiq-ssc-fix-controller-deregistration.patch b/queue-6.1/spi-lantiq-ssc-fix-controller-deregistration.patch new file mode 100644 index 0000000000..859415cc66 --- /dev/null +++ b/queue-6.1/spi-lantiq-ssc-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-249945-greg=kroah.com@vger.kernel.org Wed May 20 20:18:04 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 10:28:08 -0400 +Subject: spi: lantiq-ssc: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Hauke Mehrtens , Mark Brown , Sasha Levin +Message-ID: <20260520142808.3647890-1-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit b99206710d032c16b7f8b75e4bc18414d8e4b9f4 ] + +Make sure to deregister the controller before releasing underlying +resources like clocks during driver unbind. + +Fixes: 17f84b793c01 ("spi: lantiq-ssc: add support for Lantiq SSC SPI controller") +Cc: stable@vger.kernel.org # 4.11 +Cc: Hauke Mehrtens +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260409120419.388546-17-johan@kernel.org +Signed-off-by: Mark Brown +[ adapted spi_controller/host naming to spi_master/master and preserved the int-returning remove() with trailing return 0 ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-lantiq-ssc.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-lantiq-ssc.c ++++ b/drivers/spi/spi-lantiq-ssc.c +@@ -997,7 +997,7 @@ static int lantiq_ssc_probe(struct platf + "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n", + revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma); + +- err = devm_spi_register_master(dev, master); ++ err = spi_register_master(master); + if (err) { + dev_err(dev, "failed to register spi_master\n"); + goto err_wq_destroy; +@@ -1021,6 +1021,10 @@ static int lantiq_ssc_remove(struct plat + { + struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev); + ++ spi_master_get(spi->master); ++ ++ spi_unregister_master(spi->master); ++ + lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN); + lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC); + rx_fifo_flush(spi); +@@ -1031,6 +1035,8 @@ static int lantiq_ssc_remove(struct plat + clk_disable_unprepare(spi->spi_clk); + clk_put(spi->fpi_clk); + ++ spi_master_put(spi->master); ++ + return 0; + } + diff --git a/queue-6.1/spi-microchip-core-qspi-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-microchip-core-qspi-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..d66cc3689e --- /dev/null +++ b/queue-6.1/spi-microchip-core-qspi-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,63 @@ +From stable+bounces-247278-greg=kroah.com@vger.kernel.org Fri May 15 00:22:58 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 14:50:12 -0400 +Subject: spi: microchip-core-qspi: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Conor Dooley" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260514185014.948789-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit e4cf312d6db2941b8267de6e094312afc1b523ee ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20230303172041.2103336-37-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: e6464140d439 ("spi: microchip-core-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-microchip-core-qspi.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-microchip-core-qspi.c ++++ b/drivers/spi/spi-microchip-core-qspi.c +@@ -567,7 +567,7 @@ out: + return ret; + } + +-static int mchp_coreqspi_remove(struct platform_device *pdev) ++static void mchp_coreqspi_remove(struct platform_device *pdev) + { + struct mchp_coreqspi *qspi = platform_get_drvdata(pdev); + u32 control = readl_relaxed(qspi->regs + REG_CONTROL); +@@ -576,8 +576,6 @@ static int mchp_coreqspi_remove(struct p + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); + clk_disable_unprepare(qspi->clk); +- +- return 0; + } + + static const struct of_device_id mchp_coreqspi_of_match[] = { +@@ -592,7 +590,7 @@ static struct platform_driver mchp_coreq + .name = "microchip,coreqspi", + .of_match_table = mchp_coreqspi_of_match, + }, +- .remove = mchp_coreqspi_remove, ++ .remove_new = mchp_coreqspi_remove, + }; + module_platform_driver(mchp_coreqspi_driver); + diff --git a/queue-6.1/spi-microchip-core-qspi-fix-controller-deregistration.patch b/queue-6.1/spi-microchip-core-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..a6140420c1 --- /dev/null +++ b/queue-6.1/spi-microchip-core-qspi-fix-controller-deregistration.patch @@ -0,0 +1,64 @@ +From stable+bounces-247280-greg=kroah.com@vger.kernel.org Fri May 15 00:20:22 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 14:50:14 -0400 +Subject: spi: microchip-core-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Naga Sureshkumar Relli , Conor Dooley , Mark Brown , Sasha Levin +Message-ID: <20260514185014.948789-3-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit e6464140d439f2d42f072eb422a5b1fec470c5a6 ] + +Make sure to deregister the controller before disabling underlying +resources like interrupts during driver unbind. + +Fixes: 8596124c4c1b ("spi: microchip-core-qspi: Add support for microchip fpga qspi controllers") +Cc: stable@vger.kernel.org # 6.1 +Cc: Naga Sureshkumar Relli +Signed-off-by: Johan Hovold +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409120419.388546-19-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-microchip-core-qspi.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-microchip-core-qspi.c ++++ b/drivers/spi/spi-microchip-core-qspi.c +@@ -512,7 +512,7 @@ static int mchp_coreqspi_probe(struct pl + "unable to allocate master for QSPI controller\n"); + + qspi = spi_controller_get_devdata(ctlr); +- platform_set_drvdata(pdev, qspi); ++ platform_set_drvdata(pdev, ctlr); + + qspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qspi->regs)) +@@ -545,7 +545,7 @@ static int mchp_coreqspi_probe(struct pl + SPI_TX_DUAL | SPI_TX_QUAD; + ctlr->dev.of_node = np; + +- ret = devm_spi_register_controller(&pdev->dev, ctlr); ++ ret = spi_register_controller(ctlr); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "spi_register_controller failed\n"); +@@ -555,9 +555,13 @@ static int mchp_coreqspi_probe(struct pl + + static void mchp_coreqspi_remove(struct platform_device *pdev) + { +- struct mchp_coreqspi *qspi = platform_get_drvdata(pdev); +- u32 control = readl_relaxed(qspi->regs + REG_CONTROL); ++ struct spi_controller *ctlr = platform_get_drvdata(pdev); ++ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr); ++ u32 control; + ++ spi_unregister_controller(ctlr); ++ ++ control = readl_relaxed(qspi->regs + REG_CONTROL); + mchp_coreqspi_disable_ints(qspi); + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); diff --git a/queue-6.1/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch b/queue-6.1/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..22e7aebbca --- /dev/null +++ b/queue-6.1/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch @@ -0,0 +1,96 @@ +From stable+bounces-247279-greg=kroah.com@vger.kernel.org Fri May 15 00:23:01 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 14:50:13 -0400 +Subject: spi: microchip-core-qspi: Use helper function devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Li Zetao , Jonathan Cameron , Mark Brown , Sasha Levin +Message-ID: <20260514185014.948789-2-sashal@kernel.org> + +From: Li Zetao + +[ Upstream commit e922f3fff21445117e9196bd8e940ad8e15ca8c7 ] + +Since commit 7ef9651e9792 ("clk: Provide new devm_clk helpers for prepared +and enabled clocks"), devm_clk_get() and clk_prepare_enable() can now be +replaced by devm_clk_get_enabled() when driver enables (and possibly +prepares) the clocks for the whole lifetime of the device. Moreover, it is +no longer necessary to unprepare and disable the clocks explicitly. + +Reviewed-by: Jonathan Cameron +Signed-off-by: Li Zetao +Link: https://lore.kernel.org/r/20230823133938.1359106-18-lizetao1@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: e6464140d439 ("spi: microchip-core-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-microchip-core-qspi.c | 29 +++++++---------------------- + 1 file changed, 7 insertions(+), 22 deletions(-) + +--- a/drivers/spi/spi-microchip-core-qspi.c ++++ b/drivers/spi/spi-microchip-core-qspi.c +@@ -519,30 +519,23 @@ static int mchp_coreqspi_probe(struct pl + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs), + "failed to map registers\n"); + +- qspi->clk = devm_clk_get(&pdev->dev, NULL); ++ qspi->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(qspi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk), + "could not get clock\n"); + +- ret = clk_prepare_enable(qspi->clk); +- if (ret) +- return dev_err_probe(&pdev->dev, ret, +- "failed to enable clock\n"); +- + init_completion(&qspi->data_completion); + mutex_init(&qspi->op_lock); + + qspi->irq = platform_get_irq(pdev, 0); +- if (qspi->irq < 0) { +- ret = qspi->irq; +- goto out; +- } ++ if (qspi->irq < 0) ++ return qspi->irq; + + ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr, + IRQF_SHARED, pdev->name, qspi); + if (ret) { + dev_err(&pdev->dev, "request_irq failed %d\n", ret); +- goto out; ++ return ret; + } + + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); +@@ -553,18 +546,11 @@ static int mchp_coreqspi_probe(struct pl + ctlr->dev.of_node = np; + + ret = devm_spi_register_controller(&pdev->dev, ctlr); +- if (ret) { +- dev_err_probe(&pdev->dev, ret, +- "spi_register_controller failed\n"); +- goto out; +- } ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "spi_register_controller failed\n"); + + return 0; +- +-out: +- clk_disable_unprepare(qspi->clk); +- +- return ret; + } + + static void mchp_coreqspi_remove(struct platform_device *pdev) +@@ -575,7 +561,6 @@ static void mchp_coreqspi_remove(struct + mchp_coreqspi_disable_ints(qspi); + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); +- clk_disable_unprepare(qspi->clk); + } + + static const struct of_device_id mchp_coreqspi_of_match[] = { diff --git a/queue-6.1/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-6.1/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch new file mode 100644 index 0000000000..bfd719d300 --- /dev/null +++ b/queue-6.1/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch @@ -0,0 +1,47 @@ +From stable+bounces-259389-greg=kroah.com@vger.kernel.org Mon Jun 1 06:10:47 2026 +From: Sasha Levin +Date: Sun, 31 May 2026 20:38:30 -0400 +Subject: spi: qup: fix error pointer deref after DMA setup failure +To: stable@vger.kernel.org +Cc: Johan Hovold , Mark Brown , Sasha Levin +Message-ID: <20260601003830.82222-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit a7e8f3efd50a165ba0189f6dc57f7e51a7d149db ] + +The driver falls back to PIO mode if DMA setup fails during probe. + +Make sure to the clear the DMA channel pointers on setup failure to +avoid dereferencing an error pointer (or attempting to release a channel +a second time) on later probe errors or driver unbind. + +This issue was flagged by Sashiko when reviewing a devres allocation +conversion patch. + +Fixes: 612762e82ae6 ("spi: qup: Add DMA capabilities") +Link: https://sashiko.dev/#/patchset/20260505072909.618363-1-johan%40kernel.org?part=4 +Cc: stable@vger.kernel.org # 4.1 +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260512074334.914735-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-qup.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/spi/spi-qup.c ++++ b/drivers/spi/spi-qup.c +@@ -968,8 +968,11 @@ static int spi_qup_init_dma(struct spi_c + + err: + dma_release_channel(host->dma_tx); ++ host->dma_tx = NULL; + err_tx: + dma_release_channel(host->dma_rx); ++ host->dma_rx = NULL; ++ + return ret; + } + diff --git a/queue-6.1/spi-qup-switch-to-use-modern-name.patch b/queue-6.1/spi-qup-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..ef4d0d7db8 --- /dev/null +++ b/queue-6.1/spi-qup-switch-to-use-modern-name.patch @@ -0,0 +1,463 @@ +From stable+bounces-259390-greg=kroah.com@vger.kernel.org Mon Jun 1 06:10:48 2026 +From: Sasha Levin +Date: Sun, 31 May 2026 20:38:29 -0400 +Subject: spi: qup: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260601003830.82222-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 597442ff4f6226206b7cc28b86eb2be0ae9c6418 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://lore.kernel.org/r/20230818093154.1183529-10-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: a7e8f3efd50a ("spi: qup: fix error pointer deref after DMA setup failure") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-qup.c | 168 +++++++++++++++++++++++++------------------------- + 1 file changed, 84 insertions(+), 84 deletions(-) + +--- a/drivers/spi/spi-qup.c ++++ b/drivers/spi/spi-qup.c +@@ -386,20 +386,20 @@ static void spi_qup_write(struct spi_qup + } while (remainder); + } + +-static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl, ++static int spi_qup_prep_sg(struct spi_controller *host, struct scatterlist *sgl, + unsigned int nents, enum dma_transfer_direction dir, + dma_async_tx_callback callback) + { +- struct spi_qup *qup = spi_master_get_devdata(master); ++ struct spi_qup *qup = spi_controller_get_devdata(host); + unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE; + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan; + dma_cookie_t cookie; + + if (dir == DMA_MEM_TO_DEV) +- chan = master->dma_tx; ++ chan = host->dma_tx; + else +- chan = master->dma_rx; ++ chan = host->dma_rx; + + desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); + if (IS_ERR_OR_NULL(desc)) +@@ -413,13 +413,13 @@ static int spi_qup_prep_sg(struct spi_ma + return dma_submit_error(cookie); + } + +-static void spi_qup_dma_terminate(struct spi_master *master, ++static void spi_qup_dma_terminate(struct spi_controller *host, + struct spi_transfer *xfer) + { + if (xfer->tx_buf) +- dmaengine_terminate_all(master->dma_tx); ++ dmaengine_terminate_all(host->dma_tx); + if (xfer->rx_buf) +- dmaengine_terminate_all(master->dma_rx); ++ dmaengine_terminate_all(host->dma_rx); + } + + static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max, +@@ -446,8 +446,8 @@ static int spi_qup_do_dma(struct spi_dev + unsigned long timeout) + { + dma_async_tx_callback rx_done = NULL, tx_done = NULL; +- struct spi_master *master = spi->master; +- struct spi_qup *qup = spi_master_get_devdata(master); ++ struct spi_controller *host = spi->controller; ++ struct spi_qup *qup = spi_controller_get_devdata(host); + struct scatterlist *tx_sgl, *rx_sgl; + int ret; + +@@ -482,20 +482,20 @@ static int spi_qup_do_dma(struct spi_dev + return ret; + } + if (rx_sgl) { +- ret = spi_qup_prep_sg(master, rx_sgl, rx_nents, ++ ret = spi_qup_prep_sg(host, rx_sgl, rx_nents, + DMA_DEV_TO_MEM, rx_done); + if (ret) + return ret; +- dma_async_issue_pending(master->dma_rx); ++ dma_async_issue_pending(host->dma_rx); + } + + if (tx_sgl) { +- ret = spi_qup_prep_sg(master, tx_sgl, tx_nents, ++ ret = spi_qup_prep_sg(host, tx_sgl, tx_nents, + DMA_MEM_TO_DEV, tx_done); + if (ret) + return ret; + +- dma_async_issue_pending(master->dma_tx); ++ dma_async_issue_pending(host->dma_tx); + } + + if (!wait_for_completion_timeout(&qup->done, timeout)) +@@ -514,8 +514,8 @@ static int spi_qup_do_dma(struct spi_dev + static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, + unsigned long timeout) + { +- struct spi_master *master = spi->master; +- struct spi_qup *qup = spi_master_get_devdata(master); ++ struct spi_controller *host = spi->controller; ++ struct spi_qup *qup = spi_controller_get_devdata(host); + int ret, n_words, iterations, offset = 0; + + n_words = qup->n_words; +@@ -659,7 +659,7 @@ static irqreturn_t spi_qup_qup_irq(int i + /* set clock freq ... bits per word, determine mode */ + static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer) + { +- struct spi_qup *controller = spi_master_get_devdata(spi->master); ++ struct spi_qup *controller = spi_controller_get_devdata(spi->controller); + int ret; + + if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { +@@ -680,9 +680,9 @@ static int spi_qup_io_prep(struct spi_de + + if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32))) + controller->mode = QUP_IO_M_MODE_FIFO; +- else if (spi->master->can_dma && +- spi->master->can_dma(spi->master, spi, xfer) && +- spi->master->cur_msg_mapped) ++ else if (spi->controller->can_dma && ++ spi->controller->can_dma(spi->controller, spi, xfer) && ++ spi->controller->cur_msg_mapped) + controller->mode = QUP_IO_M_MODE_BAM; + else + controller->mode = QUP_IO_M_MODE_BLOCK; +@@ -693,7 +693,7 @@ static int spi_qup_io_prep(struct spi_de + /* prep qup for another spi transaction of specific type */ + static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) + { +- struct spi_qup *controller = spi_master_get_devdata(spi->master); ++ struct spi_qup *controller = spi_controller_get_devdata(spi->controller); + u32 config, iomode, control; + unsigned long flags; + +@@ -841,11 +841,11 @@ static int spi_qup_io_config(struct spi_ + return 0; + } + +-static int spi_qup_transfer_one(struct spi_master *master, ++static int spi_qup_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + unsigned long timeout, flags; + int ret; + +@@ -879,21 +879,21 @@ static int spi_qup_transfer_one(struct s + spin_unlock_irqrestore(&controller->lock, flags); + + if (ret && spi_qup_is_dma_xfer(controller->mode)) +- spi_qup_dma_terminate(master, xfer); ++ spi_qup_dma_terminate(host, xfer); + + return ret; + } + +-static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi, ++static bool spi_qup_can_dma(struct spi_controller *host, struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct spi_qup *qup = spi_master_get_devdata(master); ++ struct spi_qup *qup = spi_controller_get_devdata(host); + size_t dma_align = dma_get_cache_alignment(); + int n_words; + + if (xfer->rx_buf) { + if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) || +- IS_ERR_OR_NULL(master->dma_rx)) ++ IS_ERR_OR_NULL(host->dma_rx)) + return false; + if (qup->qup_v1 && (xfer->len % qup->in_blk_sz)) + return false; +@@ -901,7 +901,7 @@ static bool spi_qup_can_dma(struct spi_m + + if (xfer->tx_buf) { + if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) || +- IS_ERR_OR_NULL(master->dma_tx)) ++ IS_ERR_OR_NULL(host->dma_tx)) + return false; + if (qup->qup_v1 && (xfer->len % qup->out_blk_sz)) + return false; +@@ -914,30 +914,30 @@ static bool spi_qup_can_dma(struct spi_m + return true; + } + +-static void spi_qup_release_dma(struct spi_master *master) ++static void spi_qup_release_dma(struct spi_controller *host) + { +- if (!IS_ERR_OR_NULL(master->dma_rx)) +- dma_release_channel(master->dma_rx); +- if (!IS_ERR_OR_NULL(master->dma_tx)) +- dma_release_channel(master->dma_tx); ++ if (!IS_ERR_OR_NULL(host->dma_rx)) ++ dma_release_channel(host->dma_rx); ++ if (!IS_ERR_OR_NULL(host->dma_tx)) ++ dma_release_channel(host->dma_tx); + } + +-static int spi_qup_init_dma(struct spi_master *master, resource_size_t base) ++static int spi_qup_init_dma(struct spi_controller *host, resource_size_t base) + { +- struct spi_qup *spi = spi_master_get_devdata(master); ++ struct spi_qup *spi = spi_controller_get_devdata(host); + struct dma_slave_config *rx_conf = &spi->rx_conf, + *tx_conf = &spi->tx_conf; + struct device *dev = spi->dev; + int ret; + + /* allocate dma resources, if available */ +- master->dma_rx = dma_request_chan(dev, "rx"); +- if (IS_ERR(master->dma_rx)) +- return PTR_ERR(master->dma_rx); +- +- master->dma_tx = dma_request_chan(dev, "tx"); +- if (IS_ERR(master->dma_tx)) { +- ret = PTR_ERR(master->dma_tx); ++ host->dma_rx = dma_request_chan(dev, "rx"); ++ if (IS_ERR(host->dma_rx)) ++ return PTR_ERR(host->dma_rx); ++ ++ host->dma_tx = dma_request_chan(dev, "tx"); ++ if (IS_ERR(host->dma_tx)) { ++ ret = PTR_ERR(host->dma_tx); + goto err_tx; + } + +@@ -952,13 +952,13 @@ static int spi_qup_init_dma(struct spi_m + tx_conf->dst_addr = base + QUP_OUTPUT_FIFO; + tx_conf->dst_maxburst = spi->out_blk_sz; + +- ret = dmaengine_slave_config(master->dma_rx, rx_conf); ++ ret = dmaengine_slave_config(host->dma_rx, rx_conf); + if (ret) { + dev_err(dev, "failed to configure RX channel\n"); + goto err; + } + +- ret = dmaengine_slave_config(master->dma_tx, tx_conf); ++ ret = dmaengine_slave_config(host->dma_tx, tx_conf); + if (ret) { + dev_err(dev, "failed to configure TX channel\n"); + goto err; +@@ -967,9 +967,9 @@ static int spi_qup_init_dma(struct spi_m + return 0; + + err: +- dma_release_channel(master->dma_tx); ++ dma_release_channel(host->dma_tx); + err_tx: +- dma_release_channel(master->dma_rx); ++ dma_release_channel(host->dma_rx); + return ret; + } + +@@ -979,7 +979,7 @@ static void spi_qup_set_cs(struct spi_de + u32 spi_ioc; + u32 spi_ioc_orig; + +- controller = spi_master_get_devdata(spi->master); ++ controller = spi_controller_get_devdata(spi->controller); + spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL); + spi_ioc_orig = spi_ioc; + if (!val) +@@ -993,7 +993,7 @@ static void spi_qup_set_cs(struct spi_de + + static int spi_qup_probe(struct platform_device *pdev) + { +- struct spi_master *master; ++ struct spi_controller *host; + struct clk *iclk, *cclk; + struct spi_qup *controller; + struct resource *res; +@@ -1029,34 +1029,34 @@ static int spi_qup_probe(struct platform + return -ENXIO; + } + +- master = spi_alloc_master(dev, sizeof(struct spi_qup)); +- if (!master) { +- dev_err(dev, "cannot allocate master\n"); ++ host = spi_alloc_host(dev, sizeof(struct spi_qup)); ++ if (!host) { ++ dev_err(dev, "cannot allocate host\n"); + return -ENOMEM; + } + + /* use num-cs unless not present or out of range */ + if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) || + num_cs > SPI_NUM_CHIPSELECTS) +- master->num_chipselect = SPI_NUM_CHIPSELECTS; ++ host->num_chipselect = SPI_NUM_CHIPSELECTS; + else +- master->num_chipselect = num_cs; ++ host->num_chipselect = num_cs; + +- master->use_gpio_descriptors = true; +- master->max_native_cs = SPI_NUM_CHIPSELECTS; +- master->bus_num = pdev->id; +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; +- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); +- master->max_speed_hz = max_freq; +- master->transfer_one = spi_qup_transfer_one; +- master->dev.of_node = pdev->dev.of_node; +- master->auto_runtime_pm = true; +- master->dma_alignment = dma_get_cache_alignment(); +- master->max_dma_len = SPI_MAX_XFER; ++ host->use_gpio_descriptors = true; ++ host->max_native_cs = SPI_NUM_CHIPSELECTS; ++ host->bus_num = pdev->id; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; ++ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); ++ host->max_speed_hz = max_freq; ++ host->transfer_one = spi_qup_transfer_one; ++ host->dev.of_node = pdev->dev.of_node; ++ host->auto_runtime_pm = true; ++ host->dma_alignment = dma_get_cache_alignment(); ++ host->max_dma_len = SPI_MAX_XFER; + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- controller = spi_master_get_devdata(master); ++ controller = spi_controller_get_devdata(host); + + controller->dev = dev; + controller->base = base; +@@ -1064,16 +1064,16 @@ static int spi_qup_probe(struct platform + controller->cclk = cclk; + controller->irq = irq; + +- ret = spi_qup_init_dma(master, res->start); ++ ret = spi_qup_init_dma(host, res->start); + if (ret == -EPROBE_DEFER) + goto error; + else if (!ret) +- master->can_dma = spi_qup_can_dma; ++ host->can_dma = spi_qup_can_dma; + + controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev); + + if (!controller->qup_v1) +- master->set_cs = spi_qup_set_cs; ++ host->set_cs = spi_qup_set_cs; + + spin_lock_init(&controller->lock); + init_completion(&controller->done); +@@ -1151,7 +1151,7 @@ static int spi_qup_probe(struct platform + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + +- ret = devm_spi_register_master(dev, master); ++ ret = devm_spi_register_controller(dev, host); + if (ret) + goto disable_pm; + +@@ -1163,17 +1163,17 @@ error_clk: + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + error_dma: +- spi_qup_release_dma(master); ++ spi_qup_release_dma(host); + error: +- spi_master_put(master); ++ spi_controller_put(host); + return ret; + } + + #ifdef CONFIG_PM + static int spi_qup_pm_suspend_runtime(struct device *device) + { +- struct spi_master *master = dev_get_drvdata(device); +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(device); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + u32 config; + + /* Enable clocks auto gaiting */ +@@ -1189,8 +1189,8 @@ static int spi_qup_pm_suspend_runtime(st + + static int spi_qup_pm_resume_runtime(struct device *device) + { +- struct spi_master *master = dev_get_drvdata(device); +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(device); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + u32 config; + int ret; + +@@ -1215,8 +1215,8 @@ static int spi_qup_pm_resume_runtime(str + #ifdef CONFIG_PM_SLEEP + static int spi_qup_suspend(struct device *device) + { +- struct spi_master *master = dev_get_drvdata(device); +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(device); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + int ret; + + if (pm_runtime_suspended(device)) { +@@ -1224,7 +1224,7 @@ static int spi_qup_suspend(struct device + if (ret) + return ret; + } +- ret = spi_master_suspend(master); ++ ret = spi_controller_suspend(host); + if (ret) + return ret; + +@@ -1239,8 +1239,8 @@ static int spi_qup_suspend(struct device + + static int spi_qup_resume(struct device *device) + { +- struct spi_master *master = dev_get_drvdata(device); +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(device); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + int ret; + + ret = clk_prepare_enable(controller->iclk); +@@ -1257,7 +1257,7 @@ static int spi_qup_resume(struct device + if (ret) + goto disable_clk; + +- ret = spi_master_resume(master); ++ ret = spi_controller_resume(host); + if (ret) + goto disable_clk; + +@@ -1272,8 +1272,8 @@ disable_clk: + + static int spi_qup_remove(struct platform_device *pdev) + { +- struct spi_master *master = dev_get_drvdata(&pdev->dev); +- struct spi_qup *controller = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(&pdev->dev); ++ struct spi_qup *controller = spi_controller_get_devdata(host); + int ret; + + ret = pm_runtime_get_sync(&pdev->dev); +@@ -1291,7 +1291,7 @@ static int spi_qup_remove(struct platfor + ERR_PTR(ret)); + } + +- spi_qup_release_dma(master); ++ spi_qup_release_dma(host); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); diff --git a/queue-6.1/spi-s3c64xx-fix-null-deref-on-driver-unbind.patch b/queue-6.1/spi-s3c64xx-fix-null-deref-on-driver-unbind.patch new file mode 100644 index 0000000000..c86faf5bba --- /dev/null +++ b/queue-6.1/spi-s3c64xx-fix-null-deref-on-driver-unbind.patch @@ -0,0 +1,49 @@ +From stable+bounces-247118-greg=kroah.com@vger.kernel.org Thu May 14 10:51:05 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 01:20:32 -0400 +Subject: spi: s3c64xx: fix NULL-deref on driver unbind +To: stable@vger.kernel.org +Cc: Johan Hovold , Adithya K V , Mark Brown , Sasha Levin +Message-ID: <20260514052032.41196-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 45daacbead8a009844bd5dba6cfa731332184d17 ] + +A change moving DMA channel allocation from probe() back to +s3c64xx_spi_prepare_transfer() failed to remove the corresponding +deallocation from remove(). + +Drop the bogus DMA channel release from remove() to avoid triggering a +NULL-pointer dereference on driver unbind. + +This issue was flagged by Sashiko when reviewing a controller +deregistration fix. + +Fixes: f52b03c70744 ("spi: s3c64xx: requests spi-dma channel only during data transfer") +Cc: stable@vger.kernel.org # 6.0 +Cc: Adithya K V +Link: https://sashiko.dev/#/patchset/20260410081757.503099-1-johan%40kernel.org +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410094925.518343-1-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-s3c64xx.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/drivers/spi/spi-s3c64xx.c ++++ b/drivers/spi/spi-s3c64xx.c +@@ -1274,11 +1274,6 @@ static int s3c64xx_spi_remove(struct pla + + writel(0, sdd->regs + S3C64XX_SPI_INT_EN); + +- if (!is_polling(sdd)) { +- dma_release_channel(sdd->rx_dma.ch); +- dma_release_channel(sdd->tx_dma.ch); +- } +- + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); diff --git a/queue-6.1/spi-s3c64xx-use-devm_clk_get_enabled.patch b/queue-6.1/spi-s3c64xx-use-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..49fd95262c --- /dev/null +++ b/queue-6.1/spi-s3c64xx-use-devm_clk_get_enabled.patch @@ -0,0 +1,104 @@ +From stable+bounces-247117-greg=kroah.com@vger.kernel.org Thu May 14 10:50:39 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 01:20:31 -0400 +Subject: spi: s3c64xx: Use devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Andi Shyti , Mark Brown , Sasha Levin +Message-ID: <20260514052032.41196-1-sashal@kernel.org> + +From: Andi Shyti + +[ Upstream commit 20c475d21ed9326f7b1396c9bb8991b375cb6c50 ] + +Replace the tuple devm_clk_get()/clk_prepare_enable() with the +single function devm_clk_get_enabled(). + +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20230531205550.568340-1-andi.shyti@kernel.org +Signed-off-by: Mark Brown +Stable-dep-of: 45daacbead8a ("spi: s3c64xx: fix NULL-deref on driver unbind") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-s3c64xx.c | 39 +++++---------------------------------- + 1 file changed, 5 insertions(+), 34 deletions(-) + +--- a/drivers/spi/spi-s3c64xx.c ++++ b/drivers/spi/spi-s3c64xx.c +@@ -1189,46 +1189,28 @@ static int s3c64xx_spi_probe(struct plat + } + + /* Setup clocks */ +- sdd->clk = devm_clk_get(&pdev->dev, "spi"); ++ sdd->clk = devm_clk_get_enabled(&pdev->dev, "spi"); + if (IS_ERR(sdd->clk)) { + dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n"); + ret = PTR_ERR(sdd->clk); + goto err_deref_master; + } + +- ret = clk_prepare_enable(sdd->clk); +- if (ret) { +- dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n"); +- goto err_deref_master; +- } +- + sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr); +- sdd->src_clk = devm_clk_get(&pdev->dev, clk_name); ++ sdd->src_clk = devm_clk_get_enabled(&pdev->dev, clk_name); + if (IS_ERR(sdd->src_clk)) { + dev_err(&pdev->dev, + "Unable to acquire clock '%s'\n", clk_name); + ret = PTR_ERR(sdd->src_clk); +- goto err_disable_clk; +- } +- +- ret = clk_prepare_enable(sdd->src_clk); +- if (ret) { +- dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name); +- goto err_disable_clk; ++ goto err_deref_master; + } + + if (sdd->port_conf->clk_ioclk) { +- sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk"); ++ sdd->ioclk = devm_clk_get_enabled(&pdev->dev, "spi_ioclk"); + if (IS_ERR(sdd->ioclk)) { + dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n"); + ret = PTR_ERR(sdd->ioclk); +- goto err_disable_src_clk; +- } +- +- ret = clk_prepare_enable(sdd->ioclk); +- if (ret) { +- dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n"); +- goto err_disable_src_clk; ++ goto err_deref_master; + } + } + +@@ -1277,11 +1259,6 @@ err_pm_put: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + +- clk_disable_unprepare(sdd->ioclk); +-err_disable_src_clk: +- clk_disable_unprepare(sdd->src_clk); +-err_disable_clk: +- clk_disable_unprepare(sdd->clk); + err_deref_master: + spi_master_put(master); + +@@ -1302,12 +1279,6 @@ static int s3c64xx_spi_remove(struct pla + dma_release_channel(sdd->tx_dma.ch); + } + +- clk_disable_unprepare(sdd->ioclk); +- +- clk_disable_unprepare(sdd->src_clk); +- +- clk_disable_unprepare(sdd->clk); +- + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); diff --git a/queue-6.1/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..dc269c1eff --- /dev/null +++ b/queue-6.1/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,76 @@ +From stable+bounces-247004-greg=kroah.com@vger.kernel.org Wed May 13 23:56:55 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:15 -0400 +Subject: spi: spi-ti-qspi: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513182017.3918352-2-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 2f2802d1a59d79a3d00cb429841db502c2bbc3df ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. + +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new(), which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Add an error message to the error path that returned an error before to +replace the core's error message with more information. Apart from the +different wording of the error message, this patch doesn't introduce a +semantic difference. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20231105172649.3738556-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -909,21 +909,22 @@ free_master: + return ret; + } + +-static int ti_qspi_remove(struct platform_device *pdev) ++static void ti_qspi_remove(struct platform_device *pdev) + { + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int rc; + + rc = spi_master_suspend(qspi->master); +- if (rc) +- return rc; ++ if (rc) { ++ dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n", ++ ERR_PTR(rc)); ++ return; ++ } + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + ti_qspi_dma_cleanup(qspi); +- +- return 0; + } + + static const struct dev_pm_ops ti_qspi_pm_ops = { +@@ -932,7 +933,7 @@ static const struct dev_pm_ops ti_qspi_p + + static struct platform_driver ti_qspi_driver = { + .probe = ti_qspi_probe, +- .remove = ti_qspi_remove, ++ .remove_new = ti_qspi_remove, + .driver = { + .name = "ti-qspi", + .pm = &ti_qspi_pm_ops, diff --git a/queue-6.1/spi-spi-ti-qspi-switch-to-use-modern-name.patch b/queue-6.1/spi-spi-ti-qspi-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..ad8fe45d7c --- /dev/null +++ b/queue-6.1/spi-spi-ti-qspi-switch-to-use-modern-name.patch @@ -0,0 +1,293 @@ +From stable+bounces-247005-greg=kroah.com@vger.kernel.org Wed May 13 23:56:59 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:16 -0400 +Subject: spi: spi-ti-qspi: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513182017.3918352-3-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 9d93c8d97b4cdb5edddb4c5530881c90eecb7e44 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-16-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 88 +++++++++++++++++++++++----------------------- + 1 file changed, 44 insertions(+), 44 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -41,7 +41,7 @@ struct ti_qspi { + /* list synchronization */ + struct mutex list_lock; + +- struct spi_master *master; ++ struct spi_controller *host; + void __iomem *base; + void __iomem *mmap_base; + size_t mmap_size; +@@ -138,20 +138,20 @@ static inline void ti_qspi_write(struct + + static int ti_qspi_setup(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + int ret; + +- if (spi->master->busy) { +- dev_dbg(qspi->dev, "master busy doing other transfers\n"); ++ if (spi->controller->busy) { ++ dev_dbg(qspi->dev, "host busy doing other transfers\n"); + return -EBUSY; + } + +- if (!qspi->master->max_speed_hz) { ++ if (!qspi->host->max_speed_hz) { + dev_err(qspi->dev, "spi max frequency not defined\n"); + return -EINVAL; + } + +- spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz); ++ spi->max_speed_hz = min(spi->max_speed_hz, qspi->host->max_speed_hz); + + ret = pm_runtime_resume_and_get(qspi->dev); + if (ret < 0) { +@@ -527,7 +527,7 @@ static int ti_qspi_dma_xfer_sg(struct ti + + static void ti_qspi_enable_memory_map(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) { +@@ -541,7 +541,7 @@ static void ti_qspi_enable_memory_map(st + + static void ti_qspi_disable_memory_map(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) +@@ -555,7 +555,7 @@ static void ti_qspi_setup_mmap_read(stru + u8 data_nbits, u8 addr_width, + u8 dummy_bytes) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + u32 memval = opcode; + + switch (data_nbits) { +@@ -577,7 +577,7 @@ static void ti_qspi_setup_mmap_read(stru + + static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) + { +- struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller); + size_t max_len; + + if (op->data.dir == SPI_MEM_DATA_IN) { +@@ -607,7 +607,7 @@ static int ti_qspi_adjust_op_size(struct + static int ti_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +- struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller); + u32 from = 0; + int ret = 0; + +@@ -634,10 +634,10 @@ static int ti_qspi_exec_mem_op(struct sp + struct sg_table sgt; + + if (virt_addr_valid(op->data.buf.in) && +- !spi_controller_dma_map_mem_op_data(mem->spi->master, op, ++ !spi_controller_dma_map_mem_op_data(mem->spi->controller, op, + &sgt)) { + ret = ti_qspi_dma_xfer_sg(qspi, sgt, from); +- spi_controller_dma_unmap_mem_op_data(mem->spi->master, ++ spi_controller_dma_unmap_mem_op_data(mem->spi->controller, + op, &sgt); + } else { + ret = ti_qspi_dma_bounce_buffer(qspi, from, +@@ -659,10 +659,10 @@ static const struct spi_controller_mem_o + .adjust_op_size = ti_qspi_adjust_op_size, + }; + +-static int ti_qspi_start_transfer_one(struct spi_master *master, ++static int ti_qspi_start_transfer_one(struct spi_controller *host, + struct spi_message *m) + { +- struct ti_qspi *qspi = spi_master_get_devdata(master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(host); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + int status = 0, ret; +@@ -721,7 +721,7 @@ static int ti_qspi_start_transfer_one(st + + ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); + m->status = status; +- spi_finalize_current_message(master); ++ spi_finalize_current_message(host); + + return status; + } +@@ -757,33 +757,33 @@ MODULE_DEVICE_TABLE(of, ti_qspi_match); + static int ti_qspi_probe(struct platform_device *pdev) + { + struct ti_qspi *qspi; +- struct spi_master *master; ++ struct spi_controller *host; + struct resource *r, *res_mmap; + struct device_node *np = pdev->dev.of_node; + u32 max_freq; + int ret = 0, num_cs, irq; + dma_cap_mask_t mask; + +- master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*qspi)); ++ if (!host) + return -ENOMEM; + +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; + +- master->flags = SPI_CONTROLLER_HALF_DUPLEX; +- master->setup = ti_qspi_setup; +- master->auto_runtime_pm = true; +- master->transfer_one_message = ti_qspi_start_transfer_one; +- master->dev.of_node = pdev->dev.of_node; +- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | +- SPI_BPW_MASK(8); +- master->mem_ops = &ti_qspi_mem_ops; ++ host->flags = SPI_CONTROLLER_HALF_DUPLEX; ++ host->setup = ti_qspi_setup; ++ host->auto_runtime_pm = true; ++ host->transfer_one_message = ti_qspi_start_transfer_one; ++ host->dev.of_node = pdev->dev.of_node; ++ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | ++ SPI_BPW_MASK(8); ++ host->mem_ops = &ti_qspi_mem_ops; + + if (!of_property_read_u32(np, "num-cs", &num_cs)) +- master->num_chipselect = num_cs; ++ host->num_chipselect = num_cs; + +- qspi = spi_master_get_devdata(master); +- qspi->master = master; ++ qspi = spi_controller_get_devdata(host); ++ qspi->host = host; + qspi->dev = &pdev->dev; + platform_set_drvdata(pdev, qspi); + +@@ -793,7 +793,7 @@ static int ti_qspi_probe(struct platform + if (r == NULL) { + dev_err(&pdev->dev, "missing platform data\n"); + ret = -ENODEV; +- goto free_master; ++ goto free_host; + } + } + +@@ -813,7 +813,7 @@ static int ti_qspi_probe(struct platform + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; +- goto free_master; ++ goto free_host; + } + + mutex_init(&qspi->list_lock); +@@ -821,7 +821,7 @@ static int ti_qspi_probe(struct platform + qspi->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(qspi->base)) { + ret = PTR_ERR(qspi->base); +- goto free_master; ++ goto free_host; + } + + +@@ -831,7 +831,7 @@ static int ti_qspi_probe(struct platform + "syscon-chipselects"); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); +- goto free_master; ++ goto free_host; + } + ret = of_property_read_u32_index(np, + "syscon-chipselects", +@@ -839,7 +839,7 @@ static int ti_qspi_probe(struct platform + if (ret) { + dev_err(&pdev->dev, + "couldn't get ctrl_mod reg index\n"); +- goto free_master; ++ goto free_host; + } + } + +@@ -854,7 +854,7 @@ static int ti_qspi_probe(struct platform + pm_runtime_enable(&pdev->dev); + + if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) +- master->max_speed_hz = max_freq; ++ host->max_speed_hz = max_freq; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); +@@ -878,7 +878,7 @@ static int ti_qspi_probe(struct platform + qspi->rx_chan = NULL; + goto no_dma; + } +- master->dma_rx = qspi->rx_chan; ++ host->dma_rx = qspi->rx_chan; + init_completion(&qspi->transfer_complete); + if (res_mmap) + qspi->mmap_phys_base = (dma_addr_t)res_mmap->start; +@@ -891,21 +891,21 @@ no_dma: + "mmap failed with error %ld using PIO mode\n", + PTR_ERR(qspi->mmap_base)); + qspi->mmap_base = NULL; +- master->mem_ops = NULL; ++ host->mem_ops = NULL; + } + } + qspi->mmap_enabled = false; + qspi->current_cs = -1; + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (!ret) + return 0; + + ti_qspi_dma_cleanup(qspi); + + pm_runtime_disable(&pdev->dev); +-free_master: +- spi_master_put(master); ++free_host: ++ spi_controller_put(host); + return ret; + } + +@@ -914,9 +914,9 @@ static void ti_qspi_remove(struct platfo + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int rc; + +- rc = spi_master_suspend(qspi->master); ++ rc = spi_controller_suspend(qspi->host); + if (rc) { +- dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n", ++ dev_alert(&pdev->dev, "spi_controller_suspend() failed (%pe)\n", + ERR_PTR(rc)); + return; + } diff --git a/queue-6.1/spi-spi-zynq-do-not-check-for-0-return-after-calling-platform_get_irq.patch b/queue-6.1/spi-spi-zynq-do-not-check-for-0-return-after-calling-platform_get_irq.patch new file mode 100644 index 0000000000..7495040d74 --- /dev/null +++ b/queue-6.1/spi-spi-zynq-do-not-check-for-0-return-after-calling-platform_get_irq.patch @@ -0,0 +1,52 @@ +From stable+bounces-247025-greg=kroah.com@vger.kernel.org Thu May 14 01:04:27 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:17 -0400 +Subject: spi: spi-zynq: Do not check for 0 return after calling platform_get_irq() +To: stable@vger.kernel.org +Cc: Ruan Jinjie , Mark Brown , Sasha Levin +Message-ID: <20260513193420.3938432-2-sashal@kernel.org> + +From: Ruan Jinjie + +[ Upstream commit 3182d49aad5f1cd8acdcf7de0c5b651772edd32e ] + +It is not possible for platform_get_irq() to return 0. Use the +return value from platform_get_irq(). + +Signed-off-by: Ruan Jinjie +Link: https://lore.kernel.org/r/20230802094357.981100-1-ruanjinjie@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: c9c012706c9f ("spi: zynq-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 4 ++-- + drivers/spi/spi-zynqmp-gqspi.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -688,8 +688,8 @@ static int zynq_qspi_probe(struct platfo + } + + xqspi->irq = platform_get_irq(pdev, 0); +- if (xqspi->irq <= 0) { +- ret = -ENXIO; ++ if (xqspi->irq < 0) { ++ ret = xqspi->irq; + goto clk_dis_all; + } + ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq, +--- a/drivers/spi/spi-zynqmp-gqspi.c ++++ b/drivers/spi/spi-zynqmp-gqspi.c +@@ -1164,8 +1164,8 @@ static int zynqmp_qspi_probe(struct plat + zynqmp_qspi_init_hw(xqspi); + + xqspi->irq = platform_get_irq(pdev, 0); +- if (xqspi->irq <= 0) { +- ret = -ENXIO; ++ if (xqspi->irq < 0) { ++ ret = xqspi->irq; + goto clk_dis_all; + } + ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq, diff --git a/queue-6.1/spi-st-ssc4-fix-controller-deregistration.patch b/queue-6.1/spi-st-ssc4-fix-controller-deregistration.patch new file mode 100644 index 0000000000..c9947cf037 --- /dev/null +++ b/queue-6.1/spi-st-ssc4-fix-controller-deregistration.patch @@ -0,0 +1,55 @@ +From stable+bounces-249918-greg=kroah.com@vger.kernel.org Wed May 20 18:42:06 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 09:11:33 -0400 +Subject: spi: st-ssc4: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Lee Jones , Mark Brown , Sasha Levin +Message-ID: <20260520131133.3608592-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 19857374010d06ca6a2f7c2c53464122eb804df0 ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: 9e862375c542 ("spi: Add new driver for STMicroelectronics' SPI Controller") +Cc: stable@vger.kernel.org # 4.0 +Cc: Lee Jones +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-18-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-st-ssc4.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-st-ssc4.c ++++ b/drivers/spi/spi-st-ssc4.c +@@ -349,7 +349,7 @@ static int spi_st_probe(struct platform_ + + platform_set_drvdata(pdev, host); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) { + dev_err(&pdev->dev, "Failed to register host\n"); + goto rpm_disable; +@@ -371,10 +371,16 @@ static int spi_st_remove(struct platform + struct spi_controller *host = platform_get_drvdata(pdev); + struct spi_st *spi_st = spi_controller_get_devdata(host); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_disable(&pdev->dev); + + clk_disable_unprepare(spi_st->clk); + ++ spi_controller_put(host); ++ + pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; diff --git a/queue-6.1/spi-st-ssc4-switch-to-use-modern-name.patch b/queue-6.1/spi-st-ssc4-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..d227a5489f --- /dev/null +++ b/queue-6.1/spi-st-ssc4-switch-to-use-modern-name.patch @@ -0,0 +1,210 @@ +From stable+bounces-249919-greg=kroah.com@vger.kernel.org Wed May 20 18:50:13 2026 +From: Sasha Levin +Date: Wed, 20 May 2026 09:11:32 -0400 +Subject: spi: st-ssc4: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260520131133.3608592-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit e6b7e64cb11966b26646a362677ca5a08481157e ] + +Change legacy name master/slave to modern name host/target or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-4-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 19857374010d ("spi: st-ssc4: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-st-ssc4.c | 70 +++++++++++++++++++++++----------------------- + 1 file changed, 35 insertions(+), 35 deletions(-) + +--- a/drivers/spi/spi-st-ssc4.c ++++ b/drivers/spi/spi-st-ssc4.c +@@ -6,7 +6,7 @@ + * Patrice Chotard + * Lee Jones + * +- * SPI master mode controller driver, used in STMicroelectronics devices. ++ * SPI host mode controller driver, used in STMicroelectronics devices. + */ + + #include +@@ -115,10 +115,10 @@ static void ssc_read_rx_fifo(struct spi_ + spi_st->words_remaining -= count; + } + +-static int spi_st_transfer_one(struct spi_master *master, ++static int spi_st_transfer_one(struct spi_controller *host, + struct spi_device *spi, struct spi_transfer *t) + { +- struct spi_st *spi_st = spi_master_get_devdata(master); ++ struct spi_st *spi_st = spi_controller_get_devdata(host); + uint32_t ctl = 0; + + /* Setup transfer */ +@@ -165,7 +165,7 @@ static int spi_st_transfer_one(struct sp + if (ctl) + writel_relaxed(ctl, spi_st->base + SSC_CTL); + +- spi_finalize_current_transfer(spi->master); ++ spi_finalize_current_transfer(spi->controller); + + return t->len; + } +@@ -174,7 +174,7 @@ static int spi_st_transfer_one(struct sp + #define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) + static int spi_st_setup(struct spi_device *spi) + { +- struct spi_st *spi_st = spi_master_get_devdata(spi->master); ++ struct spi_st *spi_st = spi_controller_get_devdata(spi->controller); + u32 spi_st_clk, sscbrg, var; + u32 hz = spi->max_speed_hz; + +@@ -274,35 +274,35 @@ static irqreturn_t spi_st_irq(int irq, v + static int spi_st_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +- struct spi_master *master; ++ struct spi_controller *host; + struct spi_st *spi_st; + int irq, ret = 0; + u32 var; + +- master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*spi_st)); ++ if (!host) + return -ENOMEM; + +- master->dev.of_node = np; +- master->mode_bits = MODEBITS; +- master->setup = spi_st_setup; +- master->transfer_one = spi_st_transfer_one; +- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); +- master->auto_runtime_pm = true; +- master->bus_num = pdev->id; +- master->use_gpio_descriptors = true; +- spi_st = spi_master_get_devdata(master); ++ host->dev.of_node = np; ++ host->mode_bits = MODEBITS; ++ host->setup = spi_st_setup; ++ host->transfer_one = spi_st_transfer_one; ++ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); ++ host->auto_runtime_pm = true; ++ host->bus_num = pdev->id; ++ host->use_gpio_descriptors = true; ++ spi_st = spi_controller_get_devdata(host); + + spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); + if (IS_ERR(spi_st->clk)) { + dev_err(&pdev->dev, "Unable to request clock\n"); + ret = PTR_ERR(spi_st->clk); +- goto put_master; ++ goto put_host; + } + + ret = clk_prepare_enable(spi_st->clk); + if (ret) +- goto put_master; ++ goto put_host; + + init_completion(&spi_st->done); + +@@ -324,7 +324,7 @@ static int spi_st_probe(struct platform_ + var &= ~SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + +- /* Set SSC into slave mode before reconfiguring PIO pins */ ++ /* Set SSC into target mode before reconfiguring PIO pins */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_MS; + writel_relaxed(var, spi_st->base + SSC_CTL); +@@ -347,11 +347,11 @@ static int spi_st_probe(struct platform_ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) { +- dev_err(&pdev->dev, "Failed to register master\n"); ++ dev_err(&pdev->dev, "Failed to register host\n"); + goto rpm_disable; + } + +@@ -361,15 +361,15 @@ rpm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable: + clk_disable_unprepare(spi_st->clk); +-put_master: +- spi_master_put(master); ++put_host: ++ spi_controller_put(host); + return ret; + } + + static int spi_st_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); +- struct spi_st *spi_st = spi_master_get_devdata(master); ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ struct spi_st *spi_st = spi_controller_get_devdata(host); + + pm_runtime_disable(&pdev->dev); + +@@ -383,8 +383,8 @@ static int spi_st_remove(struct platform + #ifdef CONFIG_PM + static int spi_st_runtime_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct spi_st *spi_st = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct spi_st *spi_st = spi_controller_get_devdata(host); + + writel_relaxed(0, spi_st->base + SSC_IEN); + pinctrl_pm_select_sleep_state(dev); +@@ -396,8 +396,8 @@ static int spi_st_runtime_suspend(struct + + static int spi_st_runtime_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct spi_st *spi_st = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct spi_st *spi_st = spi_controller_get_devdata(host); + int ret; + + ret = clk_prepare_enable(spi_st->clk); +@@ -410,10 +410,10 @@ static int spi_st_runtime_resume(struct + #ifdef CONFIG_PM_SLEEP + static int spi_st_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); ++ struct spi_controller *host = dev_get_drvdata(dev); + int ret; + +- ret = spi_master_suspend(master); ++ ret = spi_controller_suspend(host); + if (ret) + return ret; + +@@ -422,10 +422,10 @@ static int spi_st_suspend(struct device + + static int spi_st_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); ++ struct spi_controller *host = dev_get_drvdata(dev); + int ret; + +- ret = spi_master_resume(master); ++ ret = spi_controller_resume(host); + if (ret) + return ret; + diff --git a/queue-6.1/spi-sun4i-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-sun4i-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..b59dc7c605 --- /dev/null +++ b/queue-6.1/spi-sun4i-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,58 @@ +From stable+bounces-246980-greg=kroah.com@vger.kernel.org Wed May 13 23:22:17 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:59 -0400 +Subject: spi: sun4i: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Andre Przywara" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513174501.3896424-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit b7b949458ac391963e56ae354b73fee63016dcee ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: Andre Przywara +Link: https://lore.kernel.org/r/20230303172041.2103336-75-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 42108a2f03e0 ("spi: sun4i: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun4i.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -519,11 +519,9 @@ err_free_master: + return ret; + } + +-static int sun4i_spi_remove(struct platform_device *pdev) ++static void sun4i_spi_remove(struct platform_device *pdev) + { + pm_runtime_force_suspend(&pdev->dev); +- +- return 0; + } + + static const struct of_device_id sun4i_spi_match[] = { +@@ -539,7 +537,7 @@ static const struct dev_pm_ops sun4i_spi + + static struct platform_driver sun4i_spi_driver = { + .probe = sun4i_spi_probe, +- .remove = sun4i_spi_remove, ++ .remove_new = sun4i_spi_remove, + .driver = { + .name = "sun4i-spi", + .of_match_table = sun4i_spi_match, diff --git a/queue-6.1/spi-sun4i-fix-controller-deregistration.patch b/queue-6.1/spi-sun4i-fix-controller-deregistration.patch new file mode 100644 index 0000000000..03f3c8e704 --- /dev/null +++ b/queue-6.1/spi-sun4i-fix-controller-deregistration.patch @@ -0,0 +1,54 @@ +From stable+bounces-246982-greg=kroah.com@vger.kernel.org Wed May 13 23:25:56 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:45:01 -0400 +Subject: spi: sun4i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260513174501.3896424-3-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 42108a2f03e0fdeabe9d02d085bdb058baa1189f ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: b5f6517948cc ("spi: sunxi: Add Allwinner A10 SPI controller driver") +Cc: stable@vger.kernel.org # 3.15 +Cc: Maxime Ripard +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-19-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun4i.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -503,7 +503,7 @@ static int sun4i_spi_probe(struct platfo + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; +@@ -521,7 +521,15 @@ err_free_host: + + static void sun4i_spi_remove(struct platform_device *pdev) + { ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_force_suspend(&pdev->dev); ++ ++ spi_controller_put(host); + } + + static const struct of_device_id sun4i_spi_match[] = { diff --git a/queue-6.1/spi-sun4i-switch-to-use-modern-name.patch b/queue-6.1/spi-sun4i-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..66290ebda8 --- /dev/null +++ b/queue-6.1/spi-sun4i-switch-to-use-modern-name.patch @@ -0,0 +1,207 @@ +From stable+bounces-246981-greg=kroah.com@vger.kernel.org Wed May 13 23:25:51 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:45:00 -0400 +Subject: spi: sun4i: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513174501.3896424-2-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 6d232cc8a7e59af0c083319827541966a68817a0 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-7-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 42108a2f03e0 ("spi: sun4i: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun4i.c | 72 ++++++++++++++++++++++++------------------------ + 1 file changed, 36 insertions(+), 36 deletions(-) + +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -75,7 +75,7 @@ + #define SUN4I_FIFO_STA_TF_CNT_BITS 16 + + struct sun4i_spi { +- struct spi_master *master; ++ struct spi_controller *host; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; +@@ -161,7 +161,7 @@ static inline void sun4i_spi_fill_fifo(s + + static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct sun4i_spi *sspi = spi_master_get_devdata(spi->master); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(spi->controller); + u32 reg; + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); +@@ -201,11 +201,11 @@ static size_t sun4i_spi_max_transfer_siz + return SUN4I_MAX_XFER_SIZE - 1; + } + +-static int sun4i_spi_transfer_one(struct spi_master *master, ++static int sun4i_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *tfr) + { +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + unsigned int mclk_rate, div, timeout; + unsigned int start, end, tx_time; + unsigned int tx_len = 0; +@@ -334,7 +334,7 @@ static int sun4i_spi_transfer_one(struct + msecs_to_jiffies(tx_time)); + end = jiffies; + if (!timeout) { +- dev_warn(&master->dev, ++ dev_warn(&host->dev, + "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", + dev_name(&spi->dev), tfr->len, tfr->speed_hz, + jiffies_to_msecs(end - start), tx_time); +@@ -389,8 +389,8 @@ static irqreturn_t sun4i_spi_handler(int + + static int sun4i_spi_runtime_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + int ret; + + ret = clk_prepare_enable(sspi->hclk); +@@ -418,8 +418,8 @@ out: + + static int sun4i_spi_runtime_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); +@@ -429,62 +429,62 @@ static int sun4i_spi_runtime_suspend(str + + static int sun4i_spi_probe(struct platform_device *pdev) + { +- struct spi_master *master; ++ struct spi_controller *host; + struct sun4i_spi *sspi; + int ret = 0, irq; + +- master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi)); +- if (!master) { +- dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); ++ host = spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi)); ++ if (!host) { ++ dev_err(&pdev->dev, "Unable to allocate SPI Host\n"); + return -ENOMEM; + } + +- platform_set_drvdata(pdev, master); +- sspi = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, host); ++ sspi = spi_controller_get_devdata(host); + + sspi->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); +- goto err_free_master; ++ goto err_free_host; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; +- goto err_free_master; ++ goto err_free_host; + } + + ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, + 0, "sun4i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); +- goto err_free_master; ++ goto err_free_host; + } + +- sspi->master = master; +- master->max_speed_hz = 100 * 1000 * 1000; +- master->min_speed_hz = 3 * 1000; +- master->set_cs = sun4i_spi_set_cs; +- master->transfer_one = sun4i_spi_transfer_one; +- master->num_chipselect = 4; +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; +- master->bits_per_word_mask = SPI_BPW_MASK(8); +- master->dev.of_node = pdev->dev.of_node; +- master->auto_runtime_pm = true; +- master->max_transfer_size = sun4i_spi_max_transfer_size; ++ sspi->host = host; ++ host->max_speed_hz = 100 * 1000 * 1000; ++ host->min_speed_hz = 3 * 1000; ++ host->set_cs = sun4i_spi_set_cs; ++ host->transfer_one = sun4i_spi_transfer_one; ++ host->num_chipselect = 4; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ++ host->bits_per_word_mask = SPI_BPW_MASK(8); ++ host->dev.of_node = pdev->dev.of_node; ++ host->auto_runtime_pm = true; ++ host->max_transfer_size = sun4i_spi_max_transfer_size; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); +- goto err_free_master; ++ goto err_free_host; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); +- goto err_free_master; ++ goto err_free_host; + } + + init_completion(&sspi->done); +@@ -496,16 +496,16 @@ static int sun4i_spi_probe(struct platfo + ret = sun4i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); +- goto err_free_master; ++ goto err_free_host; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) { +- dev_err(&pdev->dev, "cannot register SPI master\n"); ++ dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; + } + +@@ -514,8 +514,8 @@ static int sun4i_spi_probe(struct platfo + err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun4i_spi_runtime_suspend(&pdev->dev); +-err_free_master: +- spi_master_put(master); ++err_free_host: ++ spi_controller_put(host); + return ret; + } + diff --git a/queue-6.1/spi-sun6i-fix-controller-deregistration.patch b/queue-6.1/spi-sun6i-fix-controller-deregistration.patch new file mode 100644 index 0000000000..68121c8749 --- /dev/null +++ b/queue-6.1/spi-sun6i-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247095-greg=kroah.com@vger.kernel.org Thu May 14 08:40:56 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 23:10:51 -0400 +Subject: spi: sun6i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260514031051.4119801-1-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit d874a1c33aee0d88fb4ba2f8aeadaa9f1965209a ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: 3558fe900e8a ("spi: sunxi: Add Allwinner A31 SPI controller driver") +Cc: stable@vger.kernel.org # 3.15 +Cc: Maxime Ripard +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-20-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller APIs to spi_master equivalents and kept int return type for sun6i_spi_remove ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun6i.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -688,7 +688,7 @@ static int sun6i_spi_probe(struct platfo + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = spi_register_master(master); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI master\n"); + goto err_pm_disable; +@@ -714,12 +714,19 @@ static int sun6i_spi_remove(struct platf + { + struct spi_master *master = platform_get_drvdata(pdev); + ++ spi_master_get(master); ++ ++ spi_unregister_master(master); ++ + pm_runtime_force_suspend(&pdev->dev); + + if (master->dma_tx) + dma_release_channel(master->dma_tx); + if (master->dma_rx) + dma_release_channel(master->dma_rx); ++ ++ spi_master_put(master); ++ + return 0; + } + diff --git a/queue-6.1/spi-syncuacer-fix-controller-deregistration.patch b/queue-6.1/spi-syncuacer-fix-controller-deregistration.patch new file mode 100644 index 0000000000..91658fcd23 --- /dev/null +++ b/queue-6.1/spi-syncuacer-fix-controller-deregistration.patch @@ -0,0 +1,54 @@ +From stable+bounces-246979-greg=kroah.com@vger.kernel.org Wed May 13 23:15:05 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:55 -0400 +Subject: spi: syncuacer: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Masahisa Kojima , Mark Brown , Sasha Levin +Message-ID: <20260513174455.3896307-3-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 75d849c3452e9611de031db45b3149ba9a99035f ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: b0823ee35cf9 ("spi: Add spi driver for Socionext SynQuacer platform") +Cc: stable@vger.kernel.org # 5.3 +Cc: Masahisa Kojima +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-21-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-synquacer.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-synquacer.c ++++ b/drivers/spi/spi-synquacer.c +@@ -719,7 +719,7 @@ static int synquacer_spi_probe(struct pl + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + +- ret = devm_spi_register_controller(sspi->dev, host); ++ ret = spi_register_controller(host); + if (ret) + goto disable_pm; + +@@ -740,9 +740,15 @@ static void synquacer_spi_remove(struct + struct spi_controller *host = platform_get_drvdata(pdev); + struct synquacer_spi *sspi = spi_controller_get_devdata(host); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_disable(sspi->dev); + + clk_disable_unprepare(sspi->clk); ++ ++ spi_controller_put(host); + } + + static int __maybe_unused synquacer_spi_suspend(struct device *dev) diff --git a/queue-6.1/spi-synquacer-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-synquacer-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..25008bb95e --- /dev/null +++ b/queue-6.1/spi-synquacer-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-246977-greg=kroah.com@vger.kernel.org Wed May 13 23:25:36 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:53 -0400 +Subject: spi: synquacer: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513174455.3896307-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 1972cdc47df737f5b90ac2132080004f5e413e91 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230303172041.2103336-78-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 75d849c3452e ("spi: syncuacer: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-synquacer.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-synquacer.c ++++ b/drivers/spi/spi-synquacer.c +@@ -735,7 +735,7 @@ put_spi: + return ret; + } + +-static int synquacer_spi_remove(struct platform_device *pdev) ++static void synquacer_spi_remove(struct platform_device *pdev) + { + struct spi_master *master = platform_get_drvdata(pdev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); +@@ -743,8 +743,6 @@ static int synquacer_spi_remove(struct p + pm_runtime_disable(sspi->dev); + + clk_disable_unprepare(sspi->clk); +- +- return 0; + } + + static int __maybe_unused synquacer_spi_suspend(struct device *dev) +@@ -820,7 +818,7 @@ static struct platform_driver synquacer_ + .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), + }, + .probe = synquacer_spi_probe, +- .remove = synquacer_spi_remove, ++ .remove_new = synquacer_spi_remove, + }; + module_platform_driver(synquacer_spi_driver); + diff --git a/queue-6.1/spi-synquacer-switch-to-use-modern-name.patch b/queue-6.1/spi-synquacer-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..414d69afcc --- /dev/null +++ b/queue-6.1/spi-synquacer-switch-to-use-modern-name.patch @@ -0,0 +1,260 @@ +From stable+bounces-246978-greg=kroah.com@vger.kernel.org Wed May 13 23:25:42 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:54 -0400 +Subject: spi: synquacer: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513174455.3896307-2-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 3524d1b727a66712f02f92807219a3650e5cf910 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-10-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 75d849c3452e ("spi: syncuacer: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-synquacer.c | 84 ++++++++++++++++++++++---------------------- + 1 file changed, 42 insertions(+), 42 deletions(-) + +--- a/drivers/spi/spi-synquacer.c ++++ b/drivers/spi/spi-synquacer.c +@@ -225,11 +225,11 @@ static int write_fifo(struct synquacer_s + return 0; + } + +-static int synquacer_spi_config(struct spi_master *master, ++static int synquacer_spi_config(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + unsigned int speed, mode, bpw, cs, bus_width, transfer_mode; + u32 rate, val, div; + +@@ -263,7 +263,7 @@ static int synquacer_spi_config(struct s + } + + sspi->transfer_mode = transfer_mode; +- rate = master->max_speed_hz; ++ rate = host->max_speed_hz; + + div = DIV_ROUND_UP(rate, speed); + if (div > 254) { +@@ -350,11 +350,11 @@ static int synquacer_spi_config(struct s + return 0; + } + +-static int synquacer_spi_transfer_one(struct spi_master *master, ++static int synquacer_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + int status = 0; + u32 words; +@@ -378,7 +378,7 @@ static int synquacer_spi_transfer_one(st + if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST)) + xfer->bits_per_word = 32; + +- ret = synquacer_spi_config(master, spi, xfer); ++ ret = synquacer_spi_config(host, spi, xfer); + + /* restore */ + xfer->bits_per_word = bpw; +@@ -482,7 +482,7 @@ static int synquacer_spi_transfer_one(st + + static void synquacer_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(spi->master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); +@@ -517,11 +517,11 @@ static int synquacer_spi_wait_status_upd + return -EBUSY; + } + +-static int synquacer_spi_enable(struct spi_master *master) ++static int synquacer_spi_enable(struct spi_controller *host) + { + u32 val; + int status; +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + + /* Disable module */ + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); +@@ -601,18 +601,18 @@ static irqreturn_t sq_spi_tx_handler(int + static int synquacer_spi_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +- struct spi_master *master; ++ struct spi_controller *host; + struct synquacer_spi *sspi; + int ret; + int rx_irq, tx_irq; + +- master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*sspi)); ++ if (!host) + return -ENOMEM; + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- sspi = spi_master_get_devdata(master); ++ sspi = spi_controller_get_devdata(host); + sspi->dev = &pdev->dev; + + init_completion(&sspi->transfer_done); +@@ -625,7 +625,7 @@ static int synquacer_spi_probe(struct pl + + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ + device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", +- &master->max_speed_hz); /* for ACPI */ ++ &host->max_speed_hz); /* for ACPI */ + + if (dev_of_node(&pdev->dev)) { + if (device_property_match_string(&pdev->dev, +@@ -655,21 +655,21 @@ static int synquacer_spi_probe(struct pl + goto put_spi; + } + +- master->max_speed_hz = clk_get_rate(sspi->clk); ++ host->max_speed_hz = clk_get_rate(sspi->clk); + } + +- if (!master->max_speed_hz) { ++ if (!host->max_speed_hz) { + dev_err(&pdev->dev, "missing clock source\n"); + ret = -EINVAL; + goto disable_clk; + } +- master->min_speed_hz = master->max_speed_hz / 254; ++ host->min_speed_hz = host->max_speed_hz / 254; + + sspi->aces = device_property_read_bool(&pdev->dev, + "socionext,set-aces"); + sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm"); + +- master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; ++ host->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; + + rx_irq = platform_get_irq(pdev, 0); + if (rx_irq <= 0) { +@@ -699,27 +699,27 @@ static int synquacer_spi_probe(struct pl + goto disable_clk; + } + +- master->dev.of_node = np; +- master->dev.fwnode = pdev->dev.fwnode; +- master->auto_runtime_pm = true; +- master->bus_num = pdev->id; +- +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | +- SPI_TX_QUAD | SPI_RX_QUAD; +- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | +- SPI_BPW_MASK(16) | SPI_BPW_MASK(8); ++ host->dev.of_node = np; ++ host->dev.fwnode = pdev->dev.fwnode; ++ host->auto_runtime_pm = true; ++ host->bus_num = pdev->id; ++ ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | ++ SPI_TX_QUAD | SPI_RX_QUAD; ++ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | ++ SPI_BPW_MASK(16) | SPI_BPW_MASK(8); + +- master->set_cs = synquacer_spi_set_cs; +- master->transfer_one = synquacer_spi_transfer_one; ++ host->set_cs = synquacer_spi_set_cs; ++ host->transfer_one = synquacer_spi_transfer_one; + +- ret = synquacer_spi_enable(master); ++ ret = synquacer_spi_enable(host); + if (ret) + goto disable_clk; + + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + +- ret = devm_spi_register_master(sspi->dev, master); ++ ret = devm_spi_register_controller(sspi->dev, host); + if (ret) + goto disable_pm; + +@@ -730,15 +730,15 @@ disable_pm: + disable_clk: + clk_disable_unprepare(sspi->clk); + put_spi: +- spi_master_put(master); ++ spi_controller_put(host); + + return ret; + } + + static void synquacer_spi_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + + pm_runtime_disable(sspi->dev); + +@@ -747,11 +747,11 @@ static void synquacer_spi_remove(struct + + static int __maybe_unused synquacer_spi_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + +- ret = spi_master_suspend(master); ++ ret = spi_controller_suspend(host); + if (ret) + return ret; + +@@ -763,8 +763,8 @@ static int __maybe_unused synquacer_spi_ + + static int __maybe_unused synquacer_spi_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + + if (!pm_runtime_suspended(dev)) { +@@ -778,7 +778,7 @@ static int __maybe_unused synquacer_spi_ + return ret; + } + +- ret = synquacer_spi_enable(master); ++ ret = synquacer_spi_enable(host); + if (ret) { + clk_disable_unprepare(sspi->clk); + dev_err(dev, "failed to enable spi (%d)\n", ret); +@@ -786,7 +786,7 @@ static int __maybe_unused synquacer_spi_ + } + } + +- ret = spi_master_resume(master); ++ ret = spi_controller_resume(host); + if (ret < 0) + clk_disable_unprepare(sspi->clk); + diff --git a/queue-6.1/spi-tegra114-fix-controller-deregistration.patch b/queue-6.1/spi-tegra114-fix-controller-deregistration.patch new file mode 100644 index 0000000000..a53b4b2dcb --- /dev/null +++ b/queue-6.1/spi-tegra114-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247173-greg=kroah.com@vger.kernel.org Thu May 14 17:16:10 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:45:54 -0400 +Subject: spi: tegra114: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514114554.179180-1-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 9c9c27ff2058142d8f800de3186d6864184958de ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: 5c8096439600 ("spi: tegra114: use devm_spi_register_master()") +Cc: stable@vger.kernel.org # 3.13 +Cc: Jingoo Han +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-22-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller/host APIs to spi_master/master equivalents and placed spi_master_put() before the existing return 0 in remove ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-tegra114.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -1415,7 +1415,7 @@ static int tegra_spi_probe(struct platfo + } + + master->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to master err %d\n", ret); + goto exit_free_irq; +@@ -1441,6 +1441,10 @@ static int tegra_spi_remove(struct platf + struct spi_master *master = platform_get_drvdata(pdev); + struct tegra_spi_data *tspi = spi_master_get_devdata(master); + ++ spi_master_get(master); ++ ++ spi_unregister_master(master); ++ + free_irq(tspi->irq, tspi); + + if (tspi->tx_dma_chan) +@@ -1453,6 +1457,8 @@ static int tegra_spi_remove(struct platf + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_spi_runtime_suspend(&pdev->dev); + ++ spi_master_put(master); ++ + return 0; + } + diff --git a/queue-6.1/spi-tegra20-sflash-fix-controller-deregistration.patch b/queue-6.1/spi-tegra20-sflash-fix-controller-deregistration.patch new file mode 100644 index 0000000000..6224390398 --- /dev/null +++ b/queue-6.1/spi-tegra20-sflash-fix-controller-deregistration.patch @@ -0,0 +1,58 @@ +From stable+bounces-247174-greg=kroah.com@vger.kernel.org Thu May 14 17:21:07 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:46:26 -0400 +Subject: spi: tegra20-sflash: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514114626.180398-1-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit ad7310e983327f939dd6c4e801eab13238992572 ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: f12f7318c44a ("spi: tegra20-sflash: use devm_spi_register_master()") +Cc: stable@vger.kernel.org # 3.13 +Cc: Jingoo Han +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-23-johan@kernel.org +Signed-off-by: Mark Brown +[ renamed spi_controller/host APIs to spi_master/master equivalents and switched devm_spi_register_master to spi_register_master ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-tegra20-sflash.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-tegra20-sflash.c ++++ b/drivers/spi/spi-tegra20-sflash.c +@@ -506,7 +506,7 @@ static int tegra_sflash_probe(struct pla + pm_runtime_put(&pdev->dev); + + master->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to master err %d\n", ret); + goto exit_pm_disable; +@@ -529,12 +529,18 @@ static int tegra_sflash_remove(struct pl + struct spi_master *master = platform_get_drvdata(pdev); + struct tegra_sflash_data *tsd = spi_master_get_devdata(master); + ++ spi_master_get(master); ++ ++ spi_unregister_master(master); ++ + free_irq(tsd->irq, tsd); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_sflash_runtime_suspend(&pdev->dev); + ++ spi_master_put(master); ++ + return 0; + } + diff --git a/queue-6.1/spi-ti-qspi-fix-controller-deregistration.patch b/queue-6.1/spi-ti-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..8bd935653c --- /dev/null +++ b/queue-6.1/spi-ti-qspi-fix-controller-deregistration.patch @@ -0,0 +1,69 @@ +From stable+bounces-247006-greg=kroah.com@vger.kernel.org Wed May 13 23:57:12 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:20:17 -0400 +Subject: spi: ti-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Sebastian Andrzej Siewior , Mark Brown , Sasha Levin +Message-ID: <20260513182017.3918352-4-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 0c18a1bacbb1d8b8aa34d3d004a2cb8226c8b1ea ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Note that the controller is suspended before disabling and releasing +resources since commit 3ac066e2227c ("spi: spi-ti-qspi: Suspend the +queue before removing the device") which avoids issues like unclocked +accesses but prevents SPI device drivers from doing I/O during +deregistration. + +Fixes: 3b3a80019ff1 ("spi: ti-qspi: one only one interrupt handler") +Cc: stable@vger.kernel.org # 3.13 +Cc: Sebastian Andrzej Siewior +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-24-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -897,7 +897,7 @@ no_dma: + qspi->mmap_enabled = false; + qspi->current_cs = -1; + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (!ret) + return 0; + +@@ -912,19 +912,17 @@ free_host: + static void ti_qspi_remove(struct platform_device *pdev) + { + struct ti_qspi *qspi = platform_get_drvdata(pdev); +- int rc; + +- rc = spi_controller_suspend(qspi->host); +- if (rc) { +- dev_alert(&pdev->dev, "spi_controller_suspend() failed (%pe)\n", +- ERR_PTR(rc)); +- return; +- } ++ spi_controller_get(qspi->host); ++ ++ spi_unregister_controller(qspi->host); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + ti_qspi_dma_cleanup(qspi); ++ ++ spi_controller_put(qspi->host); + } + + static const struct dev_pm_ops ti_qspi_pm_ops = { diff --git a/queue-6.1/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..be2e433164 --- /dev/null +++ b/queue-6.1/spi-topcliff-pch-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-247679-greg=kroah.com@vger.kernel.org Fri May 15 17:52:14 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 07:45:14 -0400 +Subject: spi: topcliff-pch: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260515114516.3021914-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit b082694f18bdff807b42a3bccc62c3a524168f23 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230303172041.2103336-83-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 5d6f477d6fc0 ("spi: topcliff-pch: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-topcliff-pch.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-topcliff-pch.c ++++ b/drivers/spi/spi-topcliff-pch.c +@@ -1396,7 +1396,7 @@ err_pci_iomap: + return ret; + } + +-static int pch_spi_pd_remove(struct platform_device *plat_dev) ++static void pch_spi_pd_remove(struct platform_device *plat_dev) + { + struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev); + struct pch_spi_data *data = platform_get_drvdata(plat_dev); +@@ -1434,8 +1434,6 @@ static int pch_spi_pd_remove(struct plat + + pci_iounmap(board_dat->pdev, data->io_remap_addr); + spi_unregister_master(data->master); +- +- return 0; + } + #ifdef CONFIG_PM + static int pch_spi_pd_suspend(struct platform_device *pd_dev, +@@ -1516,7 +1514,7 @@ static struct platform_driver pch_spi_pd + .name = "pch-spi", + }, + .probe = pch_spi_pd_probe, +- .remove = pch_spi_pd_remove, ++ .remove_new = pch_spi_pd_remove, + .suspend = pch_spi_pd_suspend, + .resume = pch_spi_pd_resume + }; diff --git a/queue-6.1/spi-uniphier-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-uniphier-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..9c030d165e --- /dev/null +++ b/queue-6.1/spi-uniphier-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-247182-greg=kroah.com@vger.kernel.org Thu May 14 17:32:42 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 08:02:30 -0400 +Subject: spi: uniphier: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260514120233.192698-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 1b13d196d2813dadc1947940dbd4aaad6ae21c02 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230303172041.2103336-84-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 0245435f7772 ("spi: uniphier: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -775,7 +775,7 @@ out_master_put: + return ret; + } + +-static int uniphier_spi_remove(struct platform_device *pdev) ++static void uniphier_spi_remove(struct platform_device *pdev) + { + struct spi_master *master = platform_get_drvdata(pdev); + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); +@@ -786,8 +786,6 @@ static int uniphier_spi_remove(struct pl + dma_release_channel(master->dma_rx); + + clk_disable_unprepare(priv->clk); +- +- return 0; + } + + static const struct of_device_id uniphier_spi_match[] = { +@@ -798,7 +796,7 @@ MODULE_DEVICE_TABLE(of, uniphier_spi_mat + + static struct platform_driver uniphier_spi_driver = { + .probe = uniphier_spi_probe, +- .remove = uniphier_spi_remove, ++ .remove_new = uniphier_spi_remove, + .driver = { + .name = "uniphier-spi", + .of_match_table = uniphier_spi_match, diff --git a/queue-6.1/spi-uniphier-fix-controller-deregistration.patch b/queue-6.1/spi-uniphier-fix-controller-deregistration.patch new file mode 100644 index 0000000000..41951bb86a --- /dev/null +++ b/queue-6.1/spi-uniphier-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247185-greg=kroah.com@vger.kernel.org Thu May 14 17:32:49 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 08:02:33 -0400 +Subject: spi: uniphier: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Keiji Hayashibara , Mark Brown , Sasha Levin +Message-ID: <20260514120233.192698-4-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 0245435f777264ac45945ed2f325dd095a41d1af ] + +Make sure to deregister the controller before releasing underlying +resources like DMA during driver unbind. + +Note that clocks were also disabled before the recent commit +fdca270f8f87 ("spi: uniphier: Simplify clock handling with +devm_clk_get_enabled()"). + +Fixes: 5ba155a4d4cc ("spi: add SPI controller driver for UniPhier SoC") +Cc: stable@vger.kernel.org # 4.19 +Cc: Keiji Hayashibara +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-25-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -747,7 +747,7 @@ static int uniphier_spi_probe(struct pla + + host->max_dma_len = min(dma_tx_burst, dma_rx_burst); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) + goto out_release_dma; + +@@ -772,10 +772,16 @@ static void uniphier_spi_remove(struct p + { + struct spi_controller *host = platform_get_drvdata(pdev); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); ++ ++ spi_controller_put(host); + } + + static const struct of_device_id uniphier_spi_match[] = { diff --git a/queue-6.1/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch b/queue-6.1/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..3b833c75e1 --- /dev/null +++ b/queue-6.1/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch @@ -0,0 +1,99 @@ +From stable+bounces-247184-greg=kroah.com@vger.kernel.org Thu May 14 17:33:02 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 08:02:32 -0400 +Subject: spi: uniphier: Simplify clock handling with devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Pei Xiao , Kunihiko Hayashi , Mark Brown , Sasha Levin +Message-ID: <20260514120233.192698-3-sashal@kernel.org> + +From: Pei Xiao + +[ Upstream commit fdca270f8f87cae2eb5b619234b9dd11a863ce6b ] + +Replace devm_clk_get() followed by clk_prepare_enable() with +devm_clk_get_enabled() for the clock. This removes the need for +explicit clock enable and disable calls, as the managed API automatically +handles clock disabling on device removal or probe failure. + +Remove the now-unnecessary clk_disable_unprepare() calls from the probe +error path and the remove callback. Adjust error labels accordingly. + +Signed-off-by: Pei Xiao +Reviewed-by: Kunihiko Hayashi +Link: https://patch.msgid.link/b2deeefd4ef1a4bce71116aabfcb7e81400f6d37.1775546948.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Stable-dep-of: 0245435f7772 ("spi: uniphier: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -666,28 +666,24 @@ static int uniphier_spi_probe(struct pla + } + priv->base_dma_addr = res->start; + +- priv->clk = devm_clk_get(&pdev->dev, NULL); ++ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); + goto out_host_put; + } + +- ret = clk_prepare_enable(priv->clk); +- if (ret) +- goto out_host_put; +- + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; +- goto out_disable_clk; ++ goto out_host_put; + } + + ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler, + 0, "uniphier-spi", priv); + if (ret) { + dev_err(&pdev->dev, "failed to request IRQ\n"); +- goto out_disable_clk; ++ goto out_host_put; + } + + init_completion(&priv->xfer_done); +@@ -717,7 +713,7 @@ static int uniphier_spi_probe(struct pla + if (IS_ERR_OR_NULL(host->dma_tx)) { + if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; +- goto out_disable_clk; ++ goto out_host_put; + } + host->dma_tx = NULL; + dma_tx_burst = INT_MAX; +@@ -767,9 +763,6 @@ out_release_dma: + host->dma_tx = NULL; + } + +-out_disable_clk: +- clk_disable_unprepare(priv->clk); +- + out_host_put: + spi_controller_put(host); + return ret; +@@ -778,14 +771,11 @@ out_host_put: + static void uniphier_spi_remove(struct platform_device *pdev) + { + struct spi_controller *host = platform_get_drvdata(pdev); +- struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); +- +- clk_disable_unprepare(priv->clk); + } + + static const struct of_device_id uniphier_spi_match[] = { diff --git a/queue-6.1/spi-uniphier-switch-to-use-modern-name.patch b/queue-6.1/spi-uniphier-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..78a0dc2a14 --- /dev/null +++ b/queue-6.1/spi-uniphier-switch-to-use-modern-name.patch @@ -0,0 +1,513 @@ +From stable+bounces-247183-greg=kroah.com@vger.kernel.org Thu May 14 17:32:59 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 08:02:31 -0400 +Subject: spi: uniphier: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260514120233.192698-2-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 4c2ee0991013ca8a32bb093a017d460204790112 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-19-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 0245435f7772 ("spi: uniphier: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 198 ++++++++++++++++++++++----------------------- + 1 file changed, 99 insertions(+), 99 deletions(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -26,7 +26,7 @@ struct uniphier_spi_priv { + void __iomem *base; + dma_addr_t base_dma_addr; + struct clk *clk; +- struct spi_master *master; ++ struct spi_controller *host; + struct completion xfer_done; + + int error; +@@ -127,7 +127,7 @@ static inline void uniphier_spi_irq_disa + + static void uniphier_spi_set_mode(struct spi_device *spi) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val1, val2; + + /* +@@ -180,7 +180,7 @@ static void uniphier_spi_set_mode(struct + + static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(priv->base + SSI_TXWDS); +@@ -198,7 +198,7 @@ static void uniphier_spi_set_transfer_si + static void uniphier_spi_set_baudrate(struct spi_device *spi, + unsigned int speed) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val, ckdiv; + + /* +@@ -217,7 +217,7 @@ static void uniphier_spi_set_baudrate(st + static void uniphier_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + priv->error = 0; +@@ -333,7 +333,7 @@ static void uniphier_spi_fill_tx_fifo(st + + static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(priv->base + SSI_FPS); +@@ -346,16 +346,16 @@ static void uniphier_spi_set_cs(struct s + writel(val, priv->base + SSI_FPS); + } + +-static bool uniphier_spi_can_dma(struct spi_master *master, ++static bool uniphier_spi_can_dma(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + unsigned int bpw = bytes_per_word(priv->bits_per_word); + +- if ((!master->dma_tx && !master->dma_rx) +- || (!master->dma_tx && t->tx_buf) +- || (!master->dma_rx && t->rx_buf)) ++ if ((!host->dma_tx && !host->dma_rx) ++ || (!host->dma_tx && t->tx_buf) ++ || (!host->dma_rx && t->rx_buf)) + return false; + + return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; +@@ -363,33 +363,33 @@ static bool uniphier_spi_can_dma(struct + + static void uniphier_spi_dma_rxcb(void *data) + { +- struct spi_master *master = data; +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = data; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_RXRE); + + if (!(state & SSI_DMA_TX_BUSY)) +- spi_finalize_current_transfer(master); ++ spi_finalize_current_transfer(host); + } + + static void uniphier_spi_dma_txcb(void *data) + { +- struct spi_master *master = data; +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = data; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_TXRE); + + if (!(state & SSI_DMA_RX_BUSY)) +- spi_finalize_current_transfer(master); ++ spi_finalize_current_transfer(host); + } + +-static int uniphier_spi_transfer_one_dma(struct spi_master *master, ++static int uniphier_spi_transfer_one_dma(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; + int buswidth; + +@@ -412,23 +412,23 @@ static int uniphier_spi_transfer_one_dma + .src_maxburst = SSI_FIFO_BURST_NUM, + }; + +- dmaengine_slave_config(master->dma_rx, &rxconf); ++ dmaengine_slave_config(host->dma_rx, &rxconf); + + rxdesc = dmaengine_prep_slave_sg( +- master->dma_rx, ++ host->dma_rx, + t->rx_sg.sgl, t->rx_sg.nents, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) + goto out_err_prep; + + rxdesc->callback = uniphier_spi_dma_rxcb; +- rxdesc->callback_param = master; ++ rxdesc->callback_param = host; + + uniphier_spi_irq_enable(priv, SSI_IE_RXRE); + atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); + + dmaengine_submit(rxdesc); +- dma_async_issue_pending(master->dma_rx); ++ dma_async_issue_pending(host->dma_rx); + } + + if (priv->tx_buf) { +@@ -439,23 +439,23 @@ static int uniphier_spi_transfer_one_dma + .dst_maxburst = SSI_FIFO_BURST_NUM, + }; + +- dmaengine_slave_config(master->dma_tx, &txconf); ++ dmaengine_slave_config(host->dma_tx, &txconf); + + txdesc = dmaengine_prep_slave_sg( +- master->dma_tx, ++ host->dma_tx, + t->tx_sg.sgl, t->tx_sg.nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) + goto out_err_prep; + + txdesc->callback = uniphier_spi_dma_txcb; +- txdesc->callback_param = master; ++ txdesc->callback_param = host; + + uniphier_spi_irq_enable(priv, SSI_IE_TXRE); + atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); + + dmaengine_submit(txdesc); +- dma_async_issue_pending(master->dma_tx); ++ dma_async_issue_pending(host->dma_tx); + } + + /* signal that we need to wait for completion */ +@@ -463,17 +463,17 @@ static int uniphier_spi_transfer_one_dma + + out_err_prep: + if (rxdesc) +- dmaengine_terminate_sync(master->dma_rx); ++ dmaengine_terminate_sync(host->dma_rx); + + return -EINVAL; + } + +-static int uniphier_spi_transfer_one_irq(struct spi_master *master, ++static int uniphier_spi_transfer_one_irq(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); +- struct device *dev = master->dev.parent; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); ++ struct device *dev = host->dev.parent; + unsigned long time_left; + + reinit_completion(&priv->xfer_done); +@@ -495,11 +495,11 @@ static int uniphier_spi_transfer_one_irq + return priv->error; + } + +-static int uniphier_spi_transfer_one_poll(struct spi_master *master, ++static int uniphier_spi_transfer_one_poll(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int loop = SSI_POLL_TIMEOUT_US * 10; + + while (priv->tx_bytes) { +@@ -520,14 +520,14 @@ static int uniphier_spi_transfer_one_pol + return 0; + + irq_transfer: +- return uniphier_spi_transfer_one_irq(master, spi, t); ++ return uniphier_spi_transfer_one_irq(host, spi, t); + } + +-static int uniphier_spi_transfer_one(struct spi_master *master, ++static int uniphier_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + unsigned long threshold; + bool use_dma; + +@@ -537,9 +537,9 @@ static int uniphier_spi_transfer_one(str + + uniphier_spi_setup_transfer(spi, t); + +- use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; ++ use_dma = host->can_dma ? host->can_dma(host, spi, t) : false; + if (use_dma) +- return uniphier_spi_transfer_one_dma(master, spi, t); ++ return uniphier_spi_transfer_one_dma(host, spi, t); + + /* + * If the transfer operation will take longer than +@@ -548,33 +548,33 @@ static int uniphier_spi_transfer_one(str + threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, + USEC_PER_SEC * BITS_PER_BYTE); + if (t->len > threshold) +- return uniphier_spi_transfer_one_irq(master, spi, t); ++ return uniphier_spi_transfer_one_irq(host, spi, t); + else +- return uniphier_spi_transfer_one_poll(master, spi, t); ++ return uniphier_spi_transfer_one_poll(host, spi, t); + } + +-static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) ++static int uniphier_spi_prepare_transfer_hardware(struct spi_controller *host) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + writel(SSI_CTL_EN, priv->base + SSI_CTL); + + return 0; + } + +-static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master) ++static int uniphier_spi_unprepare_transfer_hardware(struct spi_controller *host) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + writel(0, priv->base + SSI_CTL); + + return 0; + } + +-static void uniphier_spi_handle_err(struct spi_master *master, ++static void uniphier_spi_handle_err(struct spi_controller *host, + struct spi_message *msg) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + u32 val; + + /* stop running spi transfer */ +@@ -587,12 +587,12 @@ static void uniphier_spi_handle_err(stru + uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); + + if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { +- dmaengine_terminate_async(master->dma_tx); ++ dmaengine_terminate_async(host->dma_tx); + atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + } + + if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { +- dmaengine_terminate_async(master->dma_rx); ++ dmaengine_terminate_async(host->dma_rx); + atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + } + } +@@ -641,7 +641,7 @@ done: + static int uniphier_spi_probe(struct platform_device *pdev) + { + struct uniphier_spi_priv *priv; +- struct spi_master *master; ++ struct spi_controller *host; + struct resource *res; + struct dma_slave_caps caps; + u32 dma_tx_burst = 0, dma_rx_burst = 0; +@@ -649,20 +649,20 @@ static int uniphier_spi_probe(struct pla + int irq; + int ret; + +- master = spi_alloc_master(&pdev->dev, sizeof(*priv)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*priv)); ++ if (!host) + return -ENOMEM; + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- priv = spi_master_get_devdata(master); +- priv->master = master; ++ priv = spi_controller_get_devdata(host); ++ priv->host = host; + priv->is_save_param = false; + + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); +- goto out_master_put; ++ goto out_host_put; + } + priv->base_dma_addr = res->start; + +@@ -670,12 +670,12 @@ static int uniphier_spi_probe(struct pla + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); +- goto out_master_put; ++ goto out_host_put; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) +- goto out_master_put; ++ goto out_host_put; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { +@@ -694,35 +694,35 @@ static int uniphier_spi_probe(struct pla + + clk_rate = clk_get_rate(priv->clk); + +- master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); +- master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; +- master->dev.of_node = pdev->dev.of_node; +- master->bus_num = pdev->id; +- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); +- +- master->set_cs = uniphier_spi_set_cs; +- master->transfer_one = uniphier_spi_transfer_one; +- master->prepare_transfer_hardware ++ host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); ++ host->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ++ host->dev.of_node = pdev->dev.of_node; ++ host->bus_num = pdev->id; ++ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); ++ ++ host->set_cs = uniphier_spi_set_cs; ++ host->transfer_one = uniphier_spi_transfer_one; ++ host->prepare_transfer_hardware + = uniphier_spi_prepare_transfer_hardware; +- master->unprepare_transfer_hardware ++ host->unprepare_transfer_hardware + = uniphier_spi_unprepare_transfer_hardware; +- master->handle_err = uniphier_spi_handle_err; +- master->can_dma = uniphier_spi_can_dma; ++ host->handle_err = uniphier_spi_handle_err; ++ host->can_dma = uniphier_spi_can_dma; + +- master->num_chipselect = 1; +- master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; ++ host->num_chipselect = 1; ++ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + +- master->dma_tx = dma_request_chan(&pdev->dev, "tx"); +- if (IS_ERR_OR_NULL(master->dma_tx)) { +- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { ++ host->dma_tx = dma_request_chan(&pdev->dev, "tx"); ++ if (IS_ERR_OR_NULL(host->dma_tx)) { ++ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_disable_clk; + } +- master->dma_tx = NULL; ++ host->dma_tx = NULL; + dma_tx_burst = INT_MAX; + } else { +- ret = dma_get_slave_caps(master->dma_tx, &caps); ++ ret = dma_get_slave_caps(host->dma_tx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", + ret); +@@ -731,16 +731,16 @@ static int uniphier_spi_probe(struct pla + dma_tx_burst = caps.max_burst; + } + +- master->dma_rx = dma_request_chan(&pdev->dev, "rx"); +- if (IS_ERR_OR_NULL(master->dma_rx)) { +- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { ++ host->dma_rx = dma_request_chan(&pdev->dev, "rx"); ++ if (IS_ERR_OR_NULL(host->dma_rx)) { ++ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_release_dma; + } +- master->dma_rx = NULL; ++ host->dma_rx = NULL; + dma_rx_burst = INT_MAX; + } else { +- ret = dma_get_slave_caps(master->dma_rx, &caps); ++ ret = dma_get_slave_caps(host->dma_rx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", + ret); +@@ -749,41 +749,41 @@ static int uniphier_spi_probe(struct pla + dma_rx_burst = caps.max_burst; + } + +- master->max_dma_len = min(dma_tx_burst, dma_rx_burst); ++ host->max_dma_len = min(dma_tx_burst, dma_rx_burst); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) + goto out_release_dma; + + return 0; + + out_release_dma: +- if (!IS_ERR_OR_NULL(master->dma_rx)) { +- dma_release_channel(master->dma_rx); +- master->dma_rx = NULL; +- } +- if (!IS_ERR_OR_NULL(master->dma_tx)) { +- dma_release_channel(master->dma_tx); +- master->dma_tx = NULL; ++ if (!IS_ERR_OR_NULL(host->dma_rx)) { ++ dma_release_channel(host->dma_rx); ++ host->dma_rx = NULL; ++ } ++ if (!IS_ERR_OR_NULL(host->dma_tx)) { ++ dma_release_channel(host->dma_tx); ++ host->dma_tx = NULL; + } + + out_disable_clk: + clk_disable_unprepare(priv->clk); + +-out_master_put: +- spi_master_put(master); ++out_host_put: ++ spi_controller_put(host); + return ret; + } + + static void uniphier_spi_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + +- if (master->dma_tx) +- dma_release_channel(master->dma_tx); +- if (master->dma_rx) +- dma_release_channel(master->dma_rx); ++ if (host->dma_tx) ++ dma_release_channel(host->dma_tx); ++ if (host->dma_rx) ++ dma_release_channel(host->dma_rx); + + clk_disable_unprepare(priv->clk); + } diff --git a/queue-6.1/spi-zynq-qspi-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/spi-zynq-qspi-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..3a80a45af3 --- /dev/null +++ b/queue-6.1/spi-zynq-qspi-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-247024-greg=kroah.com@vger.kernel.org Thu May 14 01:04:26 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:16 -0400 +Subject: spi: zynq-qspi: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513193420.3938432-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit ae9084b6458d34ebf3e377d0407ebe513e41ac71 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230303172041.2103336-87-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: c9c012706c9f ("spi: zynq-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -750,7 +750,7 @@ remove_master: + * + * Return: 0 on success and error value on failure + */ +-static int zynq_qspi_remove(struct platform_device *pdev) ++static void zynq_qspi_remove(struct platform_device *pdev) + { + struct zynq_qspi *xqspi = platform_get_drvdata(pdev); + +@@ -758,8 +758,6 @@ static int zynq_qspi_remove(struct platf + + clk_disable_unprepare(xqspi->refclk); + clk_disable_unprepare(xqspi->pclk); +- +- return 0; + } + + static const struct of_device_id zynq_qspi_of_match[] = { +@@ -774,7 +772,7 @@ MODULE_DEVICE_TABLE(of, zynq_qspi_of_mat + */ + static struct platform_driver zynq_qspi_driver = { + .probe = zynq_qspi_probe, +- .remove = zynq_qspi_remove, ++ .remove_new = zynq_qspi_remove, + .driver = { + .name = "zynq-qspi", + .of_match_table = zynq_qspi_of_match, diff --git a/queue-6.1/spi-zynq-qspi-fix-controller-deregistration.patch b/queue-6.1/spi-zynq-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..ef70bb4052 --- /dev/null +++ b/queue-6.1/spi-zynq-qspi-fix-controller-deregistration.patch @@ -0,0 +1,73 @@ +From stable+bounces-247028-greg=kroah.com@vger.kernel.org Thu May 14 01:04:51 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:20 -0400 +Subject: spi: zynq-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Naga Sureshkumar Relli , Mark Brown , Sasha Levin +Message-ID: <20260513193420.3938432-5-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit c9c012706c9fa8ca6d129a9161caf92ab625a3fd ] + +Make sure to deregister the controller before disabling it during driver +unbind. + +Note that clocks were also disabled before the recent commit +1f8fd9490e31 ("spi: zynq-qspi: Simplify clock handling with +devm_clk_get_enabled()"). + +Fixes: 67dca5e580f1 ("spi: spi-mem: Add support for Zynq QSPI controller") +Cc: stable@vger.kernel.org # 5.2: 8eb2fd00f65a +Cc: stable@vger.kernel.org # 5.2 +Cc: Naga Sureshkumar Relli +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-27-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -641,7 +641,7 @@ static int zynq_qspi_probe(struct platfo + + xqspi = spi_controller_get_devdata(ctlr); + xqspi->dev = dev; +- platform_set_drvdata(pdev, xqspi); ++ platform_set_drvdata(pdev, ctlr); + xqspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xqspi->regs)) { + ret = PTR_ERR(xqspi->regs); +@@ -699,9 +699,9 @@ static int zynq_qspi_probe(struct platfo + /* QSPI controller initializations */ + zynq_qspi_init_hw(xqspi, ctlr->num_chipselect); + +- ret = devm_spi_register_controller(&pdev->dev, ctlr); ++ ret = spi_register_controller(ctlr); + if (ret) { +- dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); ++ dev_err(&pdev->dev, "failed to register controller\n"); + goto remove_ctlr; + } + +@@ -725,9 +725,16 @@ remove_ctlr: + */ + static void zynq_qspi_remove(struct platform_device *pdev) + { +- struct zynq_qspi *xqspi = platform_get_drvdata(pdev); ++ struct spi_controller *ctlr = platform_get_drvdata(pdev); ++ struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); ++ ++ spi_controller_get(ctlr); ++ ++ spi_unregister_controller(ctlr); + + zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0); ++ ++ spi_controller_put(ctlr); + } + + static const struct of_device_id zynq_qspi_of_match[] = { diff --git a/queue-6.1/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch b/queue-6.1/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..3214f286dc --- /dev/null +++ b/queue-6.1/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch @@ -0,0 +1,142 @@ +From stable+bounces-247027-greg=kroah.com@vger.kernel.org Thu May 14 01:11:40 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:19 -0400 +Subject: spi: zynq-qspi: Simplify clock handling with devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Pei Xiao , Michal Simek , Mark Brown , Sasha Levin +Message-ID: <20260513193420.3938432-4-sashal@kernel.org> + +From: Pei Xiao + +[ Upstream commit 1f8fd9490e3184e9a2394df2e682901a1d57ce71 ] + +Replace devm_clk_get() followed by clk_prepare_enable() with +devm_clk_get_enabled() for both "pclk" and "ref_clk". This removes +the need for explicit clock enable and disable calls, as the managed +API automatically disables the clocks on device removal or probe +failure. + +Remove the now-unnecessary clk_disable_unprepare() calls from the +probe error paths and the remove callback. Simplify error handling +by jumping directly to the remove_ctlr label. + +Signed-off-by: Pei Xiao +Acked-by: Michal Simek +Link: https://patch.msgid.link/24043625f89376da36feca2408f990a85be7ab36.1775555500.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Stable-dep-of: c9c012706c9f ("spi: zynq-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 42 ++++++------------------------------------ + 1 file changed, 6 insertions(+), 36 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -379,21 +379,10 @@ static int zynq_qspi_setup_op(struct spi + { + struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr); +- int ret; + + if (ctlr->busy) + return -EBUSY; + +- ret = clk_enable(qspi->refclk); +- if (ret) +- return ret; +- +- ret = clk_enable(qspi->pclk); +- if (ret) { +- clk_disable(qspi->refclk); +- return ret; +- } +- + zynq_qspi_write(qspi, ZYNQ_QSPI_ENABLE_OFFSET, + ZYNQ_QSPI_ENABLE_ENABLE_MASK); + +@@ -659,7 +648,7 @@ static int zynq_qspi_probe(struct platfo + goto remove_ctlr; + } + +- xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); ++ xqspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); + if (IS_ERR(xqspi->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + ret = PTR_ERR(xqspi->pclk); +@@ -668,36 +657,24 @@ static int zynq_qspi_probe(struct platfo + + init_completion(&xqspi->data_completion); + +- xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); ++ xqspi->refclk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); + if (IS_ERR(xqspi->refclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->refclk); + goto remove_ctlr; + } + +- ret = clk_prepare_enable(xqspi->pclk); +- if (ret) { +- dev_err(&pdev->dev, "Unable to enable APB clock.\n"); +- goto remove_ctlr; +- } +- +- ret = clk_prepare_enable(xqspi->refclk); +- if (ret) { +- dev_err(&pdev->dev, "Unable to enable device clock.\n"); +- goto clk_dis_pclk; +- } +- + xqspi->irq = platform_get_irq(pdev, 0); + if (xqspi->irq < 0) { + ret = xqspi->irq; +- goto clk_dis_all; ++ goto remove_ctlr; + } + ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq, + 0, pdev->name, xqspi); + if (ret != 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "request_irq failed\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } + + ret = of_property_read_u32(np, "num-cs", +@@ -707,7 +684,7 @@ static int zynq_qspi_probe(struct platfo + } else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) { + ret = -EINVAL; + dev_err(&pdev->dev, "only 2 chip selects are available\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } else { + ctlr->num_chipselect = num_cs; + } +@@ -725,15 +702,11 @@ static int zynq_qspi_probe(struct platfo + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { + dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } + + return ret; + +-clk_dis_all: +- clk_disable_unprepare(xqspi->refclk); +-clk_dis_pclk: +- clk_disable_unprepare(xqspi->pclk); + remove_ctlr: + spi_controller_put(ctlr); + +@@ -755,9 +728,6 @@ static void zynq_qspi_remove(struct plat + struct zynq_qspi *xqspi = platform_get_drvdata(pdev); + + zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0); +- +- clk_disable_unprepare(xqspi->refclk); +- clk_disable_unprepare(xqspi->pclk); + } + + static const struct of_device_id zynq_qspi_of_match[] = { diff --git a/queue-6.1/spi-zynq-qspi-switch-to-use-modern-name.patch b/queue-6.1/spi-zynq-qspi-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..f68bc39929 --- /dev/null +++ b/queue-6.1/spi-zynq-qspi-switch-to-use-modern-name.patch @@ -0,0 +1,145 @@ +From stable+bounces-247026-greg=kroah.com@vger.kernel.org Thu May 14 01:04:32 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 15:34:18 -0400 +Subject: spi: zynq-qspi: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513193420.3938432-3-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 178ebb0c505b0a35edb4fb2a0e23a1f29e1db14d ] + +Change legacy name master/slave to modern name host/target or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-24-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: c9c012706c9f ("spi: zynq-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -54,10 +54,10 @@ + #define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */ + + /* +- * QSPI Configuration Register - Baud rate and slave select ++ * QSPI Configuration Register - Baud rate and target select + * + * These are the values used in the calculation of baud rate divisor and +- * setting the slave select. ++ * setting the target select. + */ + #define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */ + #define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */ +@@ -164,14 +164,14 @@ static inline void zynq_qspi_write(struc + * + * The default settings of the QSPI controller's configurable parameters on + * reset are +- * - Master mode ++ * - Host mode + * - Baud rate divisor is set to 2 + * - Tx threshold set to 1l Rx threshold set to 32 + * - Flash memory interface mode enabled + * - Size of the word to be transferred as 8 bit + * This function performs the following actions + * - Disable and clear all the interrupts +- * - Enable manual slave select ++ * - Enable manual target select + * - Enable manual start + * - Deselect all the chip select lines + * - Set the size of the word to be transferred as 32 bit +@@ -289,7 +289,7 @@ static void zynq_qspi_txfifo_op(struct z + */ + static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) + { +- struct spi_controller *ctlr = spi->master; ++ struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); + u32 config_reg; + +@@ -377,7 +377,7 @@ static int zynq_qspi_config_op(struct zy + */ + static int zynq_qspi_setup_op(struct spi_device *spi) + { +- struct spi_controller *ctlr = spi->master; ++ struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr); + int ret; + +@@ -534,7 +534,7 @@ static irqreturn_t zynq_qspi_irq(int irq + static int zynq_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +- struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master); ++ struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller); + int err = 0, i; + u8 *tmpbuf; + +@@ -646,7 +646,7 @@ static int zynq_qspi_probe(struct platfo + struct zynq_qspi *xqspi; + u32 num_cs; + +- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); ++ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi)); + if (!ctlr) + return -ENOMEM; + +@@ -656,14 +656,14 @@ static int zynq_qspi_probe(struct platfo + xqspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xqspi->regs)) { + ret = PTR_ERR(xqspi->regs); +- goto remove_master; ++ goto remove_ctlr; + } + + xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(xqspi->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + ret = PTR_ERR(xqspi->pclk); +- goto remove_master; ++ goto remove_ctlr; + } + + init_completion(&xqspi->data_completion); +@@ -672,13 +672,13 @@ static int zynq_qspi_probe(struct platfo + if (IS_ERR(xqspi->refclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->refclk); +- goto remove_master; ++ goto remove_ctlr; + } + + ret = clk_prepare_enable(xqspi->pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APB clock.\n"); +- goto remove_master; ++ goto remove_ctlr; + } + + ret = clk_prepare_enable(xqspi->refclk); +@@ -724,7 +724,7 @@ static int zynq_qspi_probe(struct platfo + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { +- dev_err(&pdev->dev, "spi_register_master failed\n"); ++ dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); + goto clk_dis_all; + } + +@@ -734,7 +734,7 @@ clk_dis_all: + clk_disable_unprepare(xqspi->refclk); + clk_dis_pclk: + clk_disable_unprepare(xqspi->pclk); +-remove_master: ++remove_ctlr: + spi_controller_put(ctlr); + + return ret; diff --git a/queue-6.1/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-6.1/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch new file mode 100644 index 0000000000..8c3b82b851 --- /dev/null +++ b/queue-6.1/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch @@ -0,0 +1,112 @@ +From stable+bounces-260814-greg=kroah.com@vger.kernel.org Sat Jun 6 01:20:34 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:50:25 -0400 +Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir() +To: stable@vger.kernel.org +Cc: Michael Bommarito , Mika Westerberg , Sasha Levin +Message-ID: <20260605195025.2190023-1-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab ] + +A DIRECTORY entry's value field is used as the dir_offset for a +recursive call into __tb_property_parse_dir() with no depth counter. +A crafted peer that chains DIRECTORY entries into a back-reference +loop drives the parser until the kernel stack is exhausted and the +guard page fires. Any untrusted XDomain peer (cable, dock, in-line +inspector, adjacent host) that reaches the PROPERTIES_REQUEST +control-plane exchange can trigger this without authentication. + +Thread a depth counter through tb_property_parse() and +__tb_property_parse_dir(), and reject blocks that exceed +TB_PROPERTY_MAX_DEPTH = 8. That is comfortably larger than any +observed legitimate XDomain layout. + +Operators who do not need XDomain host-to-host discovery can disable +the path entirely with thunderbolt.xdomain=0 on the kernel command +line. + +Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-6 +Assisted-by: Codex:gpt-5-4 +Signed-off-by: Michael Bommarito +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/thunderbolt/property.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/thunderbolt/property.c ++++ b/drivers/thunderbolt/property.c +@@ -35,10 +35,11 @@ struct tb_property_dir_entry { + }; + + #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 ++#define TB_PROPERTY_MAX_DEPTH 8 + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, + size_t block_len, unsigned int dir_offset, size_t dir_len, +- bool is_root); ++ bool is_root, unsigned int depth); + + static inline void parse_dwdata(void *dst, const void *src, size_t dwords) + { +@@ -99,7 +100,8 @@ tb_property_alloc(const char *key, enum + } + + static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, +- const struct tb_property_entry *entry) ++ const struct tb_property_entry *entry, ++ unsigned int depth) + { + char key[TB_PROPERTY_KEY_SIZE + 1]; + struct tb_property *property; +@@ -120,7 +122,7 @@ static struct tb_property *tb_property_p + switch (property->type) { + case TB_PROPERTY_TYPE_DIRECTORY: + dir = __tb_property_parse_dir(block, block_len, entry->value, +- entry->length, false); ++ entry->length, false, depth + 1); + if (!dir) { + kfree(property); + return NULL; +@@ -165,13 +167,17 @@ static struct tb_property *tb_property_p + } + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, +- size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root) ++ size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root, ++ unsigned int depth) + { + const struct tb_property_entry *entries; + size_t i, content_len, nentries; + unsigned int content_offset; + struct tb_property_dir *dir; + ++ if (depth > TB_PROPERTY_MAX_DEPTH) ++ return NULL; ++ + dir = kzalloc(sizeof(*dir), GFP_KERNEL); + if (!dir) + return NULL; +@@ -206,7 +212,7 @@ static struct tb_property_dir *__tb_prop + for (i = 0; i < nentries; i++) { + struct tb_property *property; + +- property = tb_property_parse(block, block_len, &entries[i]); ++ property = tb_property_parse(block, block_len, &entries[i], depth); + if (!property) { + tb_property_free_dir(dir); + return NULL; +@@ -243,7 +249,7 @@ struct tb_property_dir *tb_property_pars + return NULL; + + return __tb_property_parse_dir(block, block_len, 0, rootdir->length, +- true); ++ true, 0); + } + + /** diff --git a/queue-6.1/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch b/queue-6.1/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch new file mode 100644 index 0000000000..cfe0f60a0b --- /dev/null +++ b/queue-6.1/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch @@ -0,0 +1,56 @@ +From stable+bounces-245090-greg=kroah.com@vger.kernel.org Mon May 11 05:40:51 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 20:10:41 -0400 +Subject: tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func() +To: stable@vger.kernel.org +Cc: David Carlier , Masami Hiramatsu , Mathieu Desnoyers , "Steven Rostedt (Google)" , Sasha Levin +Message-ID: <20260511001041.752593-1-sashal@kernel.org> + +From: David Carlier + +[ Upstream commit fad217e16fded7f3c09f8637b0f6a224d58b5f2e ] + +When a tracepoint goes through the 0 -> 1 transition, tracepoint_add_func() +invokes the subsystem's ext->regfunc() before attempting to install the +new probe via func_add(). If func_add() then fails (for example, when +allocate_probes() cannot allocate a new probe array under memory pressure +and returns -ENOMEM), the function returns the error without calling the +matching ext->unregfunc(), leaving the side effects of regfunc() behind +with no installed probe to justify them. + +For syscall tracepoints this is particularly unpleasant: syscall_regfunc() +bumps sys_tracepoint_refcount and sets SYSCALL_TRACEPOINT on every task. +After a leaked failure, the refcount is stuck at a non-zero value with no +consumer, and every task continues paying the syscall trace entry/exit +overhead until reboot. Other subsystems providing regfunc()/unregfunc() +pairs exhibit similarly scoped persistent state. + +Mirror the existing 1 -> 0 cleanup and call ext->unregfunc() in the +func_add() error path, gated on the same condition used there so the +unwind is symmetric with the registration. + +Fixes: 8cf868affdc4 ("tracing: Have the reg function allow to fail") +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Link: https://patch.msgid.link/20260413190601.21993-1-devnexen@gmail.com +Signed-off-by: David Carlier +Signed-off-by: Steven Rostedt (Google) +[ changed `tp->ext->unregfunc` to `tp->unregfunc` to match older struct layout ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/tracepoint.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/kernel/tracepoint.c ++++ b/kernel/tracepoint.c +@@ -337,6 +337,8 @@ static int tracepoint_add_func(struct tr + lockdep_is_held(&tracepoints_mutex)); + old = func_add(&tp_funcs, func, prio); + if (IS_ERR(old)) { ++ if (tp->unregfunc && !static_key_enabled(&tp->key)) ++ tp->unregfunc(); + WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM); + return PTR_ERR(old); + } diff --git a/queue-6.1/tracing-probes-limit-size-of-event-probe-to-3k.patch b/queue-6.1/tracing-probes-limit-size-of-event-probe-to-3k.patch new file mode 100644 index 0000000000..28d2cebcc2 --- /dev/null +++ b/queue-6.1/tracing-probes-limit-size-of-event-probe-to-3k.patch @@ -0,0 +1,70 @@ +From stable+bounces-247799-greg=kroah.com@vger.kernel.org Fri May 15 20:26:35 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 10:48:40 -0400 +Subject: tracing/probes: Limit size of event probe to 3K +To: stable@vger.kernel.org +Cc: Steven Rostedt , Mathieu Desnoyers , "Masami Hiramatsu (Google)" , Sasha Levin +Message-ID: <20260515144840.3249487-1-sashal@kernel.org> + +From: Steven Rostedt + +[ Upstream commit b2aa3b4d64e460ac606f386c24e7d8a873ce6f1a ] + +There currently isn't a max limit an event probe can be. One could make an +event greater than PAGE_SIZE, which makes the event useless because if +it's bigger than the max event that can be recorded into the ring buffer, +then it will never be recorded. + +A event probe should never need to be greater than 3K, so make that the +max size. As long as the max is less than the max that can be recorded +onto the ring buffer, it should be fine. + +Cc: stable@vger.kernel.org +Cc: Mathieu Desnoyers +Acked-by: Masami Hiramatsu (Google) +Fixes: 93ccae7a22274 ("tracing/kprobes: Support basic types on dynamic events") +Link: https://patch.msgid.link/20260428122302.706610ba@gandalf.local.home +Signed-off-by: Steven Rostedt +[ changed `ctx->offset` to `offset` and `goto fail` to `goto out` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/trace_probe.c | 6 ++++++ + kernel/trace/trace_probe.h | 4 +++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -651,6 +651,12 @@ static int traceprobe_parse_probe_arg_bo + parg->offset = *size; + *size += parg->type->size * (parg->count ?: 1); + ++ if (*size > MAX_PROBE_EVENT_SIZE) { ++ ret = -E2BIG; ++ trace_probe_log_err(offset, EVENT_TOO_BIG); ++ goto out; ++ } ++ + ret = -ENOMEM; + if (parg->count) { + len = strlen(parg->type->fmttype) + 6; +--- a/kernel/trace/trace_probe.h ++++ b/kernel/trace/trace_probe.h +@@ -33,6 +33,7 @@ + #define MAX_ARRAY_LEN 64 + #define MAX_ARG_NAME_LEN 32 + #define MAX_STRING_SIZE PATH_MAX ++#define MAX_PROBE_EVENT_SIZE 3072 + + /* Reserved field names */ + #define FIELD_STRING_IP "__probe_ip" +@@ -458,7 +459,8 @@ extern int traceprobe_define_arg_fields( + C(NO_EVENT_INFO, "This requires both group and event name to attach"),\ + C(BAD_ATTACH_EVENT, "Attached event does not exist"),\ + C(BAD_ATTACH_ARG, "Attached event does not have this field"),\ +- C(NO_EP_FILTER, "No filter rule after 'if'"), ++ C(NO_EP_FILTER, "No filter rule after 'if'"), \ ++ C(EVENT_TOO_BIG, "Event too big (too many fields?)"), + + #undef C + #define C(a, b) TP_ERR_##a diff --git a/queue-6.1/tty-serial-qcom-geni-serial-align-define-values.patch b/queue-6.1/tty-serial-qcom-geni-serial-align-define-values.patch new file mode 100644 index 0000000000..2cdcb39943 --- /dev/null +++ b/queue-6.1/tty-serial-qcom-geni-serial-align-define-values.patch @@ -0,0 +1,115 @@ +From stable+bounces-260846-greg=kroah.com@vger.kernel.org Sat Jun 6 08:19:26 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 22:47:08 -0400 +Subject: tty: serial: qcom-geni-serial: align #define values +To: stable@vger.kernel.org +Cc: Bartosz Golaszewski , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606024709.2514691-2-sashal@kernel.org> + +From: Bartosz Golaszewski + +[ Upstream commit 6cde11dbf4b65170eeefba48df730c93d75e01a3 ] + +Keep the #define symbols aligned for better readability. + +Signed-off-by: Bartosz Golaszewski +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20221229155030.418800-5-brgl@bgdev.pl +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/qcom_geni_serial.c | 60 +++++++++++++++++----------------- + 1 file changed, 30 insertions(+), 30 deletions(-) + +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -39,57 +39,57 @@ + #define SE_UART_MANUAL_RFR 0x2ac + + /* SE_UART_TRANS_CFG */ +-#define UART_TX_PAR_EN BIT(0) +-#define UART_CTS_MASK BIT(1) ++#define UART_TX_PAR_EN BIT(0) ++#define UART_CTS_MASK BIT(1) + + /* SE_UART_TX_STOP_BIT_LEN */ +-#define TX_STOP_BIT_LEN_1 0 +-#define TX_STOP_BIT_LEN_2 2 ++#define TX_STOP_BIT_LEN_1 0 ++#define TX_STOP_BIT_LEN_2 2 + + /* SE_UART_RX_TRANS_CFG */ +-#define UART_RX_PAR_EN BIT(3) ++#define UART_RX_PAR_EN BIT(3) + + /* SE_UART_RX_WORD_LEN */ +-#define RX_WORD_LEN_MASK GENMASK(9, 0) ++#define RX_WORD_LEN_MASK GENMASK(9, 0) + + /* SE_UART_RX_STALE_CNT */ +-#define RX_STALE_CNT GENMASK(23, 0) ++#define RX_STALE_CNT GENMASK(23, 0) + + /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */ +-#define PAR_CALC_EN BIT(0) +-#define PAR_EVEN 0x00 +-#define PAR_ODD 0x01 +-#define PAR_SPACE 0x10 ++#define PAR_CALC_EN BIT(0) ++#define PAR_EVEN 0x00 ++#define PAR_ODD 0x01 ++#define PAR_SPACE 0x10 + + /* SE_UART_MANUAL_RFR register fields */ +-#define UART_MANUAL_RFR_EN BIT(31) +-#define UART_RFR_NOT_READY BIT(1) +-#define UART_RFR_READY BIT(0) ++#define UART_MANUAL_RFR_EN BIT(31) ++#define UART_RFR_NOT_READY BIT(1) ++#define UART_RFR_READY BIT(0) + + /* UART M_CMD OP codes */ +-#define UART_START_TX 0x1 ++#define UART_START_TX 0x1 + /* UART S_CMD OP codes */ +-#define UART_START_READ 0x1 ++#define UART_START_READ 0x1 + +-#define UART_OVERSAMPLING 32 +-#define STALE_TIMEOUT 16 +-#define DEFAULT_BITS_PER_CHAR 10 +-#define GENI_UART_CONS_PORTS 1 +-#define GENI_UART_PORTS 3 +-#define DEF_FIFO_DEPTH_WORDS 16 +-#define DEF_TX_WM 2 +-#define DEF_FIFO_WIDTH_BITS 32 +-#define UART_RX_WM 2 ++#define UART_OVERSAMPLING 32 ++#define STALE_TIMEOUT 16 ++#define DEFAULT_BITS_PER_CHAR 10 ++#define GENI_UART_CONS_PORTS 1 ++#define GENI_UART_PORTS 3 ++#define DEF_FIFO_DEPTH_WORDS 16 ++#define DEF_TX_WM 2 ++#define DEF_FIFO_WIDTH_BITS 32 ++#define UART_RX_WM 2 + + /* SE_UART_LOOPBACK_CFG */ +-#define RX_TX_SORTED BIT(0) +-#define CTS_RTS_SORTED BIT(1) +-#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED) ++#define RX_TX_SORTED BIT(0) ++#define CTS_RTS_SORTED BIT(1) ++#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED) + + /* UART pin swap value */ +-#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0) ++#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0) + #define IO_MACRO_IO0_SEL 0x3 +-#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) ++#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) + #define IO_MACRO_IO2_IO3_SWAP 0x4640 + + /* We always configure 4 bytes per FIFO word */ diff --git a/queue-6.1/tty-serial-qcom-geni-serial-remove-unused-symbols.patch b/queue-6.1/tty-serial-qcom-geni-serial-remove-unused-symbols.patch new file mode 100644 index 0000000000..b97d6ea515 --- /dev/null +++ b/queue-6.1/tty-serial-qcom-geni-serial-remove-unused-symbols.patch @@ -0,0 +1,73 @@ +From stable+bounces-260845-greg=kroah.com@vger.kernel.org Sat Jun 6 08:17:17 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 22:47:07 -0400 +Subject: tty: serial: qcom-geni-serial: remove unused symbols +To: stable@vger.kernel.org +Cc: Bartosz Golaszewski , Konrad Dybcio , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606024709.2514691-1-sashal@kernel.org> + +From: Bartosz Golaszewski + +[ Upstream commit 68c6bd92c86cbc4937834c79963b27c77ee3bf51 ] + +Drop all unused symbols from the driver. + +Signed-off-by: Bartosz Golaszewski +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20221229155030.418800-4-brgl@bgdev.pl +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/qcom_geni_serial.c | 15 --------------- + 1 file changed, 15 deletions(-) + +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -42,20 +42,11 @@ + #define UART_TX_PAR_EN BIT(0) + #define UART_CTS_MASK BIT(1) + +-/* SE_UART_TX_WORD_LEN */ +-#define TX_WORD_LEN_MSK GENMASK(9, 0) +- + /* SE_UART_TX_STOP_BIT_LEN */ +-#define TX_STOP_BIT_LEN_MSK GENMASK(23, 0) + #define TX_STOP_BIT_LEN_1 0 +-#define TX_STOP_BIT_LEN_1_5 1 + #define TX_STOP_BIT_LEN_2 2 + +-/* SE_UART_TX_TRANS_LEN */ +-#define TX_TRANS_LEN_MSK GENMASK(23, 0) +- + /* SE_UART_RX_TRANS_CFG */ +-#define UART_RX_INS_STATUS_BIT BIT(2) + #define UART_RX_PAR_EN BIT(3) + + /* SE_UART_RX_WORD_LEN */ +@@ -66,12 +57,9 @@ + + /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */ + #define PAR_CALC_EN BIT(0) +-#define PAR_MODE_MSK GENMASK(2, 1) +-#define PAR_MODE_SHFT 1 + #define PAR_EVEN 0x00 + #define PAR_ODD 0x01 + #define PAR_SPACE 0x10 +-#define PAR_MARK 0x11 + + /* SE_UART_MANUAL_RFR register fields */ + #define UART_MANUAL_RFR_EN BIT(31) +@@ -80,11 +68,8 @@ + + /* UART M_CMD OP codes */ + #define UART_START_TX 0x1 +-#define UART_START_BREAK 0x4 +-#define UART_STOP_BREAK 0x5 + /* UART S_CMD OP codes */ + #define UART_START_READ 0x1 +-#define UART_PARAM 0x1 + + #define UART_OVERSAMPLING 32 + #define STALE_TIMEOUT 16 diff --git a/queue-6.1/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch b/queue-6.1/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch new file mode 100644 index 0000000000..3416851f5a --- /dev/null +++ b/queue-6.1/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch @@ -0,0 +1,85 @@ +From stable+bounces-260728-greg=kroah.com@vger.kernel.org Fri Jun 5 21:15:32 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:31:04 -0400 +Subject: tty: serial: samsung: Remove redundant port lock acquisition in rx helpers +To: stable@vger.kernel.org +Cc: Tudor Ambarus , stable , John Ogness , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605153104.1929085-3-sashal@kernel.org> + +From: Tudor Ambarus + +[ Upstream commit a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 ] + +Sashiko identified a deadlock when the console flow is engaged [1]. + +When console flow control is enabled (UPF_CONS_FLOW), +s3c24xx_serial_stop_tx() calls s3c24xx_serial_rx_enable() and +s3c24xx_serial_start_tx() calls s3c24xx_serial_rx_disable(). + +The serial core framework invokes the .stop_tx() and .start_tx() +callbacks with the port->lock spinlock already held. Furthermore, all +internal driver paths that invoke stop_tx (such as the DMA TX +completion handler s3c24xx_serial_tx_dma_complete() or the PIO TX IRQ +handler s3c24xx_serial_tx_irq()) also acquire port->lock prior to +calling it. (Note that s3c24xx_serial_start_tx() is only invoked by the +serial core). + +However, s3c24xx_serial_rx_enable() and s3c24xx_serial_rx_disable() +unconditionally attempt to acquire port->lock again using +uart_port_lock_irqsave(). Since spinlocks are not recursive, this +causes a deadlock on the same CPU when console flow control is engaged. + +Remove the redundant lock acquisition from both rx helper functions. + +Cc: stable +Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") +Reported-by: John Ogness +Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1] +Signed-off-by: Tudor Ambarus +Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -247,12 +247,9 @@ static int s3c24xx_serial_txempty_nofifo + static void s3c24xx_serial_rx_enable(struct uart_port *port) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned long flags; + int count = 10000; + u32 ucon, ufcon; + +- uart_port_lock_irqsave(port, &flags); +- + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); + +@@ -265,23 +262,18 @@ static void s3c24xx_serial_rx_enable(str + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 1; +- uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_rx_disable(struct uart_port *port) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned long flags; + u32 ucon; + +- uart_port_lock_irqsave(port, &flags); +- + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 0; +- uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_stop_tx(struct uart_port *port) diff --git a/queue-6.1/tty-serial-samsung-use-u32-for-register-interactions.patch b/queue-6.1/tty-serial-samsung-use-u32-for-register-interactions.patch new file mode 100644 index 0000000000..f5859c2cca --- /dev/null +++ b/queue-6.1/tty-serial-samsung-use-u32-for-register-interactions.patch @@ -0,0 +1,354 @@ +From stable+bounces-260727-greg=kroah.com@vger.kernel.org Fri Jun 5 21:15:51 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:31:03 -0400 +Subject: tty: serial: samsung: use u32 for register interactions +To: stable@vger.kernel.org +Cc: Tudor Ambarus , Sam Protsenko , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605153104.1929085-2-sashal@kernel.org> + +From: Tudor Ambarus + +[ Upstream commit 032a725c16add79332d774348d7ad7d0d4b86479 ] + +All registers of the IP have 32 bits. Use u32 variables when reading +or writing from/to the registers. The purpose of those variables becomes +clearer. + +Reviewed-by: Sam Protsenko +Signed-off-by: Tudor Ambarus +Link: https://lore.kernel.org/r/20240119104526.1221243-9-tudor.ambarus@linaro.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a3bb136bff5e ("tty: serial: samsung: Remove redundant port lock acquisition in rx helpers") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/samsung_tty.c | 80 +++++++++++++++++++-------------------- + 1 file changed, 40 insertions(+), 40 deletions(-) + +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -202,7 +202,7 @@ static void wr_reg(const struct uart_por + /* Byte-order aware bit setting/clearing functions. */ + + static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, +- unsigned int reg) ++ u32 reg) + { + unsigned long flags; + u32 val; +@@ -215,7 +215,7 @@ static inline void s3c24xx_set_bit(const + } + + static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, +- unsigned int reg) ++ u32 reg) + { + unsigned long flags; + u32 val; +@@ -248,8 +248,8 @@ static void s3c24xx_serial_rx_enable(str + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ucon, ufcon; + int count = 10000; ++ u32 ucon, ufcon; + + uart_port_lock_irqsave(port, &flags); + +@@ -272,7 +272,7 @@ static void s3c24xx_serial_rx_disable(st + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ucon; ++ u32 ucon; + + uart_port_lock_irqsave(port, &flags); + +@@ -597,7 +597,7 @@ static inline const struct s3c2410_uartc + } + + static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, +- unsigned long ufstat) ++ u32 ufstat) + { + const struct s3c24xx_uart_info *info = ourport->info; + +@@ -669,7 +669,7 @@ static void s3c64xx_start_rx_dma(struct + static void enable_rx_dma(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ucon; ++ u32 ucon; + + /* set Rx mode to DMA mode */ + ucon = rd_regl(port, S3C2410_UCON); +@@ -692,7 +692,7 @@ static void enable_rx_dma(struct s3c24xx + static void enable_rx_pio(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ucon; ++ u32 ucon; + + /* set Rx mode to DMA mode */ + ucon = rd_regl(port, S3C2410_UCON); +@@ -717,13 +717,14 @@ static void s3c24xx_serial_rx_drain_fifo + + static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) + { +- unsigned int utrstat, received; + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + struct s3c24xx_uart_dma *dma = ourport->dma; + struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); + struct tty_port *t = &port->state->port; + struct dma_tx_state state; ++ unsigned int received; ++ u32 utrstat; + + utrstat = rd_regl(port, S3C2410_UTRSTAT); + rd_regl(port, S3C2410_UFSTAT); +@@ -765,9 +766,10 @@ finish: + static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) + { + struct uart_port *port = &ourport->port; +- unsigned int ufcon, ch, flag, ufstat, uerstat; + unsigned int fifocnt = 0; + int max_count = port->fifosize; ++ u32 ufcon, ufstat, uerstat; ++ u8 ch, flag; + + while (max_count-- > 0) { + /* +@@ -951,7 +953,7 @@ static irqreturn_t s3c64xx_serial_handle + { + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; +- unsigned int pend = rd_regl(port, S3C64XX_UINTP); ++ u32 pend = rd_regl(port, S3C64XX_UINTP); + irqreturn_t ret = IRQ_HANDLED; + + if (pend & S3C64XX_UINTM_RXD_MSK) { +@@ -970,7 +972,7 @@ static irqreturn_t apple_serial_handle_i + { + const struct s3c24xx_uart_port *ourport = id; + const struct uart_port *port = &ourport->port; +- unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); ++ u32 pend = rd_regl(port, S3C2410_UTRSTAT); + irqreturn_t ret = IRQ_NONE; + + if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { +@@ -989,8 +991,8 @@ static irqreturn_t apple_serial_handle_i + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); +- unsigned long ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ufstat = rd_regl(port, S3C2410_UFSTAT); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + if ((ufstat & info->tx_fifomask) != 0 || +@@ -1005,7 +1007,7 @@ static unsigned int s3c24xx_serial_tx_em + /* no modem control lines */ + static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) + { +- unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); ++ u32 umstat = rd_reg(port, S3C2410_UMSTAT); + + if (umstat & S3C2410_UMSTAT_CTS) + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +@@ -1015,8 +1017,8 @@ static unsigned int s3c24xx_serial_get_m + + static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) + { +- unsigned int umcon = rd_regl(port, S3C2410_UMCON); +- unsigned int ucon = rd_regl(port, S3C2410_UCON); ++ u32 umcon = rd_regl(port, S3C2410_UMCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + if (mctrl & TIOCM_RTS) + umcon |= S3C2410_UMCOM_RTS_LOW; +@@ -1036,7 +1038,7 @@ static void s3c24xx_serial_set_mctrl(str + static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) + { + unsigned long flags; +- unsigned int ucon; ++ u32 ucon; + + uart_port_lock_irqsave(port, &flags); + +@@ -1217,7 +1219,7 @@ static void apple_s5l_serial_shutdown(st + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + +- unsigned int ucon; ++ u32 ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | +@@ -1285,7 +1287,7 @@ static int s3c64xx_serial_startup(struct + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ufcon; ++ u32 ufcon; + int ret; + + wr_regl(port, S3C64XX_UINTM, 0xf); +@@ -1330,7 +1332,7 @@ static int apple_s5l_serial_startup(stru + { + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; +- unsigned int ufcon; ++ u32 ufcon; + int ret; + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); +@@ -1415,7 +1417,7 @@ static void s3c24xx_serial_pm(struct uar + static inline int s3c24xx_serial_getsource(struct uart_port *port) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned int ucon; ++ u32 ucon; + + if (info->num_clks == 1) + return 0; +@@ -1429,7 +1431,7 @@ static void s3c24xx_serial_setsource(str + unsigned int clk_sel) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned int ucon; ++ u32 ucon; + + if (info->num_clks == 1) + return; +@@ -1548,9 +1550,8 @@ static void s3c24xx_serial_set_termios(s + struct clk *clk = ERR_PTR(-EINVAL); + unsigned long flags; + unsigned int baud, quot, clk_sel = 0; +- unsigned int ulcon; +- unsigned int umcon; + unsigned int udivslot = 0; ++ u32 ulcon, umcon; + + /* + * We don't support modem control lines. +@@ -1857,7 +1858,7 @@ static void s3c24xx_serial_resetport(str + const struct s3c2410_uartcfg *cfg) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ucon = rd_regl(port, S3C2410_UCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + ucon &= (info->clksel_mask | info->ucon_mask); + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); +@@ -2100,7 +2101,7 @@ static int s3c24xx_serial_init_port(stru + wr_regl(port, S3C64XX_UINTSP, 0xf); + break; + case TYPE_APPLE_S5L: { +- unsigned int ucon; ++ u32 ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | +@@ -2312,7 +2313,7 @@ static int s3c24xx_serial_resume_noirq(s + /* restore IRQ mask */ + switch (ourport->info->type) { + case TYPE_S3C6400: { +- unsigned int uintm = 0xf; ++ u32 uintm = 0xf; + + if (ourport->tx_enabled) + uintm &= ~S3C64XX_UINTM_TXD_MSK; +@@ -2328,7 +2329,7 @@ static int s3c24xx_serial_resume_noirq(s + break; + } + case TYPE_APPLE_S5L: { +- unsigned int ucon; ++ u32 ucon; + int ret; + + ret = clk_prepare_enable(ourport->clk); +@@ -2391,10 +2392,10 @@ static const struct dev_pm_ops s3c24xx_s + static struct uart_port *cons_uart; + + static int +-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) ++s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon) + { + const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); +- unsigned long ufstat, utrstat; ++ u32 ufstat, utrstat; + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + /* fifo mode - check amount of data in fifo registers... */ +@@ -2410,7 +2411,7 @@ s3c24xx_serial_console_txrdy(struct uart + } + + static bool +-s3c24xx_port_configured(unsigned int ucon) ++s3c24xx_port_configured(u32 ucon) + { + /* consider the serial port configured if the tx/rx mode set */ + return (ucon & 0xf) != 0; +@@ -2425,7 +2426,7 @@ s3c24xx_port_configured(unsigned int uco + static int s3c24xx_serial_get_poll_char(struct uart_port *port) + { + const struct s3c24xx_uart_port *ourport = to_ourport(port); +- unsigned int ufstat; ++ u32 ufstat; + + ufstat = rd_regl(port, S3C2410_UFSTAT); + if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) +@@ -2437,8 +2438,8 @@ static int s3c24xx_serial_get_poll_char( + static void s3c24xx_serial_put_poll_char(struct uart_port *port, + unsigned char c) + { +- unsigned int ufcon = rd_regl(port, S3C2410_UFCON); +- unsigned int ucon = rd_regl(port, S3C2410_UCON); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ucon = rd_regl(port, S3C2410_UCON); + + /* not possible to xmit on unconfigured port */ + if (!s3c24xx_port_configured(ucon)) +@@ -2454,7 +2455,7 @@ static void s3c24xx_serial_put_poll_char + static void + s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch) + { +- unsigned int ufcon = rd_regl(port, S3C2410_UFCON); ++ u32 ufcon = rd_regl(port, S3C2410_UFCON); + + while (!s3c24xx_serial_console_txrdy(port, ufcon)) + cpu_relax(); +@@ -2465,7 +2466,7 @@ static void + s3c24xx_serial_console_write(struct console *co, const char *s, + unsigned int count) + { +- unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); ++ u32 ucon = rd_regl(cons_uart, S3C2410_UCON); + unsigned long flags; + bool locked = true; + +@@ -2492,11 +2493,9 @@ s3c24xx_serial_get_options(struct uart_p + int *parity, int *bits) + { + struct clk *clk; +- unsigned int ulcon; +- unsigned int ucon; +- unsigned int ubrdiv; + unsigned long rate; + unsigned int clk_sel; ++ u32 ulcon, ucon, ubrdiv; + char clk_name[MAX_CLK_NAME_LENGTH]; + + ulcon = rd_regl(port, S3C2410_ULCON); +@@ -3010,7 +3009,8 @@ static int samsung_early_read(struct con + { + struct earlycon_device *dev = con->data; + const struct samsung_early_console_data *data = dev->port.private_data; +- int ch, ufstat, num_read = 0; ++ int num_read = 0; ++ u32 ch, ufstat; + + while (num_read < n) { + ufstat = rd_regl(&dev->port, S3C2410_UFSTAT); diff --git a/queue-6.1/udf-fix-partition-descriptor-append-bookkeeping.patch b/queue-6.1/udf-fix-partition-descriptor-append-bookkeeping.patch new file mode 100644 index 0000000000..cc972ebac9 --- /dev/null +++ b/queue-6.1/udf-fix-partition-descriptor-append-bookkeeping.patch @@ -0,0 +1,61 @@ +From stable+bounces-244831-greg=kroah.com@vger.kernel.org Sat May 9 02:47:36 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 17:17:31 -0400 +Subject: udf: fix partition descriptor append bookkeeping +To: stable@vger.kernel.org +Cc: Seohyeon Maeng , Jan Kara , Sasha Levin +Message-ID: <20260508211731.1959991-1-sashal@kernel.org> + +From: Seohyeon Maeng + +[ Upstream commit 08841b06fa64d8edbd1a21ca6e613420c90cc4b8 ] + +Mounting a crafted UDF image with repeated partition descriptors can +trigger a heap out-of-bounds write in part_descs_loc[]. + +handle_partition_descriptor() deduplicates entries by partition number, +but appended slots never record partnum. As a result duplicate +Partition Descriptors are appended repeatedly and num_part_descs keeps +growing. + +Once the table is full, the growth path still sizes the allocation from +partnum even though inserts are indexed by num_part_descs. If partnum is +already aligned to PART_DESC_ALLOC_STEP, ALIGN(partnum, step) can keep +the old capacity and the next append writes past the end of the table. + +Store partnum in the appended slot and size growth from the next append +count so deduplication and capacity tracking follow the same model. + +Fixes: ee4af50ca94f ("udf: Fix mounting of Win7 created UDF filesystems") +Cc: stable@vger.kernel.org +Signed-off-by: Seohyeon Maeng +Link: https://patch.msgid.link/20260310081652.21220-1-bioloidgp@gmail.com +Signed-off-by: Jan Kara +[ replaced kzalloc_objs() helper with equivalent kcalloc() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/super.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -1657,8 +1657,9 @@ static struct udf_vds_record *handle_par + return &(data->part_descs_loc[i].rec); + if (data->num_part_descs >= data->size_part_descs) { + struct part_desc_seq_scan_data *new_loc; +- unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP); ++ unsigned int new_size; + ++ new_size = data->num_part_descs + PART_DESC_ALLOC_STEP; + new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL); + if (!new_loc) + return ERR_PTR(-ENOMEM); +@@ -1668,6 +1669,7 @@ static struct udf_vds_record *handle_par + data->part_descs_loc = new_loc; + data->size_part_descs = new_size; + } ++ data->part_descs_loc[data->num_part_descs].partnum = partnum; + return &(data->part_descs_loc[data->num_part_descs++].rec); + } + diff --git a/queue-6.1/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch b/queue-6.1/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch new file mode 100644 index 0000000000..43691f708a --- /dev/null +++ b/queue-6.1/usb-cdns3-plat-fix-leaked-usb2_phy-initialization-on-usb3_phy-acquisition-failure.patch @@ -0,0 +1,48 @@ +From stable+bounces-260594-greg=kroah.com@vger.kernel.org Fri Jun 5 06:05:07 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 20:34:56 -0400 +Subject: usb: cdns3: plat: fix leaked usb2_phy initialization on usb3_phy acquisition failure +To: stable@vger.kernel.org +Cc: Peter Chen , stable , sashiko-bot , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605003456.2707466-1-sashal@kernel.org> + +From: Peter Chen + +[ Upstream commit e6970cda63fd4b4546aeed9d0e2f53a7c95cd09c ] + +Move usb2_phy initialization after usb3_phy acquisition. + +Fixes: f738957277ba ("usb: cdns3: Split core.c into cdns3-plat and core.c file") +Cc: stable +Reported-by: sashiko-bot +Closes: https://lore.kernel.org/linux-devicetree/agKaEePSFknhDBg2@nchen-desktop/T/#m21e1d9c1574eb127ce03c0c2a1a49002ce435b52 +Signed-off-by: Peter Chen +Link: https://patch.msgid.link/20260513085310.2217547-2-peter.chen@cixtech.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/cdns3/cdns3-plat.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/usb/cdns3/cdns3-plat.c ++++ b/drivers/usb/cdns3/cdns3-plat.c +@@ -120,14 +120,14 @@ static int cdns3_plat_probe(struct platf + if (IS_ERR(cdns->usb2_phy)) + return PTR_ERR(cdns->usb2_phy); + +- ret = phy_init(cdns->usb2_phy); +- if (ret) +- return ret; +- + cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy"); + if (IS_ERR(cdns->usb3_phy)) + return PTR_ERR(cdns->usb3_phy); + ++ ret = phy_init(cdns->usb2_phy); ++ if (ret) ++ return ret; ++ + ret = phy_init(cdns->usb3_phy); + if (ret) + goto err_phy3_init; diff --git a/queue-6.1/usb-dwc3-move-guid-programming-after-phy-initialization.patch b/queue-6.1/usb-dwc3-move-guid-programming-after-phy-initialization.patch new file mode 100644 index 0000000000..5712ddc9c8 --- /dev/null +++ b/queue-6.1/usb-dwc3-move-guid-programming-after-phy-initialization.patch @@ -0,0 +1,63 @@ +From stable+bounces-246864-greg=kroah.com@vger.kernel.org Wed May 13 19:27:04 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 09:32:57 -0400 +Subject: usb: dwc3: Move GUID programming after PHY initialization +To: stable@vger.kernel.org +Cc: Selvarasu Ganesan , stable , Pritam Manohar Sutar , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260513133257.3732683-1-sashal@kernel.org> + +From: Selvarasu Ganesan + +[ Upstream commit aad35f9c926ec220b0742af1ada45666ae667956 ] + +The Linux Version Code is currently written to the GUID register before +PHY initialization. Certain PHY implementations (such as Synopsys eUSB +PHY performing link_sw_reset) clear the GUID register to its default +value during initialization, causing the kernel version information to +be lost. + +Move the GUID register programming to occur after PHY initialization +completes to ensure the Linux version information persists. + +Fixes: fa0ea13e9f1c ("usb: dwc3: core: write LINUX_VERSION_CODE to our GUID register") +Cc: stable +Reported-by: Pritam Manohar Sutar +Signed-off-by: Selvarasu Ganesan +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com +Signed-off-by: Greg Kroah-Hartman +[ adapted dwc3_writel(dwc, ...) to dwc3_writel(dwc->regs, ...) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1239,12 +1239,6 @@ static int dwc3_core_init(struct dwc3 *d + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + +- /* +- * Write Linux Version Code to our GUID register so it's easy to figure +- * out which kernel version a bug was found. +- */ +- dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); +- + ret = dwc3_phy_setup(dwc); + if (ret) + goto err0; +@@ -1284,6 +1278,12 @@ static int dwc3_core_init(struct dwc3 *d + if (ret) + goto err1; + ++ /* ++ * Write Linux Version Code to our GUID register so it's easy to figure ++ * out which kernel version a bug was found. ++ */ ++ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); ++ + dwc3_core_setup_global_control(dwc); + dwc3_core_num_eps(dwc); + diff --git a/queue-6.1/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch b/queue-6.1/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch new file mode 100644 index 0000000000..c0fc1d910c --- /dev/null +++ b/queue-6.1/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch @@ -0,0 +1,95 @@ +From sashal@kernel.org Sat Jun 6 00:01:21 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 14:31:18 -0400 +Subject: usb: dwc3: xilinx: fix error handling in zynqmp init error paths +To: stable@vger.kernel.org +Cc: Radhey Shyam Pandey , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183118.2054817-1-sashal@kernel.org> + +From: Radhey Shyam Pandey + +[ Upstream commit c1a0ecbf32c4b397353204e2ec94c5bb9f3300ed ] + +Fix error handling and resource cleanup i.e remove invalid +phy_exit() after failed phy_init(), route failures through +proper cleanup paths and return 0 explicitly on success. + +Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms") +Cc: stable@vger.kernel.org +Acked-by: Thinh Nguyen +Signed-off-by: Radhey Shyam Pandey +Link: https://patch.msgid.link/20260519115529.2980421-1-radhey.shyam.pandey@amd.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-xilinx.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -171,15 +171,13 @@ static int dwc3_xlnx_init_zynqmp(struct + } + + ret = phy_init(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); ++ if (ret < 0) + goto err; +- } + + ret = reset_control_deassert(apbrst); + if (ret < 0) { + dev_err(dev, "Failed to release APB reset\n"); +- goto err; ++ goto err_phy_exit; + } + + /* Set PIPE Power Present signal in FPD Power Present Register*/ +@@ -191,27 +189,25 @@ static int dwc3_xlnx_init_zynqmp(struct + ret = reset_control_deassert(crst); + if (ret < 0) { + dev_err(dev, "Failed to release core reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = reset_control_deassert(hibrst); + if (ret < 0) { + dev_err(dev, "Failed to release hibernation reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = phy_power_on(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); +- goto err; +- } ++ if (ret < 0) ++ goto err_phy_exit; + + skip_usb3_phy: + /* ulpi reset via gpio-modepin or gpio-framework driver */ + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) { +- return dev_err_probe(dev, PTR_ERR(reset_gpio), +- "Failed to request reset GPIO\n"); ++ ret = PTR_ERR(reset_gpio); ++ goto err_phy_power_off; + } + + if (reset_gpio) { +@@ -231,6 +227,12 @@ skip_usb3_phy: + writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); + } + ++ return 0; ++ ++err_phy_power_off: ++ phy_power_off(priv_data->usb3_phy); ++err_phy_exit: ++ phy_exit(priv_data->usb3_phy); + err: + return ret; + } diff --git a/queue-6.1/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch b/queue-6.1/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch new file mode 100644 index 0000000000..3a742a45c8 --- /dev/null +++ b/queue-6.1/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch @@ -0,0 +1,58 @@ +From sashal@kernel.org Sat Jun 6 00:47:15 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:17:11 -0400 +Subject: usb: gadget: f_hid: fix device reference leak in hidg_alloc() +To: stable@vger.kernel.org +Cc: Guangshuo Li , stable , Johan Hovold , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605191711.2132578-2-sashal@kernel.org> + +From: Guangshuo Li + +[ Upstream commit 4f88d65def6f3c90121601b4f62a4c967f3063a6 ] + +hidg_alloc() initializes hidg->dev with device_initialize() before +calling dev_set_name(). If dev_set_name() fails, the function currently +jumps to err_unlock and returns without calling put_device(). + +This leaves the device reference unbalanced and prevents hidg_release() +from being called. Calling put_device() here is also safe, since +hidg_release() only frees resources owned by hidg. + +The issue was identified by a static analysis tool I developed and +confirmed by manual review. + +Route the dev_set_name() failure path through err_put_device so the +device reference is dropped properly. + +Fixes: 89ff3dfac604 ("usb: gadget: f_hid: fix f_hidg lifetime vs cdev") +Cc: stable +Reviewed-by: Johan Hovold +Signed-off-by: Guangshuo Li +Reviewed-by: Johan Hovold johan@kernel.org +Link: https://patch.msgid.link/20260413142119.2977716-1-lgs201920130244@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_hid.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -1278,7 +1278,7 @@ static struct usb_function *hidg_alloc(s + hidg->dev.devt = MKDEV(major, opts->minor); + ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor); + if (ret) +- goto err_unlock; ++ goto err_put_device; + + hidg->bInterfaceSubClass = opts->subclass; + hidg->bInterfaceProtocol = opts->protocol; +@@ -1313,7 +1313,6 @@ static struct usb_function *hidg_alloc(s + + err_put_device: + put_device(&hidg->dev); +-err_unlock: + mutex_unlock(&opts->lock); + return ERR_PTR(ret); + } diff --git a/queue-6.1/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch b/queue-6.1/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch new file mode 100644 index 0000000000..3c3841451b --- /dev/null +++ b/queue-6.1/usb-gadget-f_hid-tidy-error-handling-in-hidg_alloc.patch @@ -0,0 +1,87 @@ +From sashal@kernel.org Sat Jun 6 00:47:14 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:17:10 -0400 +Subject: usb: gadget: f_hid: tidy error handling in hidg_alloc +To: stable@vger.kernel.org +Cc: John Keeping , Lee Jones , Andrzej Pietrasiewicz , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605191711.2132578-1-sashal@kernel.org> + +From: John Keeping + +[ Upstream commit 944fe915d00d3cb1bacb1e77cabfb6dc82e6f8b8 ] + +Unify error handling at the end of the function, reducing the risk of +missing something on one of the error paths. + +Moving the increment of opts->refcnt later means there is no need to +decrement it on the error path and is safe as this is guarded by +opts->lock which is held for this entire section. + +Tested-by: Lee Jones +Reviewed-by: Andrzej Pietrasiewicz +Reviewed-by: Lee Jones +Signed-off-by: John Keeping +Link: https://lore.kernel.org/r/20221122123523.3068034-4-john@metanate.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 4f88d65def6f ("usb: gadget: f_hid: fix device reference leak in hidg_alloc()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_hid.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -1265,7 +1265,6 @@ static struct usb_function *hidg_alloc(s + opts = container_of(fi, struct f_hid_opts, func_inst); + + mutex_lock(&opts->lock); +- ++opts->refcnt; + + spin_lock_init(&hidg->write_spinlock); + spin_lock_init(&hidg->read_spinlock); +@@ -1278,11 +1277,8 @@ static struct usb_function *hidg_alloc(s + hidg->dev.class = hidg_class; + hidg->dev.devt = MKDEV(major, opts->minor); + ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor); +- if (ret) { +- --opts->refcnt; +- mutex_unlock(&opts->lock); +- return ERR_PTR(ret); +- } ++ if (ret) ++ goto err_unlock; + + hidg->bInterfaceSubClass = opts->subclass; + hidg->bInterfaceProtocol = opts->protocol; +@@ -1293,14 +1289,13 @@ static struct usb_function *hidg_alloc(s + opts->report_desc_length, + GFP_KERNEL); + if (!hidg->report_desc) { +- put_device(&hidg->dev); +- --opts->refcnt; +- mutex_unlock(&opts->lock); +- return ERR_PTR(-ENOMEM); ++ ret = -ENOMEM; ++ goto err_put_device; + } + } + hidg->use_out_ep = !opts->no_out_endpoint; + ++ ++opts->refcnt; + mutex_unlock(&opts->lock); + + hidg->func.name = "hid"; +@@ -1315,6 +1310,12 @@ static struct usb_function *hidg_alloc(s + hidg->qlen = 4; + + return &hidg->func; ++ ++err_put_device: ++ put_device(&hidg->dev); ++err_unlock: ++ mutex_unlock(&opts->lock); ++ return ERR_PTR(ret); + } + + DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc); diff --git a/queue-6.1/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch b/queue-6.1/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch new file mode 100644 index 0000000000..ff0d0728a1 --- /dev/null +++ b/queue-6.1/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch @@ -0,0 +1,54 @@ +From sashal@kernel.org Sat Jun 6 00:01:24 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 14:31:21 -0400 +Subject: usb: musb: omap2430: Fix use-after-free in omap2430_probe() +To: stable@vger.kernel.org +Cc: Wentao Liang , stable , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605183121.2054969-1-sashal@kernel.org> + +From: Wentao Liang + +[ Upstream commit e194ce048f5a6c549b3a23a8c568c6470f40f772 ] + +In omap2430_probe(), of_node_put(np) is called prematurely before the +last access to np, leading to a use-after-free if the node's reference +count drops to zero. Move the of_node_put() calls after the last use of +np in both the success and error paths. + +Fixes: ffbe2feac59b ("usb: musb: omap2430: Fix probe regression for missing resources") +Cc: stable +Signed-off-by: Wentao Liang +Link: https://patch.msgid.link/20260409101104.480623-1-vulab@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/omap2430.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/musb/omap2430.c ++++ b/drivers/usb/musb/omap2430.c +@@ -340,7 +340,6 @@ static int omap2430_probe(struct platfor + } else { + device_set_of_node_from_dev(&musb->dev, &pdev->dev); + } +- of_node_put(np); + + glue->dev = &pdev->dev; + glue->musb = musb; +@@ -458,6 +457,7 @@ static int omap2430_probe(struct platfor + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err3; + } ++ of_node_put(np); + + return 0; + +@@ -467,6 +467,7 @@ err_put_control_otghs: + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); + err2: ++ of_node_put(np); + platform_device_put(musb); + + err0: diff --git a/queue-6.1/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-6.1/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch new file mode 100644 index 0000000000..b175511f2b --- /dev/null +++ b/queue-6.1/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch @@ -0,0 +1,68 @@ +From stable+bounces-260810-greg=kroah.com@vger.kernel.org Sat Jun 6 01:08:35 2026 +From: Sasha Levin +Date: Fri, 5 Jun 2026 15:38:29 -0400 +Subject: usb: typec: ucsi: Check if power role change actually happened before handling +To: stable@vger.kernel.org +Cc: Myrrh Periwinkle , stable , Sergey Senozhatsky , Heikki Krogerus , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260605193829.2169488-1-sashal@kernel.org> + +From: Myrrh Periwinkle + +[ Upstream commit b80e7d34c7ea6a564525119d6138fbb577a23dba ] + +The CrOS EC may send a connector status change event with the power +direction changed flag set even if the power direction hasn't actually +changed after initiating a SET_PDR command internally [1]. In practice +this happens on every system suspend due to other changes performed by +the EC [2][3][4], causing suspend to fail. + +Fix this by checking if the power role change actually happened before +handling it. + +[1]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=1689;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[2]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=3923;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[3]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=5094;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 +[4]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=2229;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794 + +Cc: stable +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -783,7 +783,7 @@ static void ucsi_handle_connector_change + struct ucsi_connector *con = container_of(work, struct ucsi_connector, + work); + struct ucsi *ucsi = con->ucsi; +- enum typec_role role; ++ enum typec_role role, prev_role; + u64 command; + int ret; + +@@ -791,6 +791,8 @@ static void ucsi_handle_connector_change + + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); + ++ prev_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); ++ + ret = ucsi_send_command_common(ucsi, command, &con->status, + sizeof(con->status), true); + if (ret < 0) { +@@ -804,7 +806,7 @@ static void ucsi_handle_connector_change + + role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + +- if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { ++ if ((con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) { + typec_set_pwr_role(con->port, role); + ucsi_port_psy_changed(con); + diff --git a/queue-6.1/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch b/queue-6.1/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch new file mode 100644 index 0000000000..1a469867ea --- /dev/null +++ b/queue-6.1/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch @@ -0,0 +1,45 @@ +From stable+bounces-260883-greg=kroah.com@vger.kernel.org Sat Jun 6 18:55:10 2026 +From: Sasha Levin +Date: Sat, 6 Jun 2026 09:21:53 -0400 +Subject: usb: typec: ucsi: Don't update power_supply on power role change if not connected +To: stable@vger.kernel.org +Cc: Myrrh Periwinkle , stable , Sergey Senozhatsky , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260606132153.2949745-1-sashal@kernel.org> + +From: Myrrh Periwinkle + +[ Upstream commit d98d413ca65d0790a8f3695d0a5845538958ab84 ] + +We only need to update the power_supply on power role change if the port +is connected, because otherwise the online status should be the same for +both cases. + +Cc: stable +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-2-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +[ changed `UCSI_CONSTAT(con, CONNECTED)` accessor macro to `con->status.flags & UCSI_CONSTAT_CONNECTED` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/ucsi/ucsi.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -808,7 +808,12 @@ static void ucsi_handle_connector_change + + if ((con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) { + typec_set_pwr_role(con->port, role); +- ucsi_port_psy_changed(con); ++ ++ /* Some power_supply properties vary depending on the power direction when ++ * connected ++ */ ++ if (con->status.flags & UCSI_CONSTAT_CONNECTED) ++ ucsi_port_psy_changed(con); + + /* Complete pending power role swap */ + if (!completion_done(&con->complete)) diff --git a/queue-6.1/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch b/queue-6.1/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch new file mode 100644 index 0000000000..7cf11ad98f --- /dev/null +++ b/queue-6.1/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch @@ -0,0 +1,55 @@ +From stable+bounces-246843-greg=kroah.com@vger.kernel.org Wed May 13 18:37:14 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 08:48:41 -0400 +Subject: wifi: brcmfmac: Fix potential use-after-free issue when stopping watchdog task +To: stable@vger.kernel.org +Cc: Marek Szyprowski , Arend van Spriel , Johannes Berg , Sasha Levin +Message-ID: <20260513124841.3712467-1-sashal@kernel.org> + +From: Marek Szyprowski + +[ Upstream commit c623b63580880cc742255eaed3d79804c1b91143 ] + +Watchdog task might end between send_sig() and kthread_stop() calls, what +results in the use-after-free issue. Fix this by increasing watchdog task +reference count before calling send_sig() and dropping it by switching to +kthread_stop_put(). + +Cc: stable@vger.kernel.org +Fixes: 373c83a801f1 ("brcmfmac: stop watchdog before detach and free everything") +Fixes: a9ffda88be74 ("brcm80211: fmac: abstract bus_stop interface function pointer") +Signed-off-by: Marek Szyprowski +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260416093339.2066829-1-m.szyprowski@samsung.com +Signed-off-by: Johannes Berg +[ replaced kthread_stop_put() with open-coded kthread_stop() + put_task_struct() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -2477,8 +2477,10 @@ static void brcmf_sdio_bus_stop(struct d + brcmf_dbg(TRACE, "Enter\n"); + + if (bus->watchdog_tsk) { ++ get_task_struct(bus->watchdog_tsk); + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); ++ put_task_struct(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + +@@ -4549,8 +4551,10 @@ void brcmf_sdio_remove(struct brcmf_sdio + if (bus) { + /* Stop watchdog task */ + if (bus->watchdog_tsk) { ++ get_task_struct(bus->watchdog_tsk); + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); ++ put_task_struct(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + diff --git a/queue-6.1/wifi-mac80211-remove-station-if-connection-prep-fails.patch b/queue-6.1/wifi-mac80211-remove-station-if-connection-prep-fails.patch new file mode 100644 index 0000000000..288ecf2842 --- /dev/null +++ b/queue-6.1/wifi-mac80211-remove-station-if-connection-prep-fails.patch @@ -0,0 +1,54 @@ +From stable+bounces-246817-greg=kroah.com@vger.kernel.org Wed May 13 17:18:54 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 07:48:48 -0400 +Subject: wifi: mac80211: remove station if connection prep fails +To: stable@vger.kernel.org +Cc: Johannes Berg , Miriam Rachel Korenblit , Sasha Levin +Message-ID: <20260513114848.3692309-1-sashal@kernel.org> + +From: Johannes Berg + +[ Upstream commit 283fc9e44ff5b5ac967439b4951b80bd4299f4e4 ] + +If connection preparation fails for MLO connections, then the +interface is completely reset to non-MLD. In this case, we must +not keep the station since it's related to the link of the vif +being removed. Delete an existing station. Any "new_sta" is +already being removed, so that doesn't need changes. + +This fixes a use-after-free/double-free in debugfs if that's +enabled, because a vif going from MLD (and to MLD, but that's +not relevant here) recreates its entire debugfs. + +Cc: stable@vger.kernel.org +Fixes: 81151ce462e5 ("wifi: mac80211: support MLO authentication/association with one link") +Reviewed-by: Miriam Rachel Korenblit +Link: https://patch.msgid.link/20260505151533.c4e52deb06ad.Iafe56cec7de8512626169496b134bce3a6c17010@changeid +Signed-off-by: Johannes Berg +[ used sta_info_destroy_addr() instead of __sta_info_destroy() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mac80211/mlme.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -6586,7 +6586,7 @@ static int ieee80211_prep_connection(str + struct ieee80211_bss *bss = (void *)cbss->priv; + struct sta_info *new_sta = NULL; + struct ieee80211_link_data *link; +- bool have_sta = false; ++ struct sta_info *have_sta = NULL; + bool mlo; + int err; + +@@ -6751,6 +6751,8 @@ static int ieee80211_prep_connection(str + + out_err: + ieee80211_link_release_channel(&sdata->deflink); ++ if (mlo && have_sta) ++ WARN_ON(sta_info_destroy_addr(sdata, ap_mld_addr)); + ieee80211_vif_set_links(sdata, 0); + return err; + } diff --git a/queue-6.1/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch b/queue-6.1/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch new file mode 100644 index 0000000000..4cffe2f573 --- /dev/null +++ b/queue-6.1/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch @@ -0,0 +1,132 @@ +From stable+bounces-246948-greg=kroah.com@vger.kernel.org Wed May 13 22:31:33 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:52:55 -0400 +Subject: xfrm: ah: account for ESN high bits in async callbacks +To: stable@vger.kernel.org +Cc: Michael Bommarito , Steffen Klassert , Sasha Levin +Message-ID: <20260513165255.3822003-3-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit ec54093e6a8f87e800bb6aa15eb7fc1e33faa524 ] + +AH allocates its temporary auth/ICV layout differently when ESN is enabled: +the async ahash setup appends a 4-byte seqhi slot before the ICV or +auth_data area, but the async completion callbacks still reconstruct the +temporary layout as if seqhi were absent. + +With an async AH implementation selected, that makes AH copy or compare +the wrong bytes on both the IPv4 and IPv6 paths. In UML repro on IPv4 AH +with ESN and forced async hmac(sha1), ping fails with 100% packet loss, +and the callback logs show the pre-fix drift: + + ah4 output_done: esn=1 err=0 icv_off=20 expected_off=24 + ah4 input_done: esn=1 auth_off=20 expected_auth_off=24 icv_off=32 expected_icv_off=36 + +Reconstruct the callback-side layout the same way the setup path built it +by skipping the ESN seqhi slot before locating the saved auth_data or ICV. +Per RFC 4302, the ESN high-order 32 bits participate in the AH ICV +computation, so the async callbacks must account for the seqhi slot. + +Post-fix, the same IPv4 AH+ESN+forced-async-hmac(sha1) UML repro shows +the corrected offset (ah4 output_done: esn=1 err=0 icv_off=24 +expected_off=24) and ping succeeds; net/ipv4/ah4.o and net/ipv6/ah6.o +build clean at W=1. IPv6 AH+ESN was not exercised at runtime, and the +change has not been tested against a real async hardware AH engine. + +Fixes: d4d573d0334d ("{IPv4,xfrm} Add ESN support for AH egress part") +Fixes: d8b2a8600b0e ("{IPv4,xfrm} Add ESN support for AH ingress part") +Fixes: 26dd70c3fad3 ("{IPv6,xfrm} Add ESN support for AH egress part") +Fixes: 8d6da6f32557 ("{IPv6,xfrm} Add ESN support for AH ingress part") +Cc: stable@vger.kernel.org +Assisted-by: Codex:gpt-5-4 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ah4.c | 14 ++++++++++++-- + net/ipv6/ah6.c | 14 ++++++++++++-- + 2 files changed, 24 insertions(+), 4 deletions(-) + +--- a/net/ipv4/ah4.c ++++ b/net/ipv4/ah4.c +@@ -124,9 +124,14 @@ static void ah_output_done(struct crypto + struct iphdr *top_iph = ip_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); ++ int seqhi_len = 0; ++ __be32 *seqhi; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + iph = AH_SKB_CB(skb)->tmp; +- icv = ah_tmp_icv(iph, ihl); ++ seqhi = (__be32 *)((char *)iph + ihl); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + + top_iph->tos = iph->tos; +@@ -270,12 +275,17 @@ static void ah_input_done(struct crypto_ + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); + int ah_hlen = (ah->hdrlen + 2) << 2; ++ int seqhi_len = 0; ++ __be32 *seqhi; + + if (err) + goto out; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + work_iph = AH_SKB_CB(skb)->tmp; +- auth_data = ah_tmp_auth(work_iph, ihl); ++ seqhi = (__be32 *)((char *)work_iph + ihl); ++ auth_data = ah_tmp_auth(seqhi, seqhi_len); + icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -317,14 +317,19 @@ static void ah6_output_done(struct crypt + struct ipv6hdr *top_iph = ipv6_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + struct tmp_ext *iph_ext; ++ int seqhi_len = 0; ++ __be32 *seqhi; + + extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); + if (extlen) + extlen += sizeof(*iph_ext); + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + iph_base = AH_SKB_CB(skb)->tmp; + iph_ext = ah_tmp_ext(iph_base); +- icv = ah_tmp_icv(iph_ext, extlen); ++ seqhi = (__be32 *)((char *)iph_ext + extlen); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); +@@ -471,13 +476,18 @@ static void ah6_input_done(struct crypto + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int hdr_len = skb_network_header_len(skb); + int ah_hlen = ipv6_authlen(ah); ++ int seqhi_len = 0; ++ __be32 *seqhi; + + if (err) + goto out; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, hdr_len); +- icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); ++ seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) diff --git a/queue-6.1/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch b/queue-6.1/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch new file mode 100644 index 0000000000..48460f8e20 --- /dev/null +++ b/queue-6.1/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch @@ -0,0 +1,119 @@ +From stable+bounces-246966-greg=kroah.com@vger.kernel.org Wed May 13 23:19:46 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:31:43 -0400 +Subject: xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete +To: stable@vger.kernel.org +Cc: Michal Kosiorek , Steffen Klassert , Sasha Levin +Message-ID: <20260513173143.3885911-1-sashal@kernel.org> + +From: Michal Kosiorek + +[ Upstream commit 14acf9652e5690de3c7486c6db5fb8dafd0a32a3 ] + +KASAN reproduces a slab-use-after-free in __xfrm_state_delete()'s +hlist_del_rcu calls under syzkaller load on linux-6.12.y stable +(reproduced on 6.12.47, also reachable via the same code path on +torvalds/master and on the ipsec tree). Nine unique signatures cluster +in the xfrm_state lifecycle, the load-bearing one being: + + BUG: KASAN: slab-use-after-free in __hlist_del include/linux/list.h:990 [inline] + BUG: KASAN: slab-use-after-free in hlist_del_rcu include/linux/rculist.h:516 [inline] + BUG: KASAN: slab-use-after-free in __xfrm_state_delete net/xfrm/xfrm_state.c + Write of size 8 at addr ffff8881198bcb70 by task kworker/u8:9/435 + + Workqueue: netns cleanup_net + Call Trace: + __hlist_del / hlist_del_rcu + __xfrm_state_delete + xfrm_state_delete + xfrm_state_flush + xfrm_state_fini + ops_exit_list + cleanup_net + +The other observed signatures hit the same slab object from +__xfrm_state_lookup, xfrm_alloc_spi, __xfrm_state_insert and an OOB +write variant of __xfrm_state_delete, all on the byseq/byspi +hash chains. + +__xfrm_state_delete() guards its byseq and byspi unhashes with +value-based predicates: + + if (x->km.seq) + hlist_del_rcu(&x->byseq); + if (x->id.spi) + hlist_del_rcu(&x->byspi); + +while everywhere else in the file (e.g. state_cache, state_cache_input) +the safer hlist_unhashed() check is used. xfrm_alloc_spi() sets +x->id.spi = newspi inside xfrm_state_lock and then immediately inserts +into byspi, but a path that observes x->id.spi != 0 outside of +xfrm_state_lock can still skip-or-hit the byspi unhash inconsistently +with whether x is actually on the list. The same holds for x->km.seq +versus byseq, and the bydst/bysrc unhashes have no predicate at all, +so a second __xfrm_state_delete() on the same object writes through +LIST_POISON pprev. + +The defensive change here: + + - Use hlist_del_init_rcu() instead of hlist_del_rcu() on bydst, + bysrc, byseq and byspi so a second deletion is a no-op rather + than a write through LIST_POISON pprev. The byseq/byspi nodes + are already initialised in xfrm_state_alloc(). + - Test hlist_unhashed() rather than the value predicate for + byseq/byspi, so the unhash decision tracks list state rather than + mutable scalar fields. + +Empirical verification: applied this patch on top of v6.12.47, rebuilt, +and re-ran the same syzkaller harness for 1h16m on a previously-crashy +configuration that produced ~100 hits each of slab-use-after-free +Read in xfrm_alloc_spi / Read in __xfrm_state_lookup / Write in +__xfrm_state_delete. After the patch, 7.1M execs across 32 VMs at +~1550 exec/sec produced zero xfrm_state UAF/OOB hits. /proc/slabinfo +confirms the xfrm_state slab is actively allocated and freed during +the run (~143 KiB resident), so the fuzzer is still exercising those +code paths -- they just no longer crash. + +Reproduction: + + - Linux 6.12.47 x86_64 + KASAN_GENERIC + KASAN_INLINE + KCOV + - syzkaller @ 746545b8b1e4c3a128db8652b340d3df90ce61db + - 32 QEMU/KVM VMs x 2 vCPU on AWS c5.metal bare metal + - 9 unique signatures collected in ~9h, all within xfrm_state + lifecycle + +Fixes: fe9f1d8779cb ("xfrm: add state hashtable keyed by seq") +Fixes: 7b4dc3600e48 ("[XFRM]: Do not add a state whose SPI is zero to the SPI hash.") +Reported-by: Michal Kosiorek +Tested-by: Michal Kosiorek +Cc: stable@vger.kernel.org +Signed-off-by: Michal Kosiorek +Signed-off-by: Steffen Klassert +[ dropped state_cache/state_cache_input unhash hunks and xfrm_nat_keepalive_state_updated() call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_state.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -682,12 +682,12 @@ int __xfrm_state_delete(struct xfrm_stat + x->km.state = XFRM_STATE_DEAD; + spin_lock(&net->xfrm.xfrm_state_lock); + list_del(&x->km.all); +- hlist_del_rcu(&x->bydst); +- hlist_del_rcu(&x->bysrc); +- if (x->km.seq) +- hlist_del_rcu(&x->byseq); +- if (x->id.spi) +- hlist_del_rcu(&x->byspi); ++ hlist_del_init_rcu(&x->bydst); ++ hlist_del_init_rcu(&x->bysrc); ++ if (!hlist_unhashed(&x->byseq)) ++ hlist_del_init_rcu(&x->byseq); ++ if (!hlist_unhashed(&x->byspi)) ++ hlist_del_init_rcu(&x->byspi); + net->xfrm.state_num--; + spin_unlock(&net->xfrm.xfrm_state_lock); + diff --git a/queue-6.1/xfs-fix-a-resource-leak-in-xfs_alloc_buftarg.patch b/queue-6.1/xfs-fix-a-resource-leak-in-xfs_alloc_buftarg.patch new file mode 100644 index 0000000000..30d1d3677e --- /dev/null +++ b/queue-6.1/xfs-fix-a-resource-leak-in-xfs_alloc_buftarg.patch @@ -0,0 +1,37 @@ +From stable+bounces-244778-greg=kroah.com@vger.kernel.org Fri May 8 20:26:50 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 10:52:06 -0400 +Subject: xfs: fix a resource leak in xfs_alloc_buftarg() +To: stable@vger.kernel.org +Cc: Haoxiang Li , "Darrick J. Wong" , Carlos Maiolino , Sasha Levin +Message-ID: <20260508145206.1512706-1-sashal@kernel.org> + +From: Haoxiang Li + +[ Upstream commit 29a7b2614357393b176ef06ba5bc3ff5afc8df69 ] + +In the error path, call fs_put_dax() to drop the DAX +device reference. + +Fixes: 6f643c57d57c ("xfs: implement ->notify_failure() for XFS") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Reviewed-by: Darrick J. Wong +Signed-off-by: Carlos Maiolino +[ kept `kmem_free(btp)` and `return NULL` instead of `kfree(btp)`/`ERR_PTR(error)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_buf.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/xfs/xfs_buf.c ++++ b/fs/xfs/xfs_buf.c +@@ -2036,6 +2036,7 @@ error_pcpu: + error_lru: + list_lru_destroy(&btp->bt_lru); + error_free: ++ fs_put_dax(btp->bt_daxdev, mp); + kmem_free(btp); + return NULL; + }