]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 07:10:40 +0000 (12:40 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 07:10:40 +0000 (12:40 +0530)
added patches:
acpi-scan-use-acpi_dev_put-in-object-add-error-paths.patch
alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch
alsa-aoa-i2sbus-clear-stale-prepared-state.patch
alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch
alsa-aoa-use-guard-for-mutex-locks.patch
alsa-core-fix-potential-data-race-at-fasync-handling.patch
arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch
arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch
bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch
bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.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-missing-last_unlink_trans-update-when-removing-a-directory.patch
can-ucan-fix-devres-lifetime.patch
can-ucan-fix-typos-in-comments.patch
ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch
crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch
dm-btree-improve-btree-residency.patch
dm-thin-fix-metadata-refcount-underflow.patch
drm-nouveau-fix-u32-overflow-in-pushbuf-reloc-bounds-check.patch
erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch
f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch
fbcon-avoid-oob-font-access-if-console-rotation-fails.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
ktest-fix-the-month-in-the-name-of-the-failure-directory.patch
ktest-fixing-indentation-to-match-expected-pattern.patch
media-rc-igorplugusb-heed-coherency-rules.patch
media-rc-ttusbir-respect-dma-coherency-rules.patch
mm-huge_memory-update-file-pmd-counter-before-folio_put.patch
mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
mptcp-do-not-drop-partial-packets.patch
mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch
net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch
net-hsr-defer-node-table-free-until-after-rcu-readers.patch
net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch
net-qrtr-ns-change-servers-radix-tree-to-xarray.patch
net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch
net-qrtr-ns-limit-the-maximum-number-of-lookups.patch
net-qrtr-ns-limit-the-total-number-of-nodes.patch
net-remove-redundant-if-statements.patch
netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch
netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch
octeontx2-af-add-validation-for-lmac-type.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
pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
printk-add-print_hex_dump_devel.patch
qed-fix-double-free-in-qed_cxt_tables_alloc.patch
qed-use-the-bitmap-api-to-simplify-some-functions.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
sched-use-u64-for-bandwidth-ratio-calculations.patch
scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
selftests-mptcp-drop-nanoseconds-width-specifier.patch
serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch
smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch
smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
spi-lantiq-ssc-fix-controller-deregistration.patch
spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch
spi-qup-switch-to-use-modern-name.patch
spi-st-ssc4-fix-controller-deregistration.patch
spi-sun4i-fix-controller-deregistration.patch
spi-sun6i-fix-controller-deregistration.patch
spi-syncuacer-fix-controller-deregistration.patch
spi-tegra114-fix-controller-deregistration.patch
spi-tegra20-sflash-fix-controller-deregistration.patch
spi-ti-qspi-fix-controller-deregistration.patch
spi-topcliff-pch-fix-controller-deregistration.patch
spi-uniphier-fix-controller-deregistration.patch
spi-zynq-qspi-fix-controller-deregistration.patch
thermal-core-fix-thermal-zone-governor-cleanup-issues.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
udf-fix-partition-descriptor-append-bookkeeping.patch
usb-dwc3-move-guid-programming-after-phy-initialization.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
use-less-confusing-names-for-iov_iter-direction-initializers.patch
wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch

100 files changed:
queue-5.10/acpi-scan-use-acpi_dev_put-in-object-add-error-paths.patch [new file with mode: 0644]
queue-5.10/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch [new file with mode: 0644]
queue-5.10/alsa-aoa-i2sbus-clear-stale-prepared-state.patch [new file with mode: 0644]
queue-5.10/alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch [new file with mode: 0644]
queue-5.10/alsa-aoa-use-guard-for-mutex-locks.patch [new file with mode: 0644]
queue-5.10/alsa-core-fix-potential-data-race-at-fasync-handling.patch [new file with mode: 0644]
queue-5.10/arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch [new file with mode: 0644]
queue-5.10/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch [new file with mode: 0644]
queue-5.10/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch [new file with mode: 0644]
queue-5.10/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch [new file with mode: 0644]
queue-5.10/bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.patch [new file with mode: 0644]
queue-5.10/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch [new file with mode: 0644]
queue-5.10/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch [new file with mode: 0644]
queue-5.10/bluetooth-serialize-accept_q-access.patch [new file with mode: 0644]
queue-5.10/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch [new file with mode: 0644]
queue-5.10/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch [new file with mode: 0644]
queue-5.10/can-ucan-fix-devres-lifetime.patch [new file with mode: 0644]
queue-5.10/can-ucan-fix-typos-in-comments.patch [new file with mode: 0644]
queue-5.10/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch [new file with mode: 0644]
queue-5.10/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch [new file with mode: 0644]
queue-5.10/dm-btree-improve-btree-residency.patch [new file with mode: 0644]
queue-5.10/dm-thin-fix-metadata-refcount-underflow.patch [new file with mode: 0644]
queue-5.10/drm-nouveau-fix-u32-overflow-in-pushbuf-reloc-bounds-check.patch [new file with mode: 0644]
queue-5.10/erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch [new file with mode: 0644]
queue-5.10/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch [new file with mode: 0644]
queue-5.10/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch [new file with mode: 0644]
queue-5.10/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch [new file with mode: 0644]
queue-5.10/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch [new file with mode: 0644]
queue-5.10/ice-fix-vf-queue-configuration-with-low-mtu-values.patch [new file with mode: 0644]
queue-5.10/ktest-fix-the-month-in-the-name-of-the-failure-directory.patch [new file with mode: 0644]
queue-5.10/ktest-fixing-indentation-to-match-expected-pattern.patch [new file with mode: 0644]
queue-5.10/media-rc-igorplugusb-heed-coherency-rules.patch [new file with mode: 0644]
queue-5.10/media-rc-ttusbir-respect-dma-coherency-rules.patch [new file with mode: 0644]
queue-5.10/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch [new file with mode: 0644]
queue-5.10/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch [new file with mode: 0644]
queue-5.10/mptcp-do-not-drop-partial-packets.patch [new file with mode: 0644]
queue-5.10/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch [new file with mode: 0644]
queue-5.10/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch [new file with mode: 0644]
queue-5.10/net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch [new file with mode: 0644]
queue-5.10/net-hsr-defer-node-table-free-until-after-rcu-readers.patch [new file with mode: 0644]
queue-5.10/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch [new file with mode: 0644]
queue-5.10/net-qrtr-ns-change-servers-radix-tree-to-xarray.patch [new file with mode: 0644]
queue-5.10/net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch [new file with mode: 0644]
queue-5.10/net-qrtr-ns-limit-the-maximum-number-of-lookups.patch [new file with mode: 0644]
queue-5.10/net-qrtr-ns-limit-the-total-number-of-nodes.patch [new file with mode: 0644]
queue-5.10/net-remove-redundant-if-statements.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch [new file with mode: 0644]
queue-5.10/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch [new file with mode: 0644]
queue-5.10/octeontx2-af-add-validation-for-lmac-type.patch [new file with mode: 0644]
queue-5.10/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch [new file with mode: 0644]
queue-5.10/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch [new file with mode: 0644]
queue-5.10/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch [new file with mode: 0644]
queue-5.10/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch [new file with mode: 0644]
queue-5.10/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch [new file with mode: 0644]
queue-5.10/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch [new file with mode: 0644]
queue-5.10/printk-add-print_hex_dump_devel.patch [new file with mode: 0644]
queue-5.10/qed-fix-double-free-in-qed_cxt_tables_alloc.patch [new file with mode: 0644]
queue-5.10/qed-use-the-bitmap-api-to-simplify-some-functions.patch [new file with mode: 0644]
queue-5.10/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch [new file with mode: 0644]
queue-5.10/rdma-umem-fix-kernel-doc-warnings.patch [new file with mode: 0644]
queue-5.10/rdma-umem-fix-truncation-for-block-sizes-4g.patch [new file with mode: 0644]
queue-5.10/sched-use-u64-for-bandwidth-ratio-calculations.patch [new file with mode: 0644]
queue-5.10/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch [new file with mode: 0644]
queue-5.10/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch [new file with mode: 0644]
queue-5.10/selftests-mptcp-drop-nanoseconds-width-specifier.patch [new file with mode: 0644]
queue-5.10/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch [new file with mode: 0644]
queue-5.10/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch [new file with mode: 0644]
queue-5.10/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch [new file with mode: 0644]
queue-5.10/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch [new file with mode: 0644]
queue-5.10/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch [new file with mode: 0644]
queue-5.10/spi-lantiq-ssc-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch [new file with mode: 0644]
queue-5.10/spi-qup-switch-to-use-modern-name.patch [new file with mode: 0644]
queue-5.10/spi-st-ssc4-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-sun4i-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-sun6i-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-syncuacer-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-tegra114-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-tegra20-sflash-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-ti-qspi-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-topcliff-pch-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-uniphier-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/spi-zynq-qspi-fix-controller-deregistration.patch [new file with mode: 0644]
queue-5.10/thermal-core-fix-thermal-zone-governor-cleanup-issues.patch [new file with mode: 0644]
queue-5.10/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch [new file with mode: 0644]
queue-5.10/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch [new file with mode: 0644]
queue-5.10/tracing-probes-limit-size-of-event-probe-to-3k.patch [new file with mode: 0644]
queue-5.10/tty-serial-qcom-geni-serial-align-define-values.patch [new file with mode: 0644]
queue-5.10/tty-serial-qcom-geni-serial-remove-unused-symbols.patch [new file with mode: 0644]
queue-5.10/udf-fix-partition-descriptor-append-bookkeeping.patch [new file with mode: 0644]
queue-5.10/usb-dwc3-move-guid-programming-after-phy-initialization.patch [new file with mode: 0644]
queue-5.10/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch [new file with mode: 0644]
queue-5.10/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch [new file with mode: 0644]
queue-5.10/use-less-confusing-names-for-iov_iter-direction-initializers.patch [new file with mode: 0644]
queue-5.10/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch [new file with mode: 0644]
queue-5.10/wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch [new file with mode: 0644]

diff --git a/queue-5.10/acpi-scan-use-acpi_dev_put-in-object-add-error-paths.patch b/queue-5.10/acpi-scan-use-acpi_dev_put-in-object-add-error-paths.patch
new file mode 100644 (file)
index 0000000..beec44a
--- /dev/null
@@ -0,0 +1,66 @@
+From stable+bounces-245039-greg=kroah.com@vger.kernel.org Sun May 10 21:16:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 11:46:27 -0400
+Subject: ACPI: scan: Use acpi_dev_put() in object add error paths
+To: stable@vger.kernel.org
+Cc: Guangshuo Li <lgs201920130244@gmail.com>, "Rafael J. Wysocki" <rjw@rjwysocki.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260510154627.158558-1-sashal@kernel.org>
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+[ Upstream commit 9c0acc169ac71535477caedea8315f7041c5f07c ]
+
+After acpi_init_device_object(), the lifetime of struct acpi_device is
+managed by the driver core through reference counting.
+
+Both acpi_add_power_resource() and acpi_add_single_object() call
+acpi_init_device_object() and then invoke acpi_device_add(). If that
+fails, their error paths call the release callback directly instead of
+dropping the device reference through acpi_dev_put().
+
+This bypasses the normal device lifetime rules and frees the object
+without releasing the reference acquired by device_initialize(), which
+may lead to a refcount leak.
+
+The issue was identified by a static analysis tool I developed and
+confirmed by manual review.
+
+Fix both error paths by using acpi_dev_put() and let the release
+callback handle the final cleanup.
+
+Fixes: 781d737c7466 ("ACPI: Drop power resources driver")
+Fixes: 718fb0de8ff88 ("ACPI: fix NULL bug for HID/UID string")
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Link: https://patch.msgid.link/20260413135343.2884481-1-lgs201920130244@gmail.com
+Signed-off-by: Rafael J. Wysocki <rjw@rjwysocki.net>
+[ preserved 5.10's `return result;` instead of upstream's `return NULL;` since the function returns int ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/power.c |    2 +-
+ drivers/acpi/scan.c  |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/power.c
++++ b/drivers/acpi/power.c
+@@ -977,7 +977,7 @@ int acpi_add_power_resource(acpi_handle
+       return 0;
+  err:
+-      acpi_release_power_resource(&device->dev);
++      acpi_dev_put(device);
+       return result;
+ }
+--- a/drivers/acpi/scan.c
++++ b/drivers/acpi/scan.c
+@@ -1679,7 +1679,7 @@ static int acpi_add_single_object(struct
+       result = acpi_device_add(device, acpi_device_release);
+       if (result) {
+-              acpi_device_release(&device->dev);
++              acpi_dev_put(device);
+               return result;
+       }
diff --git a/queue-5.10/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch b/queue-5.10/alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch
new file mode 100644 (file)
index 0000000..9a671ef
--- /dev/null
@@ -0,0 +1,119 @@
+From stable+bounces-245022-greg=kroah.com@vger.kernel.org Sun May 10 19:08:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 09:38:00 -0400
+Subject: ALSA: aloop: Fix peer runtime UAF during format-change stop
+To: stable@vger.kernel.org
+Cc: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>, syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com, "Takashi Iwai" <tiwai@suse.com>, "Takashi Iwai" <tiwai@suse.de>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260510133800.4137265-1-sashal@kernel.org>
+
+From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+
+[ Upstream commit e5c33cdc6f402eab8abd36ecf436b22c9d3a8aff ]
+
+loopback_check_format() may stop the capture side when playback starts
+with parameters that no longer match a running capture stream. Commit
+826af7fa62e3 ("ALSA: aloop: Fix racy access at PCM trigger") moved
+the peer lookup under cable->lock, but the actual snd_pcm_stop() still
+runs after dropping that lock.
+
+A concurrent close can clear the capture entry from cable->streams[] and
+detach or free its runtime while the playback trigger path still holds a
+stale peer substream pointer.
+
+Keep a per-cable count of in-flight peer stops before dropping
+cable->lock, and make free_cable() wait for those stops before
+detaching the runtime. This preserves the existing behavior while
+making the peer runtime lifetime explicit.
+
+Reported-by: syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=8fa95c41eafbc9d2ff6f
+Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback")
+Cc: stable@vger.kernel.org
+Suggested-by: Takashi Iwai <tiwai@suse.com>
+Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+Link: https://patch.msgid.link/20260424-alsa-aloop-peer-stop-uaf-v2-1-94e68101db8a@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[ collapsed inc/snd_pcm_stop/dec into the existing inline call site and used spin_lock_irq/unlock_irq instead of scoped_guard ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/drivers/aloop.c |   40 +++++++++++++++++++++++++++-------------
+ 1 file changed, 27 insertions(+), 13 deletions(-)
+
+--- a/sound/drivers/aloop.c
++++ b/sound/drivers/aloop.c
+@@ -99,6 +99,9 @@ struct loopback_ops {
+ struct loopback_cable {
+       spinlock_t lock;
+       struct loopback_pcm *streams[2];
++      /* in-flight peer stops running outside cable->lock */
++      atomic_t stop_count;
++      wait_queue_head_t stop_wait;
+       struct snd_pcm_hardware hw;
+       /* flags */
+       unsigned int valid;
+@@ -342,8 +345,12 @@ static int loopback_check_format(struct
+       if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               return -EIO;
+       } else {
++              /* close must not free the peer runtime below */
++              atomic_inc(&cable->stop_count);
+               snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+                                       substream, SNDRV_PCM_STATE_DRAINING);
++              if (atomic_dec_and_test(&cable->stop_count))
++                      wake_up(&cable->stop_wait);
+             __notify:
+               runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+                                                       substream->runtime;
+@@ -995,24 +1002,29 @@ static void free_cable(struct snd_pcm_su
+       struct loopback *loopback = substream->private_data;
+       int dev = get_cable_index(substream);
+       struct loopback_cable *cable;
++      struct loopback_pcm *dpcm;
++      bool other_alive;
+       cable = loopback->cables[substream->number][dev];
+       if (!cable)
+               return;
+-      if (cable->streams[!substream->stream]) {
+-              /* other stream is still alive */
+-              spin_lock_irq(&cable->lock);
+-              cable->streams[substream->stream] = NULL;
+-              spin_unlock_irq(&cable->lock);
+-      } else {
+-              struct loopback_pcm *dpcm = substream->runtime->private_data;
+-              if (cable->ops && cable->ops->close_cable && dpcm)
+-                      cable->ops->close_cable(dpcm);
+-              /* free the cable */
+-              loopback->cables[substream->number][dev] = NULL;
+-              kfree(cable);
+-      }
++      spin_lock_irq(&cable->lock);
++      cable->streams[substream->stream] = NULL;
++      other_alive = cable->streams[!substream->stream] != NULL;
++      spin_unlock_irq(&cable->lock);
++
++      /* Pair with the stop_count increment in loopback_check_format(). */
++      wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
++      if (other_alive)
++              return;
++
++      dpcm = substream->runtime->private_data;
++      if (cable->ops && cable->ops->close_cable && dpcm)
++              cable->ops->close_cable(dpcm);
++      /* free the cable */
++      loopback->cables[substream->number][dev] = NULL;
++      kfree(cable);
+ }
+ static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
+@@ -1207,6 +1219,8 @@ static int loopback_open(struct snd_pcm_
+                       goto unlock;
+               }
+               spin_lock_init(&cable->lock);
++              atomic_set(&cable->stop_count, 0);
++              init_waitqueue_head(&cable->stop_wait);
+               cable->hw = loopback_pcm_hardware;
+               if (loopback->timer_source)
+                       cable->ops = &loopback_snd_timer_ops;
diff --git a/queue-5.10/alsa-aoa-i2sbus-clear-stale-prepared-state.patch b/queue-5.10/alsa-aoa-i2sbus-clear-stale-prepared-state.patch
new file mode 100644 (file)
index 0000000..fa380fa
--- /dev/null
@@ -0,0 +1,165 @@
+From stable+bounces-242481-greg=kroah.com@vger.kernel.org Fri May  1 22:58:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 13:28:00 -0400
+Subject: ALSA: aoa: i2sbus: clear stale prepared state
+To: stable@vger.kernel.org
+Cc: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>, "kernel test robot" <lkp@intel.com>, "Takashi Iwai" <tiwai@suse.de>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260501172800.3766490-2-sashal@kernel.org>
+
+From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+
+[ Upstream commit 5ed060d5491597490fb53ec69da3edc4b1e8c165 ]
+
+The i2sbus PCM code uses pi->active to constrain the sibling stream to
+an already prepared duplex format and rate in i2sbus_pcm_open().
+
+That state is set from i2sbus_pcm_prepare(), but the current code only
+clears it on close. As a result, the sibling stream can inherit stale
+constraints after the prepared state has been torn down.
+
+Clear pi->active when hw_params() or hw_free() tears down the prepared
+state, and set it again only after prepare succeeds.
+
+Replace the stale FIXME in the duplex constraint comment with a description
+of the current driver behavior: i2sbus still programs a single shared
+transport configuration for both directions, so mixed formats are not
+supported in duplex mode.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202604010125.AvkWBYKI-lkp@intel.com/
+Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
+Cc: stable@vger.kernel.org
+Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+Link: https://patch.msgid.link/20260331-aoa-i2sbus-clear-stale-active-v2-1-3764ae2889a1@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/soundbus/i2sbus/pcm.c |   55 ++++++++++++++++++++++++++++++++--------
+ 1 file changed, 44 insertions(+), 11 deletions(-)
+
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus
+        * currently in use (if any). */
+       hw->rate_min = 5512;
+       hw->rate_max = 192000;
+-      /* if the other stream is active, then we can only
+-       * support what it is currently using.
+-       * FIXME: I lied. This comment is wrong. We can support
+-       * anything that works with the same serial format, ie.
+-       * when recording 24 bit sound we can well play 16 bit
+-       * sound at the same time iff using the same transfer mode.
++      /* If the other stream is already prepared, keep this stream
++       * on the same duplex format and rate.
++       *
++       * i2sbus_pcm_prepare() still programs one shared transport
++       * configuration for both directions, so mixed duplex formats
++       * are not supported here.
+        */
+       if (other->active) {
+-              /* FIXME: is this guaranteed by the alsa api? */
+               hw->formats &= pcm_format_to_bits(i2sdev->format);
+-              /* see above, restrict rates to the one we already have */
++              /* Restrict rates to the one already in use. */
+               hw->rate_min = i2sdev->rate;
+               hw->rate_max = i2sdev->rate;
+       }
+@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2
+ }
+ #endif
++static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
++{
++      struct pcm_info *pi;
++
++      guard(mutex)(&i2sdev->lock);
++
++      get_pcm_info(i2sdev, in, &pi, NULL);
++      pi->active = 0;
++}
++
++static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
++                                 struct snd_pcm_hw_params *params, int in)
++{
++      i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
++      return 0;
++}
++
+ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
+ {
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct
+       get_pcm_info(i2sdev, in, &pi, NULL);
+       if (pi->dbdma_ring.stopping)
+               i2sbus_wait_for_stop(i2sdev, pi);
++      i2sbus_pcm_clear_active(i2sdev, in);
+       return 0;
+ }
++static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
++                                   struct snd_pcm_hw_params *params)
++{
++      return i2sbus_hw_params(substream, params, 0);
++}
++
+ static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
+ {
+       return i2sbus_hw_free(substream, 0);
+ }
++static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
++                                 struct snd_pcm_hw_params *params)
++{
++      return i2sbus_hw_params(substream, params, 1);
++}
++
+ static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
+ {
+       return i2sbus_hw_free(substream, 1);
+@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2s
+               return -EINVAL;
+       runtime = pi->substream->runtime;
+-      pi->active = 1;
+       if (other->active &&
+           ((i2sdev->format != runtime->format)
+            || (i2sdev->rate != runtime->rate)))
+@@ -450,9 +478,11 @@ static int i2sbus_pcm_prepare(struct i2s
+       /* early exit if already programmed correctly */
+       /* not locking these is fine since we touch them only in this function */
+-      if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+-       && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
++      if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
++          in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
++              pi->active = 1;
+               return 0;
++      }
+       /* let's notify the codecs about clocks going away.
+        * For now we only do mastering on the i2s cell... */
+@@ -490,6 +520,7 @@ static int i2sbus_pcm_prepare(struct i2s
+               if (cii->codec->switch_clock)
+                       cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
++      pi->active = 1;
+       return 0;
+ }
+@@ -746,6 +777,7 @@ static snd_pcm_uframes_t i2sbus_playback
+ static const struct snd_pcm_ops i2sbus_playback_ops = {
+       .open =         i2sbus_playback_open,
+       .close =        i2sbus_playback_close,
++      .hw_params =    i2sbus_playback_hw_params,
+       .hw_free =      i2sbus_playback_hw_free,
+       .prepare =      i2sbus_playback_prepare,
+       .trigger =      i2sbus_playback_trigger,
+@@ -814,6 +846,7 @@ static snd_pcm_uframes_t i2sbus_record_p
+ static const struct snd_pcm_ops i2sbus_record_ops = {
+       .open =         i2sbus_record_open,
+       .close =        i2sbus_record_close,
++      .hw_params =    i2sbus_record_hw_params,
+       .hw_free =      i2sbus_record_hw_free,
+       .prepare =      i2sbus_record_prepare,
+       .trigger =      i2sbus_record_trigger,
diff --git a/queue-5.10/alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch b/queue-5.10/alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch
new file mode 100644 (file)
index 0000000..441eae7
--- /dev/null
@@ -0,0 +1,83 @@
+From stable+bounces-242492-greg=kroah.com@vger.kernel.org Sat May  2 00:18:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 14:48:19 -0400
+Subject: ALSA: aoa: Skip devices with no codecs in i2sbus_resume()
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501184819.3923492-2-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit fd7df93013c5118812e63a52635dc6c3a805a1de ]
+
+In i2sbus_resume(), skip devices with an empty codec list, which avoids
+using an uninitialized 'sysclock_factor' in the 32-bit format path in
+i2sbus_pcm_prepare().
+
+In i2sbus_pcm_prepare(), replace two list_for_each_entry() loops with a
+single list_first_entry() now that the codec list is guaranteed to be
+non-empty by all callers.
+
+Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
+Cc: stable@vger.kernel.org
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Link: https://patch.msgid.link/20260310102921.210109-3-thorsten.blum@linux.dev
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/soundbus/i2sbus/core.c |    3 +++
+ sound/aoa/soundbus/i2sbus/pcm.c  |   16 +++++-----------
+ 2 files changed, 8 insertions(+), 11 deletions(-)
+
+--- a/sound/aoa/soundbus/i2sbus/core.c
++++ b/sound/aoa/soundbus/i2sbus/core.c
+@@ -411,6 +411,9 @@ static int i2sbus_resume(struct macio_de
+       int err, ret = 0;
+       list_for_each_entry(i2sdev, &control->list, item) {
++              if (list_empty(&i2sdev->sound.codec_list))
++                      continue;
++
+               /* reset i2s bus format etc. */
+               i2sbus_pcm_prepare_both(i2sdev);
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -411,6 +411,9 @@ static int i2sbus_pcm_prepare(struct i2s
+       /* set stop command */
+       command->command = cpu_to_le16(DBDMA_STOP);
++      cii = list_first_entry(&i2sdev->sound.codec_list,
++                             struct codec_info_item, list);
++
+       /* ok, let's set the serial format and stuff */
+       switch (runtime->format) {
+       /* 16 bit formats */
+@@ -418,13 +421,7 @@ static int i2sbus_pcm_prepare(struct i2s
+       case SNDRV_PCM_FORMAT_U16_BE:
+               /* FIXME: if we add different bus factors we need to
+                * do more here!! */
+-              bi.bus_factor = 0;
+-              list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+-                      bi.bus_factor = cii->codec->bus_factor;
+-                      break;
+-              }
+-              if (!bi.bus_factor)
+-                      return -ENODEV;
++              bi.bus_factor = cii->codec->bus_factor;
+               input_16bit = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S32_BE:
+@@ -438,10 +435,7 @@ static int i2sbus_pcm_prepare(struct i2s
+               return -EINVAL;
+       }
+       /* we assume all sysclocks are the same! */
+-      list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+-              bi.sysclock_factor = cii->codec->sysclock_factor;
+-              break;
+-      }
++      bi.sysclock_factor = cii->codec->sysclock_factor;
+       if (clock_and_divisors(bi.sysclock_factor,
+                              bi.bus_factor,
diff --git a/queue-5.10/alsa-aoa-use-guard-for-mutex-locks.patch b/queue-5.10/alsa-aoa-use-guard-for-mutex-locks.patch
new file mode 100644 (file)
index 0000000..ef8f0b5
--- /dev/null
@@ -0,0 +1,1041 @@
+From stable+bounces-242480-greg=kroah.com@vger.kernel.org Fri May  1 22:58:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 13:27:59 -0400
+Subject: ALSA: aoa: Use guard() for mutex locks
+To: stable@vger.kernel.org
+Cc: Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501172800.3766490-1-sashal@kernel.org>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 1cb6ecbb372002ef9e531c5377e5f60122411e40 ]
+
+Replace the manual mutex lock/unlock pairs with guard() for code
+simplification.
+
+Only code refactoring, and no behavior change.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Link: https://patch.msgid.link/20250829151335.7342-14-tiwai@suse.de
+Stable-dep-of: 5ed060d54915 ("ALSA: aoa: i2sbus: clear stale prepared state")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/codecs/onyx.c         |  104 +++++++++++-------------------------
+ sound/aoa/codecs/tas.c          |  113 +++++++++++++---------------------------
+ sound/aoa/core/gpio-feature.c   |   20 ++-----
+ sound/aoa/core/gpio-pmf.c       |   26 +++------
+ sound/aoa/soundbus/i2sbus/pcm.c |   76 ++++++++------------------
+ 5 files changed, 112 insertions(+), 227 deletions(-)
+
+--- a/sound/aoa/codecs/onyx.c
++++ b/sound/aoa/codecs/onyx.c
+@@ -121,10 +121,9 @@ static int onyx_snd_vol_get(struct snd_k
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       s8 l, r;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+-      mutex_unlock(&onyx->mutex);
+       ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
+       ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
+@@ -145,15 +144,13 @@ static int onyx_snd_vol_put(struct snd_k
+           ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
+               return -EINVAL;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+       if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
+-          r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
+-              mutex_unlock(&onyx->mutex);
++          r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1])
+               return 0;
+-      }
+       onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
+                           ucontrol->value.integer.value[0]
+@@ -161,7 +158,6 @@ static int onyx_snd_vol_put(struct snd_k
+       onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
+                           ucontrol->value.integer.value[1]
+                            - VOLUME_RANGE_SHIFT);
+-      mutex_unlock(&onyx->mutex);
+       return 1;
+ }
+@@ -197,9 +193,8 @@ static int onyx_snd_inputgain_get(struct
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 ig;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
+-      mutex_unlock(&onyx->mutex);
+       ucontrol->value.integer.value[0] =
+               (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
+@@ -216,14 +211,13 @@ static int onyx_snd_inputgain_put(struct
+       if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
+           ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
+               return -EINVAL;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+       n = v;
+       n &= ~ONYX_ADC_PGA_GAIN_MASK;
+       n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
+               & ONYX_ADC_PGA_GAIN_MASK;
+       onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
+-      mutex_unlock(&onyx->mutex);
+       return n != v;
+ }
+@@ -251,9 +245,8 @@ static int onyx_snd_capture_source_get(s
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       s8 v;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+-      mutex_unlock(&onyx->mutex);
+       ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
+@@ -264,13 +257,12 @@ static void onyx_set_capture_source(stru
+ {
+       s8 v;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+       v &= ~ONYX_ADC_INPUT_MIC;
+       if (mic)
+               v |= ONYX_ADC_INPUT_MIC;
+       onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
+-      mutex_unlock(&onyx->mutex);
+ }
+ static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+@@ -311,9 +303,8 @@ static int onyx_snd_mute_get(struct snd_
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 c;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
+-      mutex_unlock(&onyx->mutex);
+       ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
+       ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
+@@ -328,9 +319,9 @@ static int onyx_snd_mute_put(struct snd_
+       u8 v = 0, c = 0;
+       int err = -EBUSY;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       if (onyx->analog_locked)
+-              goto out_unlock;
++              return -EBUSY;
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+       c = v;
+@@ -341,9 +332,6 @@ static int onyx_snd_mute_put(struct snd_
+               c |= ONYX_MUTE_RIGHT;
+       err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
+- out_unlock:
+-      mutex_unlock(&onyx->mutex);
+-
+       return !err ? (v != c) : err;
+ }
+@@ -372,9 +360,8 @@ static int onyx_snd_single_bit_get(struc
+       u8 address = (pv >> 8) & 0xff;
+       u8 mask = pv & 0xff;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, address, &c);
+-      mutex_unlock(&onyx->mutex);
+       ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
+@@ -393,11 +380,10 @@ static int onyx_snd_single_bit_put(struc
+       u8 address = (pv >> 8) & 0xff;
+       u8 mask = pv & 0xff;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       if (spdiflock && onyx->spdif_locked) {
+               /* even if alsamixer doesn't care.. */
+-              err = -EBUSY;
+-              goto out_unlock;
++              return -EBUSY;
+       }
+       onyx_read_register(onyx, address, &v);
+       c = v;
+@@ -406,9 +392,6 @@ static int onyx_snd_single_bit_put(struc
+               c |= mask;
+       err = onyx_write_register(onyx, address, c);
+- out_unlock:
+-      mutex_unlock(&onyx->mutex);
+-
+       return !err ? (v != c) : err;
+ }
+@@ -489,7 +472,7 @@ static int onyx_spdif_get(struct snd_kco
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+       ucontrol->value.iec958.status[0] = v & 0x3e;
+@@ -501,7 +484,6 @@ static int onyx_spdif_get(struct snd_kco
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       ucontrol->value.iec958.status[4] = v & 0x0f;
+-      mutex_unlock(&onyx->mutex);
+       return 0;
+ }
+@@ -512,7 +494,7 @@ static int onyx_spdif_put(struct snd_kco
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+       v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
+@@ -527,7 +509,6 @@ static int onyx_spdif_put(struct snd_kco
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+-      mutex_unlock(&onyx->mutex);
+       return 1;
+ }
+@@ -672,14 +653,13 @@ static int onyx_usable(struct codec_info
+       struct onyx *onyx = cii->codec_data;
+       int spdif_enabled, analog_enabled;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+       analog_enabled =
+               (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
+                != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
+-      mutex_unlock(&onyx->mutex);
+       switch (ti->tag) {
+       case 0: return 1;
+@@ -695,9 +675,8 @@ static int onyx_prepare(struct codec_inf
+ {
+       u8 v;
+       struct onyx *onyx = cii->codec_data;
+-      int err = -EBUSY;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+ #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+       if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
+@@ -706,10 +685,9 @@ static int onyx_prepare(struct codec_inf
+               if (onyx_write_register(onyx,
+                                       ONYX_REG_DAC_CONTROL,
+                                       v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
+-                      goto out_unlock;
++                      return -EBUSY;
+               onyx->analog_locked = 1;
+-              err = 0;
+-              goto out_unlock;
++              return 0;
+       }
+ #endif
+       switch (substream->runtime->rate) {
+@@ -719,8 +697,7 @@ static int onyx_prepare(struct codec_inf
+               /* these rates are ok for all outputs */
+               /* FIXME: program spdif channel control bits here so that
+                *        userspace doesn't have to if it only plays pcm! */
+-              err = 0;
+-              goto out_unlock;
++              return 0;
+       default:
+               /* got some rate that the digital output can't do,
+                * so disable and lock it */
+@@ -728,16 +705,12 @@ static int onyx_prepare(struct codec_inf
+               if (onyx_write_register(onyx,
+                                       ONYX_REG_DIG_INFO4,
+                                       v & ~ONYX_SPDIF_ENABLE))
+-                      goto out_unlock;
++                      return -EBUSY;
+               onyx->spdif_locked = 1;
+-              err = 0;
+-              goto out_unlock;
++              return 0;
+       }
+- out_unlock:
+-      mutex_unlock(&onyx->mutex);
+-
+-      return err;
++      return -EBUSY;
+ }
+ static int onyx_open(struct codec_info_item *cii,
+@@ -745,9 +718,8 @@ static int onyx_open(struct codec_info_i
+ {
+       struct onyx *onyx = cii->codec_data;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx->open_count++;
+-      mutex_unlock(&onyx->mutex);
+       return 0;
+ }
+@@ -757,11 +729,10 @@ static int onyx_close(struct codec_info_
+ {
+       struct onyx *onyx = cii->codec_data;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       onyx->open_count--;
+       if (!onyx->open_count)
+               onyx->spdif_locked = onyx->analog_locked = 0;
+-      mutex_unlock(&onyx->mutex);
+       return 0;
+ }
+@@ -771,7 +742,7 @@ static int onyx_switch_clock(struct code
+ {
+       struct onyx *onyx = cii->codec_data;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       /* this *MUST* be more elaborate later... */
+       switch (what) {
+       case CLOCK_SWITCH_PREPARE_SLAVE:
+@@ -783,7 +754,6 @@ static int onyx_switch_clock(struct code
+       default: /* silence warning */
+               break;
+       }
+-      mutex_unlock(&onyx->mutex);
+       return 0;
+ }
+@@ -794,27 +764,21 @@ static int onyx_suspend(struct codec_inf
+ {
+       struct onyx *onyx = cii->codec_data;
+       u8 v;
+-      int err = -ENXIO;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+-              goto out_unlock;
++              return -ENXIO;
+       onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
+       /* Apple does a sleep here but the datasheet says to do it on resume */
+-      err = 0;
+- out_unlock:
+-      mutex_unlock(&onyx->mutex);
+-
+-      return err;
++      return 0;
+ }
+ static int onyx_resume(struct codec_info_item *cii)
+ {
+       struct onyx *onyx = cii->codec_data;
+       u8 v;
+-      int err = -ENXIO;
+-      mutex_lock(&onyx->mutex);
++      guard(mutex)(&onyx->mutex);
+       /* reset codec */
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+@@ -826,17 +790,13 @@ static int onyx_resume(struct codec_info
+       /* take codec out of suspend (if it still is after reset) */
+       if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+-              goto out_unlock;
++              return -ENXIO;
+       onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
+       /* FIXME: should divide by sample rate, but 8k is the lowest we go */
+       msleep(2205000/8000);
+       /* reset all values */
+       onyx_register_init(onyx);
+-      err = 0;
+- out_unlock:
+-      mutex_unlock(&onyx->mutex);
+-
+-      return err;
++      return 0;
+ }
+ #endif /* CONFIG_PM */
+--- a/sound/aoa/codecs/tas.c
++++ b/sound/aoa/codecs/tas.c
+@@ -236,10 +236,9 @@ static int tas_snd_vol_get(struct snd_kc
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->cached_volume_l;
+       ucontrol->value.integer.value[1] = tas->cached_volume_r;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -255,18 +254,15 @@ static int tas_snd_vol_put(struct snd_kc
+           ucontrol->value.integer.value[1] > 177)
+               return -EINVAL;
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+-       && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
+-              mutex_unlock(&tas->mtx);
++       && tas->cached_volume_r == ucontrol->value.integer.value[1])
+               return 0;
+-      }
+       tas->cached_volume_l = ucontrol->value.integer.value[0];
+       tas->cached_volume_r = ucontrol->value.integer.value[1];
+       if (tas->hw_enabled)
+               tas_set_volume(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -286,10 +282,9 @@ static int tas_snd_mute_get(struct snd_k
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = !tas->mute_l;
+       ucontrol->value.integer.value[1] = !tas->mute_r;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -298,18 +293,15 @@ static int tas_snd_mute_put(struct snd_k
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       if (tas->mute_l == !ucontrol->value.integer.value[0]
+-       && tas->mute_r == !ucontrol->value.integer.value[1]) {
+-              mutex_unlock(&tas->mtx);
++       && tas->mute_r == !ucontrol->value.integer.value[1])
+               return 0;
+-      }
+       tas->mute_l = !ucontrol->value.integer.value[0];
+       tas->mute_r = !ucontrol->value.integer.value[1];
+       if (tas->hw_enabled)
+               tas_set_volume(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -338,10 +330,9 @@ static int tas_snd_mixer_get(struct snd_
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+       ucontrol->value.integer.value[1] = tas->mixer_r[idx];
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -352,19 +343,16 @@ static int tas_snd_mixer_put(struct snd_
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+-       && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
+-              mutex_unlock(&tas->mtx);
++       && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
+               return 0;
+-      }
+       tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+       tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+       if (tas->hw_enabled)
+               tas_set_mixer(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -397,9 +385,8 @@ static int tas_snd_drc_range_get(struct
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->drc_range;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -412,16 +399,13 @@ static int tas_snd_drc_range_put(struct
+           ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
+               return -EINVAL;
+-      mutex_lock(&tas->mtx);
+-      if (tas->drc_range == ucontrol->value.integer.value[0]) {
+-              mutex_unlock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
++      if (tas->drc_range == ucontrol->value.integer.value[0])
+               return 0;
+-      }
+       tas->drc_range = ucontrol->value.integer.value[0];
+       if (tas->hw_enabled)
+               tas3004_set_drc(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -441,9 +425,8 @@ static int tas_snd_drc_switch_get(struct
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->drc_enabled;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -452,16 +435,13 @@ static int tas_snd_drc_switch_put(struct
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
+-      if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
+-              mutex_unlock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
++      if (tas->drc_enabled == ucontrol->value.integer.value[0])
+               return 0;
+-      }
+       tas->drc_enabled = !!ucontrol->value.integer.value[0];
+       if (tas->hw_enabled)
+               tas3004_set_drc(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -487,9 +467,8 @@ static int tas_snd_capture_source_get(st
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -501,7 +480,7 @@ static int tas_snd_capture_source_put(st
+       if (ucontrol->value.enumerated.item[0] > 1)
+               return -EINVAL;
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       oldacr = tas->acr;
+       /*
+@@ -513,13 +492,10 @@ static int tas_snd_capture_source_put(st
+       if (ucontrol->value.enumerated.item[0])
+               tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
+                     TAS_ACR_B_MON_SEL_RIGHT;
+-      if (oldacr == tas->acr) {
+-              mutex_unlock(&tas->mtx);
++      if (oldacr == tas->acr)
+               return 0;
+-      }
+       if (tas->hw_enabled)
+               tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -558,9 +534,8 @@ static int tas_snd_treble_get(struct snd
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->treble;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -572,16 +547,13 @@ static int tas_snd_treble_put(struct snd
+       if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
+           ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
+               return -EINVAL;
+-      mutex_lock(&tas->mtx);
+-      if (tas->treble == ucontrol->value.integer.value[0]) {
+-              mutex_unlock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
++      if (tas->treble == ucontrol->value.integer.value[0])
+               return 0;
+-      }
+       tas->treble = ucontrol->value.integer.value[0];
+       if (tas->hw_enabled)
+               tas_set_treble(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -609,9 +581,8 @@ static int tas_snd_bass_get(struct snd_k
+ {
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       ucontrol->value.integer.value[0] = tas->bass;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -623,16 +594,13 @@ static int tas_snd_bass_put(struct snd_k
+       if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
+           ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
+               return -EINVAL;
+-      mutex_lock(&tas->mtx);
+-      if (tas->bass == ucontrol->value.integer.value[0]) {
+-              mutex_unlock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
++      if (tas->bass == ucontrol->value.integer.value[0])
+               return 0;
+-      }
+       tas->bass = ucontrol->value.integer.value[0];
+       if (tas->hw_enabled)
+               tas_set_bass(tas);
+-      mutex_unlock(&tas->mtx);
+       return 1;
+ }
+@@ -723,13 +691,13 @@ static int tas_switch_clock(struct codec
+               break;
+       case CLOCK_SWITCH_SLAVE:
+               /* Clocks are back, re-init the codec */
+-              mutex_lock(&tas->mtx);
+-              tas_reset_init(tas);
+-              tas_set_volume(tas);
+-              tas_set_mixer(tas);
+-              tas->hw_enabled = 1;
+-              tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+-              mutex_unlock(&tas->mtx);
++              scoped_guard(mutex, &tas->mtx) {
++                      tas_reset_init(tas);
++                      tas_set_volume(tas);
++                      tas_set_mixer(tas);
++                      tas->hw_enabled = 1;
++                      tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
++              }
+               break;
+       default:
+               /* doesn't happen as of now */
+@@ -744,23 +712,21 @@ static int tas_switch_clock(struct codec
+  * our i2c device is suspended, and then take note of that! */
+ static int tas_suspend(struct tas *tas)
+ {
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       tas->hw_enabled = 0;
+       tas->acr |= TAS_ACR_ANALOG_PDOWN;
+       tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+ static int tas_resume(struct tas *tas)
+ {
+       /* reset codec */
+-      mutex_lock(&tas->mtx);
++      guard(mutex)(&tas->mtx);
+       tas_reset_init(tas);
+       tas_set_volume(tas);
+       tas_set_mixer(tas);
+       tas->hw_enabled = 1;
+-      mutex_unlock(&tas->mtx);
+       return 0;
+ }
+@@ -803,14 +769,13 @@ static int tas_init_codec(struct aoa_cod
+               return -EINVAL;
+       }
+-      mutex_lock(&tas->mtx);
+-      if (tas_reset_init(tas)) {
+-              printk(KERN_ERR PFX "tas failed to initialise\n");
+-              mutex_unlock(&tas->mtx);
+-              return -ENXIO;
++      scoped_guard(mutex, &tas->mtx) {
++              if (tas_reset_init(tas)) {
++                      printk(KERN_ERR PFX "tas failed to initialise\n");
++                      return -ENXIO;
++              }
++              tas->hw_enabled = 1;
+       }
+-      tas->hw_enabled = 1;
+-      mutex_unlock(&tas->mtx);
+       if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+                                                  aoa_get_card(),
+--- a/sound/aoa/core/gpio-feature.c
++++ b/sound/aoa/core/gpio-feature.c
+@@ -212,10 +212,9 @@ static void ftr_handle_notify(struct wor
+       struct gpio_notification *notif =
+               container_of(work, struct gpio_notification, work.work);
+-      mutex_lock(&notif->mutex);
++      guard(mutex)(&notif->mutex);
+       if (notif->notify)
+               notif->notify(notif->data);
+-      mutex_unlock(&notif->mutex);
+ }
+ static void gpio_enable_dual_edge(int gpio)
+@@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_ru
+       if (!irq)
+               return -ENODEV;
+-      mutex_lock(&notif->mutex);
++      guard(mutex)(&notif->mutex);
+       old = notif->notify;
+-      if (!old && !notify) {
+-              err = 0;
+-              goto out_unlock;
+-      }
++      if (!old && !notify)
++              return 0;
+       if (old && notify) {
+               if (old == notify && notif->data == data)
+                       err = 0;
+-              goto out_unlock;
++              return err;
+       }
+       if (old && !notify)
+@@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_ru
+       if (!old && notify) {
+               err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
+               if (err)
+-                      goto out_unlock;
++                      return err;
+       }
+       notif->notify = notify;
+       notif->data = data;
+-      err = 0;
+- out_unlock:
+-      mutex_unlock(&notif->mutex);
+-      return err;
++      return 0;
+ }
+ static int ftr_get_detect(struct gpio_runtime *rt,
+--- a/sound/aoa/core/gpio-pmf.c
++++ b/sound/aoa/core/gpio-pmf.c
+@@ -74,10 +74,9 @@ static void pmf_handle_notify(struct wor
+       struct gpio_notification *notif =
+               container_of(work, struct gpio_notification, work.work);
+-      mutex_lock(&notif->mutex);
++      guard(mutex)(&notif->mutex);
+       if (notif->notify)
+               notif->notify(notif->data);
+-      mutex_unlock(&notif->mutex);
+ }
+ static void pmf_gpio_init(struct gpio_runtime *rt)
+@@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_ru
+               return -EINVAL;
+       }
+-      mutex_lock(&notif->mutex);
++      guard(mutex)(&notif->mutex);
+       old = notif->notify;
+-      if (!old && !notify) {
+-              err = 0;
+-              goto out_unlock;
+-      }
++      if (!old && !notify)
++              return 0;
+       if (old && notify) {
+               if (old == notify && notif->data == data)
+                       err = 0;
+-              goto out_unlock;
++              return err;
+       }
+       if (old && !notify) {
+@@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_ru
+       if (!old && notify) {
+               irq_client = kzalloc(sizeof(struct pmf_irq_client),
+                                    GFP_KERNEL);
+-              if (!irq_client) {
+-                      err = -ENOMEM;
+-                      goto out_unlock;
+-              }
++              if (!irq_client)
++                      return -ENOMEM;
+               irq_client->data = notif;
+               irq_client->handler = pmf_handle_notify_irq;
+               irq_client->owner = THIS_MODULE;
+@@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_ru
+                       printk(KERN_ERR "snd-aoa: gpio layer failed to"
+                                       " register %s irq (%d)\n", name, err);
+                       kfree(irq_client);
+-                      goto out_unlock;
++                      return err;
+               }
+               notif->gpio_private = irq_client;
+       }
+       notif->notify = notify;
+       notif->data = data;
+-      err = 0;
+- out_unlock:
+-      mutex_unlock(&notif->mutex);
+-      return err;
++      return 0;
+ }
+ static int pmf_get_detect(struct gpio_runtime *rt,
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus
+       u64 formats = 0;
+       unsigned int rates = 0;
+       struct transfer_info v;
+-      int result = 0;
+       int bus_factor = 0, sysclock_factor = 0;
+       int found_this;
+-      mutex_lock(&i2sdev->lock);
++      guard(mutex)(&i2sdev->lock);
+       get_pcm_info(i2sdev, in, &pi, &other);
+@@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus
+       if (pi->active) {
+               /* alsa messed up */
+-              result = -EBUSY;
+-              goto out_unlock;
++              return -EBUSY;
+       }
+       /* we now need to assign the hw */
+@@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus
+                       ti++;
+               }
+       }
+-      if (!masks_inited || !bus_factor || !sysclock_factor) {
+-              result = -ENODEV;
+-              goto out_unlock;
+-      }
++      if (!masks_inited || !bus_factor || !sysclock_factor)
++              return -ENODEV;
+       /* bus dependent stuff */
+       hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+                  SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
+@@ -194,15 +190,12 @@ static int i2sbus_pcm_open(struct i2sbus
+       hw->periods_max = MAX_DBDMA_COMMANDS;
+       err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+-      if (err < 0) {
+-              result = err;
+-              goto out_unlock;
+-      }
++      if (err < 0)
++              return err;
+       list_for_each_entry(cii, &sdev->codec_list, list) {
+               if (cii->codec->open) {
+                       err = cii->codec->open(cii, pi->substream);
+                       if (err) {
+-                              result = err;
+                               /* unwind */
+                               found_this = 0;
+                               list_for_each_entry_reverse(rev,
+@@ -214,14 +207,12 @@ static int i2sbus_pcm_open(struct i2sbus
+                                       if (rev == cii)
+                                               found_this = 1;
+                               }
+-                              goto out_unlock;
++                              return err;
+                       }
+               }
+       }
+- out_unlock:
+-      mutex_unlock(&i2sdev->lock);
+-      return result;
++      return 0;
+ }
+ #undef CHECK_RATE
+@@ -232,7 +223,7 @@ static int i2sbus_pcm_close(struct i2sbu
+       struct pcm_info *pi;
+       int err = 0, tmp;
+-      mutex_lock(&i2sdev->lock);
++      guard(mutex)(&i2sdev->lock);
+       get_pcm_info(i2sdev, in, &pi, NULL);
+@@ -246,7 +237,6 @@ static int i2sbus_pcm_close(struct i2sbu
+       pi->substream = NULL;
+       pi->active = 0;
+-      mutex_unlock(&i2sdev->lock);
+       return err;
+ }
+@@ -330,33 +320,26 @@ static int i2sbus_pcm_prepare(struct i2s
+       int input_16bit;
+       struct pcm_info *pi, *other;
+       int cnt;
+-      int result = 0;
+       unsigned int cmd, stopaddr;
+-      mutex_lock(&i2sdev->lock);
++      guard(mutex)(&i2sdev->lock);
+       get_pcm_info(i2sdev, in, &pi, &other);
+-      if (pi->dbdma_ring.running) {
+-              result = -EBUSY;
+-              goto out_unlock;
+-      }
++      if (pi->dbdma_ring.running)
++              return -EBUSY;
+       if (pi->dbdma_ring.stopping)
+               i2sbus_wait_for_stop(i2sdev, pi);
+-      if (!pi->substream || !pi->substream->runtime) {
+-              result = -EINVAL;
+-              goto out_unlock;
+-      }
++      if (!pi->substream || !pi->substream->runtime)
++              return -EINVAL;
+       runtime = pi->substream->runtime;
+       pi->active = 1;
+       if (other->active &&
+           ((i2sdev->format != runtime->format)
+-           || (i2sdev->rate != runtime->rate))) {
+-              result = -EINVAL;
+-              goto out_unlock;
+-      }
++           || (i2sdev->rate != runtime->rate)))
++              return -EINVAL;
+       i2sdev->format = runtime->format;
+       i2sdev->rate = runtime->rate;
+@@ -412,10 +395,8 @@ static int i2sbus_pcm_prepare(struct i2s
+                       bi.bus_factor = cii->codec->bus_factor;
+                       break;
+               }
+-              if (!bi.bus_factor) {
+-                      result = -ENODEV;
+-                      goto out_unlock;
+-              }
++              if (!bi.bus_factor)
++                      return -ENODEV;
+               input_16bit = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S32_BE:
+@@ -426,8 +407,7 @@ static int i2sbus_pcm_prepare(struct i2s
+               input_16bit = 0;
+               break;
+       default:
+-              result = -EINVAL;
+-              goto out_unlock;
++              return -EINVAL;
+       }
+       /* we assume all sysclocks are the same! */
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+@@ -438,10 +418,8 @@ static int i2sbus_pcm_prepare(struct i2s
+       if (clock_and_divisors(bi.sysclock_factor,
+                              bi.bus_factor,
+                              runtime->rate,
+-                             &sfr) < 0) {
+-              result = -EINVAL;
+-              goto out_unlock;
+-      }
++                             &sfr) < 0)
++              return -EINVAL;
+       switch (bi.bus_factor) {
+       case 32:
+               sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
+@@ -457,10 +435,8 @@ static int i2sbus_pcm_prepare(struct i2s
+               int err = 0;
+               if (cii->codec->prepare)
+                       err = cii->codec->prepare(cii, &bi, pi->substream);
+-              if (err) {
+-                      result = err;
+-                      goto out_unlock;
+-              }
++              if (err)
++                      return err;
+       }
+       /* codecs are fine with it, so set our clocks */
+       if (input_16bit)
+@@ -476,7 +452,7 @@ static int i2sbus_pcm_prepare(struct i2s
+       /* not locking these is fine since we touch them only in this function */
+       if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+        && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+-              goto out_unlock;
++              return 0;
+       /* let's notify the codecs about clocks going away.
+        * For now we only do mastering on the i2s cell... */
+@@ -514,9 +490,7 @@ static int i2sbus_pcm_prepare(struct i2s
+               if (cii->codec->switch_clock)
+                       cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+- out_unlock:
+-      mutex_unlock(&i2sdev->lock);
+-      return result;
++      return 0;
+ }
+ #ifdef CONFIG_PM
diff --git a/queue-5.10/alsa-core-fix-potential-data-race-at-fasync-handling.patch b/queue-5.10/alsa-core-fix-potential-data-race-at-fasync-handling.patch
new file mode 100644 (file)
index 0000000..8a9ace6
--- /dev/null
@@ -0,0 +1,76 @@
+From stable+bounces-242655-greg=kroah.com@vger.kernel.org Sun May  3 16:33:57 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun,  3 May 2026 07:03:44 -0400
+Subject: ALSA: core: Fix potential data race at fasync handling
+To: stable@vger.kernel.org
+Cc: Takashi Iwai <tiwai@suse.de>, Jake Lamberson <lamberson.jake@gmail.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260503110344.1034091-1-sashal@kernel.org>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 8146cd333d235ed32d48bb803fdf743472d7c783 ]
+
+In snd_fasync_work_fn(), which is the offload work for traversing and
+processing the pending fasync list, the call of kill_fasync() is done
+outside the snd_fasync_lock for avoiding deadlocks.  The problem is
+that its the references of fasync->on, fasync->signal and fasync->poll
+are done there also outside the lock.  Since these may be modified by
+snd_kill_fasync() call concurrently from other process, inconsistent
+values might be passed to kill_fasync().  Although there shouldn't be
+critical UAF, it's still better to be addressed.
+
+This patch moves the kill_fasync() argument evaluations inside the
+snd_fasync_lock for avoiding the data races above.  The handling in
+fasync->on flag is optimized in the loop to skip directly.
+
+Also, for more clarity, snd_fasync_free() takes the lock and unlink
+the pending entry more directly instead of clearing fasync->on flag.
+
+Reported-by: Jake Lamberson <lamberson.jake@gmail.com>
+Fixes: ef34a0ae7a26 ("ALSA: core: Add async signal helpers")
+Cc: <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20260420061721.3253644-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[ replaced scoped_guard(spinlock_irq, &snd_fasync_lock) with explicit spin_lock_irq()/spin_unlock_irq() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/core/misc.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/sound/core/misc.c
++++ b/sound/core/misc.c
+@@ -171,14 +171,18 @@ static LIST_HEAD(snd_fasync_list);
+ static void snd_fasync_work_fn(struct work_struct *work)
+ {
+       struct snd_fasync *fasync;
++      int signal, poll;
+       spin_lock_irq(&snd_fasync_lock);
+       while (!list_empty(&snd_fasync_list)) {
+               fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
+               list_del_init(&fasync->list);
++              if (!fasync->on)
++                      continue;
++              signal = fasync->signal;
++              poll = fasync->poll;
+               spin_unlock_irq(&snd_fasync_lock);
+-              if (fasync->on)
+-                      kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
++              kill_fasync(&fasync->fasync, signal, poll);
+               spin_lock_irq(&snd_fasync_lock);
+       }
+       spin_unlock_irq(&snd_fasync_lock);
+@@ -234,7 +238,11 @@ void snd_fasync_free(struct snd_fasync *
+ {
+       if (!fasync)
+               return;
+-      fasync->on = 0;
++
++      spin_lock_irq(&snd_fasync_lock);
++      list_del_init(&fasync->list);
++      spin_unlock_irq(&snd_fasync_lock);
++
+       flush_work(&snd_fasync_work);
+       kfree(fasync);
+ }
diff --git a/queue-5.10/arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch b/queue-5.10/arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch
new file mode 100644 (file)
index 0000000..9ac9ac6
--- /dev/null
@@ -0,0 +1,137 @@
+From stable+bounces-241768-greg=kroah.com@vger.kernel.org Wed Apr 29 01:35:55 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Apr 2026 16:05:48 -0400
+Subject: arm64/mm: Enable batched TLB flush in unmap_hotplug_range()
+To: stable@vger.kernel.org
+Cc: Anshuman Khandual <anshuman.khandual@arm.com>, Will Deacon <will@kernel.org>, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, "David Hildenbrand (Arm)" <david@kernel.org>, Ryan Roberts <ryan.roberts@arm.com>, Catalin Marinas <catalin.marinas@arm.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260428200548.3191346-1-sashal@kernel.org>
+
+From: Anshuman Khandual <anshuman.khandual@arm.com>
+
+[ Upstream commit 48478b9f791376b4b89018d7afdfd06865498f65 ]
+
+During a memory hot remove operation, both linear and vmemmap mappings for
+the memory range being removed, get unmapped via unmap_hotplug_range() but
+mapped pages get freed only for vmemmap mapping. This is just a sequential
+operation where each table entry gets cleared, followed by a leaf specific
+TLB flush, and then followed by memory free operation when applicable.
+
+This approach was simple and uniform both for vmemmap and linear mappings.
+But linear mapping might contain CONT marked block memory where it becomes
+necessary to first clear out all entire in the range before a TLB flush.
+This is as per the architecture requirement. Hence batch all TLB flushes
+during the table tear down walk and finally do it in unmap_hotplug_range().
+
+Prior to this fix, it was hypothetically possible for a speculative access
+to a higher address in the contiguous block to fill the TLB with shattered
+entries for the entire contiguous range after a lower address had already
+been cleared and invalidated. Due to the table entries being shattered, the
+subsequent TLB invalidation for the higher address would not then clear the
+TLB entries for the lower address, meaning stale TLB entries could persist.
+
+Besides it also helps in improving the performance via TLBI range operation
+along with reduced synchronization instructions. The time spent executing
+unmap_hotplug_range() improved 97% measured over a 2GB memory hot removal
+in KVM guest.
+
+This scheme is not applicable during vmemmap mapping tear down where memory
+needs to be freed and hence a TLB flush is required after clearing out page
+table entry.
+
+Cc: Will Deacon <will@kernel.org>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-kernel@vger.kernel.org
+Closes: https://lore.kernel.org/all/aWZYXhrT6D2M-7-N@willie-the-truck/
+Fixes: bbd6ec605c0f ("arm64/mm: Enable memory hot remove")
+Cc: stable@vger.kernel.org
+Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+[ renamed `__pte_clear()` to `pte_clear()` and inlined `pmd_cont(pmd)` as `pmd_val(pmd) & PMD_SECT_CONT` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/mm/mmu.c |   36 ++++++++++++++++++++----------------
+ 1 file changed, 20 insertions(+), 16 deletions(-)
+
+--- a/arch/arm64/mm/mmu.c
++++ b/arch/arm64/mm/mmu.c
+@@ -862,10 +862,14 @@ static void unmap_hotplug_pte_range(pmd_
+               WARN_ON(!pte_present(pte));
+               pte_clear(&init_mm, addr, ptep);
+-              flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+-              if (free_mapped)
++              if (free_mapped) {
++                      /* CONT blocks are not supported in the vmemmap */
++                      WARN_ON(pte_cont(pte));
++                      flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+                       free_hotplug_page_range(pte_page(pte),
+                                               PAGE_SIZE, altmap);
++              }
++              /* unmap_hotplug_range() flushes TLB for !free_mapped */
+       } while (addr += PAGE_SIZE, addr < end);
+ }
+@@ -886,15 +890,14 @@ static void unmap_hotplug_pmd_range(pud_
+               WARN_ON(!pmd_present(pmd));
+               if (pmd_sect(pmd)) {
+                       pmd_clear(pmdp);
+-
+-                      /*
+-                       * One TLBI should be sufficient here as the PMD_SIZE
+-                       * range is mapped with a single block entry.
+-                       */
+-                      flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+-                      if (free_mapped)
++                      if (free_mapped) {
++                              /* CONT blocks are not supported in the vmemmap */
++                              WARN_ON(pmd_val(pmd) & PMD_SECT_CONT);
++                              flush_tlb_kernel_range(addr, addr + PMD_SIZE);
+                               free_hotplug_page_range(pmd_page(pmd),
+                                                       PMD_SIZE, altmap);
++                      }
++                      /* unmap_hotplug_range() flushes TLB for !free_mapped */
+                       continue;
+               }
+               WARN_ON(!pmd_table(pmd));
+@@ -919,15 +922,12 @@ static void unmap_hotplug_pud_range(p4d_
+               WARN_ON(!pud_present(pud));
+               if (pud_sect(pud)) {
+                       pud_clear(pudp);
+-
+-                      /*
+-                       * One TLBI should be sufficient here as the PUD_SIZE
+-                       * range is mapped with a single block entry.
+-                       */
+-                      flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+-                      if (free_mapped)
++                      if (free_mapped) {
++                              flush_tlb_kernel_range(addr, addr + PUD_SIZE);
+                               free_hotplug_page_range(pud_page(pud),
+                                                       PUD_SIZE, altmap);
++                      }
++                      /* unmap_hotplug_range() flushes TLB for !free_mapped */
+                       continue;
+               }
+               WARN_ON(!pud_table(pud));
+@@ -957,6 +957,7 @@ static void unmap_hotplug_p4d_range(pgd_
+ static void unmap_hotplug_range(unsigned long addr, unsigned long end,
+                               bool free_mapped, struct vmem_altmap *altmap)
+ {
++      unsigned long start = addr;
+       unsigned long next;
+       pgd_t *pgdp, pgd;
+@@ -978,6 +979,9 @@ static void unmap_hotplug_range(unsigned
+               WARN_ON(!pgd_present(pgd));
+               unmap_hotplug_p4d_range(pgdp, addr, next, free_mapped, altmap);
+       } while (addr = next, addr < end);
++
++      if (!free_mapped)
++              flush_tlb_kernel_range(start, end);
+ }
+ static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,
diff --git a/queue-5.10/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch b/queue-5.10/arm64-tlb-flush-walk-cache-when-unsharing-pmd-tables.patch
new file mode 100644 (file)
index 0000000..00bd0ab
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-259527-greg=kroah.com@vger.kernel.org Mon Jun  1 16:36:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 07:02:09 -0400
+Subject: arm64: tlb: Flush walk cache when unsharing PMD tables
+To: stable@vger.kernel.org
+Cc: Zeng Heng <zengheng4@huawei.com>, Catalin Marinas <catalin.marinas@arm.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601110209.439741-1-sashal@kernel.org>
+
+From: Zeng Heng <zengheng4@huawei.com>
+
+[ 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 <zengheng4@huawei.com>
+Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch b/queue-5.10/bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.patch
new file mode 100644 (file)
index 0000000..bcd651e
--- /dev/null
@@ -0,0 +1,204 @@
+From stable+bounces-256833-greg=kroah.com@vger.kernel.org Sat May 30 05:23:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:53:21 -0400
+Subject: Bluetooth: Consolidate code around sk_alloc into a helper function
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529235323.1964735-1-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 6bfa273e533d7b25eee3d74e28a7fe8e6a8e7a93 ]
+
+This consolidates code around sk_alloc into bt_sock_alloc which does
+take care of common initialization.
+
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/bluetooth.h |    2 ++
+ net/bluetooth/af_bluetooth.c      |   21 +++++++++++++++++++++
+ net/bluetooth/bnep/sock.c         |   10 +---------
+ net/bluetooth/hci_sock.c          |   10 ++--------
+ net/bluetooth/l2cap_sock.c        |   10 +---------
+ net/bluetooth/rfcomm/sock.c       |   13 +++----------
+ net/bluetooth/sco.c               |   10 +---------
+ 7 files changed, 31 insertions(+), 45 deletions(-)
+
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -314,6 +314,8 @@ int  bt_sock_register(int proto, const s
+ void bt_sock_unregister(int proto);
+ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
+ void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
++struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
++                         struct proto *prot, int proto, gfp_t prio, int kern);
+ int  bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+                    int flags);
+ int  bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg,
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -138,6 +138,27 @@ static int bt_sock_create(struct net *ne
+       return err;
+ }
++struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
++                         struct proto *prot, int proto, gfp_t prio, int kern)
++{
++      struct sock *sk;
++
++      sk = sk_alloc(net, PF_BLUETOOTH, prio, prot, kern);
++      if (!sk)
++              return NULL;
++
++      sock_init_data(sock, sk);
++      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
++
++      sock_reset_flag(sk, SOCK_ZAPPED);
++
++      sk->sk_protocol = proto;
++      sk->sk_state    = BT_OPEN;
++
++      return sk;
++}
++EXPORT_SYMBOL(bt_sock_alloc);
++
+ void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
+ {
+       write_lock(&l->lock);
+--- a/net/bluetooth/bnep/sock.c
++++ b/net/bluetooth/bnep/sock.c
+@@ -204,21 +204,13 @@ static int bnep_sock_create(struct net *
+       if (sock->type != SOCK_RAW)
+               return -ESOCKTNOSUPPORT;
+-      sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern);
++      sk = bt_sock_alloc(net, sock, &bnep_proto, protocol, GFP_ATOMIC, kern);
+       if (!sk)
+               return -ENOMEM;
+-      sock_init_data(sock, sk);
+-
+       sock->ops = &bnep_sock_ops;
+-
+       sock->state = SS_UNCONNECTED;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = protocol;
+-      sk->sk_state    = BT_OPEN;
+-
+       bt_sock_link(&bnep_sk_list, sk);
+       return 0;
+ }
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -2091,18 +2091,12 @@ static int hci_sock_create(struct net *n
+       sock->ops = &hci_sock_ops;
+-      sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, kern);
++      sk = bt_sock_alloc(net, sock, &hci_sk_proto, protocol, GFP_ATOMIC,
++                         kern);
+       if (!sk)
+               return -ENOMEM;
+-      sock_init_data(sock, sk);
+-
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = protocol;
+-
+       sock->state = SS_UNCONNECTED;
+-      sk->sk_state = BT_OPEN;
+       sk->sk_destruct = hci_sock_destruct;
+       bt_sock_link(&hci_sk_list, sk);
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -1901,21 +1901,13 @@ static struct sock *l2cap_sock_alloc(str
+       struct sock *sk;
+       struct l2cap_chan *chan;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, kern);
++      sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       sk->sk_destruct = l2cap_sock_destruct;
+       sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state = BT_OPEN;
+-
+       chan = l2cap_chan_create();
+       if (!chan) {
+               sk_free(sk);
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -280,18 +280,16 @@ static struct proto rfcomm_proto = {
+       .obj_size       = sizeof(struct rfcomm_pinfo)
+ };
+-static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern)
++static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock,
++                                    int proto, gfp_t prio, int kern)
+ {
+       struct rfcomm_dlc *d;
+       struct sock *sk;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto, kern);
++      sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       d = rfcomm_dlc_alloc(prio);
+       if (!d) {
+               sk_free(sk);
+@@ -310,11 +308,6 @@ static struct sock *rfcomm_sock_alloc(st
+       sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+       sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state    = BT_OPEN;
+-
+       bt_sock_link(&rfcomm_sk_list, sk);
+       BT_DBG("sk %p", sk);
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -491,21 +491,13 @@ static struct sock *sco_sock_alloc(struc
+ {
+       struct sock *sk;
+-      sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, kern);
++      sk = bt_sock_alloc(net, sock, &sco_proto, proto, prio, kern);
+       if (!sk)
+               return NULL;
+-      sock_init_data(sock, sk);
+-      INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+-
+       sk->sk_destruct = sco_sock_destruct;
+       sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
+-      sock_reset_flag(sk, SOCK_ZAPPED);
+-
+-      sk->sk_protocol = proto;
+-      sk->sk_state    = BT_OPEN;
+-
+       sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
+       bt_sock_link(&sco_sk_list, sk);
diff --git a/queue-5.10/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch b/queue-5.10/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
new file mode 100644 (file)
index 0000000..8c5c27f
--- /dev/null
@@ -0,0 +1,210 @@
+From stable+bounces-256730-greg=kroah.com@vger.kernel.org Sat May 30 00:49:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 15:18:12 -0400
+Subject: Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del()
+To: stable@vger.kernel.org
+Cc: "Safa KarakuÅŸ" <safa.karakus@secunnix.com>, "Siwei Zhang" <oss@fourdim.xyz>, "Luiz Augusto von Dentz" <luiz.von.dentz@intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260529191812.1690614-1-sashal@kernel.org>
+
+From: Safa KarakuÅŸ <safa.karakus@secunnix.com>
+
+[ Upstream commit ab1513597c6cf17cd1ad2a21e3b045421b48e022 ]
+
+bt_accept_dequeue() unlinks a not-yet-accepted child from the parent
+accept queue and release_sock()s it before returning, so the returned
+sk has no caller reference and is unlocked.
+
+l2cap_sock_cleanup_listen() walks these children on listening-socket
+close.  A concurrent HCI disconnect drives hci_rx_work ->
+l2cap_conn_del() which runs l2cap_chan_del() + l2cap_sock_kill() and
+frees the child sk and its l2cap_chan; cleanup_listen() then uses both:
+
+  BUG: KASAN: slab-use-after-free in l2cap_sock_kill
+    l2cap_sock_kill / l2cap_sock_cleanup_listen / __x64_sys_close
+  Freed by: l2cap_conn_del -> l2cap_sock_close_cb -> l2cap_sock_kill
+
+This is distinct from the two fixes already in this area: commit
+e83f5e24da741 ("Bluetooth: serialize accept_q access") serialises the
+accept_q list/poll and takes temporary refs inside bt_accept_dequeue(),
+and CVE-2025-39860 serialises the userspace close()/accept() race by
+calling cleanup_listen() under lock_sock() in l2cap_sock_release().
+Neither covers l2cap_conn_del() running from hci_rx_work, so this UAF
+still reproduces on current bluetooth/master.
+
+Take the reference at the source: bt_accept_dequeue() does sock_hold()
+while sk is still locked, before release_sock(); callers sock_put().
+cleanup_listen() pins the chan with l2cap_chan_hold_unless_zero() under
+a brief child sk lock (serialising vs l2cap_sock_teardown_cb()), drops
+it before l2cap_chan_lock(), and skips a duplicate l2cap_sock_kill() on
+SOCK_DEAD.  conn->lock is not taken here: cleanup_listen() runs under
+the parent sk lock and that would invert
+conn->lock -> chan->lock -> sk_lock (lockdep).
+
+KASAN/SMP: an unprivileged listen/close vs HCI-disconnect race produced
+12 use-after-free reports per run before this change; 0, and no lockdep
+report, over 1600+ raced iterations after it on bluetooth/master.
+
+Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode")
+Cc: stable@vger.kernel.org
+Reported-by: Siwei Zhang <oss@fourdim.xyz>
+Reviewed-by: Siwei Zhang <oss@fourdim.xyz>
+Signed-off-by: Safa KarakuÅŸ <safa.karakus@secunnix.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/af_bluetooth.c |   10 ++++++++
+ net/bluetooth/l2cap_sock.c   |   51 +++++++++++++++++++++++++++++++++++++------
+ net/bluetooth/rfcomm/sock.c  |    9 ++++++-
+ net/bluetooth/sco.c          |    9 ++++++-
+ 4 files changed, 70 insertions(+), 9 deletions(-)
+
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -237,6 +237,16 @@ restart:
+                       if (newsock)
+                               sock_graft(sk, newsock);
++                      /* Hand the caller a reference taken while sk is
++                       * still locked.  bt_accept_unlink() just dropped
++                       * the accept-queue reference; without this hold a
++                       * concurrent teardown (e.g. l2cap_conn_del() ->
++                       * l2cap_sock_kill()) could free sk between
++                       * release_sock() and the caller using it.  Every
++                       * caller drops this with sock_put() when done.
++                       */
++                      sock_hold(sk);
++
+                       release_sock(sk);
+                       return sk;
+               }
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -366,8 +366,13 @@ static int l2cap_sock_accept(struct sock
+               }
+               nsk = bt_accept_dequeue(sk, newsock);
+-              if (nsk)
++              if (nsk) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps nsk alive from here.
++                       */
++                      sock_put(nsk);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
+@@ -1432,22 +1437,54 @@ static void l2cap_sock_cleanup_listen(st
+       BT_DBG("parent %p state %s", parent,
+              state_to_string(parent->sk_state));
+-      /* Close not yet accepted channels */
++      /* Close not yet accepted channels.
++       *
++       * bt_accept_dequeue() now returns sk with an extra reference held
++       * (taken while sk was still locked) so a concurrent l2cap_conn_del()
++       * -> l2cap_sock_kill() cannot free sk under us.
++       *
++       * cleanup_listen() runs under the parent sk lock, so unlike
++       * l2cap_sock_shutdown() we must NOT take conn->lock here: that would
++       * establish sk_lock -> conn->lock and invert the established
++       * conn->lock -> chan->lock -> sk_lock order (lockdep deadlock).
++       *
++       * Instead, briefly take the child sk lock to fetch and pin its chan.
++       * l2cap_conn_del() reaches the chan free only via
++       * l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes
++       * the child sk lock; holding it across l2cap_chan_hold_unless_zero()
++       * therefore guarantees the chan cannot be freed while we read and
++       * pin it (hold_unless_zero() additionally skips a chan already past
++       * its last reference).  We then drop the sk lock before taking
++       * chan->lock, so sk and chan locks are never held together.
++       */
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+-              struct l2cap_chan *chan = l2cap_pi(sk)->chan;
++              struct l2cap_chan *chan;
++
++              lock_sock_nested(sk, L2CAP_NESTING_NORMAL);
++              chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
++              release_sock(sk);
++              if (!chan) {
++                      /* l2cap_conn_del() already tearing this child down */
++                      sock_put(sk);
++                      continue;
++              }
+               BT_DBG("child chan %p state %s", chan,
+                      state_to_string(chan->state));
+-              l2cap_chan_hold(chan);
+               l2cap_chan_lock(chan);
+-
+               __clear_chan_timer(chan);
+               l2cap_chan_close(chan, ECONNRESET);
+-              l2cap_sock_kill(sk);
+-
++              /* l2cap_conn_del() may already have killed this socket
++               * (it sets SOCK_DEAD); skip the duplicate to avoid a
++               * double sock_put()/l2cap_chan_put().
++               */
++              if (!sock_flag(sk, SOCK_DEAD))
++                      l2cap_sock_kill(sk);
+               l2cap_chan_unlock(chan);
++
+               l2cap_chan_put(chan);
++              sock_put(sk);
+       }
+ }
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -190,6 +190,8 @@ static void rfcomm_sock_cleanup_listen(s
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               rfcomm_sock_close(sk);
+               rfcomm_sock_kill(sk);
++              /* Drop the reference handed back by bt_accept_dequeue(). */
++              sock_put(sk);
+       }
+       parent->sk_state  = BT_CLOSED;
+@@ -508,8 +510,13 @@ static int rfcomm_sock_accept(struct soc
+               }
+               nsk = bt_accept_dequeue(sk, newsock);
+-              if (nsk)
++              if (nsk) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps nsk alive from here.
++                       */
++                      sock_put(nsk);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -384,6 +384,8 @@ static void sco_sock_cleanup_listen(stru
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               sco_sock_close(sk);
+               sco_sock_kill(sk);
++              /* Drop the reference handed back by bt_accept_dequeue(). */
++              sock_put(sk);
+       }
+       parent->sk_state  = BT_CLOSED;
+@@ -677,8 +679,13 @@ static int sco_sock_accept(struct socket
+               }
+               ch = bt_accept_dequeue(sk, newsock);
+-              if (ch)
++              if (ch) {
++                      /* Drop the bridging ref from bt_accept_dequeue();
++                       * the grafted socket keeps ch alive from here.
++                       */
++                      sock_put(ch);
+                       break;
++              }
+               if (!timeo) {
+                       err = -EAGAIN;
diff --git a/queue-5.10/bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.patch b/queue-5.10/bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.patch
new file mode 100644 (file)
index 0000000..523e5e9
--- /dev/null
@@ -0,0 +1,94 @@
+From stable+bounces-244880-greg=kroah.com@vger.kernel.org Sat May  9 07:34:38 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 22:04:26 -0400
+Subject: Bluetooth: hci_event: fix potential UAF in SSP passkey handlers
+To: stable@vger.kernel.org
+Cc: Shuvam Pandey <shuvampandey1@gmail.com>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509020426.2866832-1-sashal@kernel.org>
+
+From: Shuvam Pandey <shuvampandey1@gmail.com>
+
+[ Upstream commit 85fa3512048793076eef658f66489112dcc91993 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_user_passkey_notify_evt() and hci_keypress_notify_evt(), otherwise
+the connection can be freed concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage in both
+handlers.
+
+Keep the existing keypress notification behavior unchanged by routing
+the early exits through a common unlock path.
+
+Fixes: 92a25256f142 ("Bluetooth: mgmt: Implement support for passkey notification")
+Cc: stable@vger.kernel.org
+Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hci_event.c |   18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -4842,9 +4842,11 @@ static void hci_user_passkey_notify_evt(
+       BT_DBG("%s", hdev->name);
++      hci_dev_lock(hdev);
++
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (!conn)
+-              return;
++              goto unlock;
+       conn->passkey_notify = __le32_to_cpu(ev->passkey);
+       conn->passkey_entered = 0;
+@@ -4853,6 +4855,9 @@ static void hci_user_passkey_notify_evt(
+               mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+                                        conn->dst_type, conn->passkey_notify,
+                                        conn->passkey_entered);
++
++unlock:
++      hci_dev_unlock(hdev);
+ }
+ static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+@@ -4862,14 +4867,16 @@ static void hci_keypress_notify_evt(stru
+       BT_DBG("%s", hdev->name);
++      hci_dev_lock(hdev);
++
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (!conn)
+-              return;
++              goto unlock;
+       switch (ev->type) {
+       case HCI_KEYPRESS_STARTED:
+               conn->passkey_entered = 0;
+-              return;
++              goto unlock;
+       case HCI_KEYPRESS_ENTERED:
+               conn->passkey_entered++;
+@@ -4884,13 +4891,16 @@ static void hci_keypress_notify_evt(stru
+               break;
+       case HCI_KEYPRESS_COMPLETED:
+-              return;
++              goto unlock;
+       }
+       if (hci_dev_test_flag(hdev, HCI_MGMT))
+               mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+                                        conn->dst_type, conn->passkey_notify,
+                                        conn->passkey_entered);
++
++unlock:
++      hci_dev_unlock(hdev);
+ }
+ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
diff --git a/queue-5.10/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch b/queue-5.10/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch
new file mode 100644 (file)
index 0000000..e610ff4
--- /dev/null
@@ -0,0 +1,155 @@
+From stable+bounces-256802-greg=kroah.com@vger.kernel.org Sat May 30 04:51:08 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:20:59 -0400
+Subject: Bluetooth: hci_qca: Convert timeout from jiffies to ms
+To: stable@vger.kernel.org
+Cc: Shuai Zhang <shuai.zhang@oss.qualcomm.com>, Paul Menzel <pmenzel@molgen.mpg.de>, Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529232059.1870888-1-sashal@kernel.org>
+
+From: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
+
+[ 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 <pmenzel@molgen.mpg.de>
+Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+[ adapted to `vmalloc`-based memdump path and older `qca_serdev_shutdown(struct device *dev)` signature ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1041,7 +1040,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));
+@@ -1309,7 +1308,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 */
+       if (qca_is_wcn399x(qca_soc_type(hu)))
+@@ -1330,8 +1329,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
+@@ -1490,7 +1489,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);
+ }
+@@ -2071,7 +2070,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;
+@@ -2129,7 +2128,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);
+@@ -2150,15 +2149,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");
+@@ -2210,7 +2209,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);
+       }
+@@ -2219,7 +2218,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-5.10/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch b/queue-5.10/bluetooth-init-sk_peer_-on-bt_sock_alloc.patch
new file mode 100644 (file)
index 0000000..cb1e1ee
--- /dev/null
@@ -0,0 +1,139 @@
+From stable+bounces-256834-greg=kroah.com@vger.kernel.org Sat May 30 05:23:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:53:22 -0400
+Subject: Bluetooth: Init sk_peer_* on bt_sock_alloc
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529235323.1964735-2-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ 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 <luiz.von.dentz@intel.com>
+Stable-dep-of: e83f5e24da74 ("Bluetooth: serialize accept_q access")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -155,6 +155,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);
+@@ -177,6 +185,9 @@ EXPORT_SYMBOL(bt_sock_unlink);
+ 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);
+@@ -189,6 +200,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
+@@ -255,21 +255,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
+@@ -177,21 +177,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)
+ {
+@@ -267,8 +252,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)
+@@ -324,8 +307,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-5.10/bluetooth-serialize-accept_q-access.patch b/queue-5.10/bluetooth-serialize-accept_q-access.patch
new file mode 100644 (file)
index 0000000..2d55d4c
--- /dev/null
@@ -0,0 +1,222 @@
+From stable+bounces-256835-greg=kroah.com@vger.kernel.org Sat May 30 05:23:33 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:53:23 -0400
+Subject: Bluetooth: serialize accept_q access
+To: stable@vger.kernel.org
+Cc: Jiexun Wang <wangjiexun2025@gmail.com>, Jann Horn <jannh@google.com>, Yuan Tan <yuantan098@gmail.com>, Yifan Wu <yifanwucs@gmail.com>, Juefei Pu <tomapufckgml@gmail.com>, Xin Liu <bird@lzu.edu.cn>, Ren Wei <n05ec@lzu.edu.cn>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529235323.1964735-3-sashal@kernel.org>
+
+From: Jiexun Wang <wangjiexun2025@gmail.com>
+
+[ 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 <jannh@google.com>
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
+Reviewed-by: Jann Horn <jannh@google.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -291,6 +291,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
+@@ -149,6 +149,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);
+@@ -187,6 +188,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);
+@@ -197,9 +199,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.
+        */
+@@ -217,8 +223,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);
+@@ -227,45 +231,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);
+@@ -293,6 +324,8 @@ restart:
+                       sock_hold(sk);
+                       release_sock(sk);
++                      if (next)
++                              sock_put(next);
+                       return sk;
+               }
+@@ -496,18 +529,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-5.10/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch b/queue-5.10/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch
new file mode 100644 (file)
index 0000000..2774f3d
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-247812-greg=kroah.com@vger.kernel.org Fri May 15 20:44:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 11:07: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 <yochaie@sweet.security>, Yochai Eisenrich <echelonh@gmail.com>, David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515150704.3261684-1-sashal@kernel.org>
+
+From: Yochai Eisenrich <yochaie@sweet.security>
+
+[ 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 <echelonh@gmail.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ioctl.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3587,7 +3587,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;
+@@ -3643,7 +3643,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-5.10/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch b/queue-5.10/btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
new file mode 100644 (file)
index 0000000..87e8f2b
--- /dev/null
@@ -0,0 +1,224 @@
+From stable+bounces-249161-greg=kroah.com@vger.kernel.org Mon May 18 06:53:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 21:23:18 -0400
+Subject: btrfs: fix missing last_unlink_trans update when removing a directory
+To: stable@vger.kernel.org
+Cc: Filipe Manana <fdmanana@suse.com>, Slava0135 <slava.kovalevskiy.2014@gmail.com>, David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260518012318.481373-1-sashal@kernel.org>
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ 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
+
+   <trigger power failure>
+
+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]  <TASK>
+   [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]  </TASK>
+   [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 <slava.kovalevskiy.2014@gmail.com>
+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 <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/inode.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4178,6 +4178,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, root, BTRFS_I(dir),
+                       BTRFS_I(d_inode(dentry)), dentry->d_name.name,
diff --git a/queue-5.10/can-ucan-fix-devres-lifetime.patch b/queue-5.10/can-ucan-fix-devres-lifetime.patch
new file mode 100644 (file)
index 0000000..3d3c12c
--- /dev/null
@@ -0,0 +1,44 @@
+From stable+bounces-244892-greg=kroah.com@vger.kernel.org Sat May  9 08:38:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 23:08:29 -0400
+Subject: can: ucan: fix devres lifetime
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>, Marc Kleine-Budde <mkl@pengutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509030829.3038691-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit fed4626501c871890da287bec62a96e52da1af89 ]
+
+USB drivers bind to USB interfaces and any device managed resources
+should have their lifetime tied to the interface rather than parent USB
+device. This avoids issues like memory leaks when drivers are unbound
+without their devices being physically disconnected (e.g. on probe
+deferral or configuration changes).
+
+Fix the control message buffer lifetime so that it is released on driver
+unbind.
+
+Fixes: 9f2d3eae88d2 ("can: ucan: add driver for Theobroma Systems UCAN devices")
+Cc: stable@vger.kernel.org     # 4.19
+Cc: Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260327104520.1310158-1-johan@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/can/usb/ucan.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/can/usb/ucan.c
++++ b/drivers/net/can/usb/ucan.c
+@@ -1394,7 +1394,7 @@ static int ucan_probe(struct usb_interfa
+        */
+       /* Prepare Memory for control transfers */
+-      ctl_msg_buffer = devm_kzalloc(&udev->dev,
++      ctl_msg_buffer = devm_kzalloc(&intf->dev,
+                                     sizeof(union ucan_ctl_payload),
+                                     GFP_KERNEL);
+       if (!ctl_msg_buffer) {
diff --git a/queue-5.10/can-ucan-fix-typos-in-comments.patch b/queue-5.10/can-ucan-fix-typos-in-comments.patch
new file mode 100644 (file)
index 0000000..d58a64f
--- /dev/null
@@ -0,0 +1,46 @@
+From stable+bounces-244891-greg=kroah.com@vger.kernel.org Sat May  9 08:38:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 23:08:28 -0400
+Subject: can: ucan: fix typos in comments
+To: stable@vger.kernel.org
+Cc: Julia Lawall <Julia.Lawall@inria.fr>, Marc Kleine-Budde <mkl@pengutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509030829.3038691-1-sashal@kernel.org>
+
+From: Julia Lawall <Julia.Lawall@inria.fr>
+
+[ Upstream commit c34983c94166689358372d4af8d5def57752860c ]
+
+Various spelling mistakes in comments.
+Detected with the help of Coccinelle.
+
+Link: https://lore.kernel.org/all/20220314115354.144023-28-Julia.Lawall@inria.fr
+Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
+Acked-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Stable-dep-of: fed4626501c8 ("can: ucan: fix devres lifetime")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/can/usb/ucan.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/usb/ucan.c
++++ b/drivers/net/can/usb/ucan.c
+@@ -1393,7 +1393,7 @@ static int ucan_probe(struct usb_interfa
+        * Stage 3 for the final driver initialisation.
+        */
+-      /* Prepare Memory for control transferes */
++      /* Prepare Memory for control transfers */
+       ctl_msg_buffer = devm_kzalloc(&udev->dev,
+                                     sizeof(union ucan_ctl_payload),
+                                     GFP_KERNEL);
+@@ -1527,7 +1527,7 @@ static int ucan_probe(struct usb_interfa
+       ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
+                                    sizeof(union ucan_ctl_payload));
+       if (ret > 0) {
+-              /* copy string while ensuring zero terminiation */
++              /* copy string while ensuring zero termination */
+               strncpy(firmware_str, up->ctl_msg_buffer->raw,
+                       sizeof(union ucan_ctl_payload));
+               firmware_str[sizeof(union ucan_ctl_payload)] = '\0';
diff --git a/queue-5.10/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch b/queue-5.10/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch
new file mode 100644 (file)
index 0000000..210a3a9
--- /dev/null
@@ -0,0 +1,113 @@
+From stable+bounces-244967-greg=kroah.com@vger.kernel.org Sat May  9 21:03:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  9 May 2026 11:33:30 -0400
+Subject: ceph: only d_add() negative dentries when they are unhashed
+To: stable@vger.kernel.org
+Cc: Max Kellermann <max.kellermann@ionos.com>, Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>, Ilya Dryomov <idryomov@gmail.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509153330.3523928-1-sashal@kernel.org>
+
+From: Max Kellermann <max.kellermann@ionos.com>
+
+[ 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:
+  <TASK>
+  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 <max.kellermann@ionos.com>
+Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ceph/dir.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/fs/ceph/dir.c
++++ b/fs/ceph/dir.c
+@@ -719,7 +719,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);
+                       }
+               }
+       }
+@@ -775,7 +776,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-5.10/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch b/queue-5.10/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch
new file mode 100644 (file)
index 0000000..ec3d42e
--- /dev/null
@@ -0,0 +1,68 @@
+From stable+bounces-245037-greg=kroah.com@vger.kernel.org Sun May 10 21:13:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 11:43:38 -0400
+Subject: crypto: caam - guard HMAC key hex dumps in hash_digest_key
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260510154339.144690-2-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ 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 <thorsten.blum@linux.dev>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -3261,7 +3261,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),
+@@ -3281,7 +3281,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-5.10/dm-btree-improve-btree-residency.patch b/queue-5.10/dm-btree-improve-btree-residency.patch
new file mode 100644 (file)
index 0000000..3031afc
--- /dev/null
@@ -0,0 +1,622 @@
+From stable+bounces-249086-greg=kroah.com@vger.kernel.org Sun May 17 19:21:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 09:51:48 -0400
+Subject: dm btree: improve btree residency
+To: stable@vger.kernel.org
+Cc: Joe Thornber <ejt@redhat.com>, Colin Ian King <colin.king@canonical.com>, Mike Snitzer <snitzer@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260517135149.147613-1-sashal@kernel.org>
+
+From: Joe Thornber <ejt@redhat.com>
+
+[ Upstream commit 4eafdb1515a708d97e4659bd488ddac19f274c4f ]
+
+This commit improves the residency of btrees built in the metadata for
+dm-thin and dm-cache.
+
+When inserting a new entry into a full btree node the current code
+splits the node into two.  This can result in very many half full nodes,
+particularly if the insertions are occurring in an ascending order (as
+happens in dm-thin with large writes).
+
+With this commit, when we insert into a full node we first try and move
+some entries to a neighbouring node that has space, failing that it
+tries to split two neighbouring nodes into three.
+
+Results are given below.  'Residency' is how full nodes are on average
+as a percentage.  Average instruction counts for the operations
+are given to show the extra processing has little overhead.
+
+                         +--------------------------+--------------------------+
+                         |         Before           |         After            |
++------------+-----------+-----------+--------------+-----------+--------------+
+|    Test    |   Phase   | Residency | Instructions | Residency | Instructions |
++------------+-----------+-----------+--------------+-----------+--------------+
+| Ascending  | insert    |        50 |         1876 |        96 |         1930 |
+|            | overwrite |        50 |         1789 |        96 |         1746 |
+|            | lookup    |        50 |          778 |        96 |          778 |
+| Descending | insert    |        50 |         3024 |        96 |         3181 |
+|            | overwrite |        50 |         1789 |        96 |         1746 |
+|            | lookup    |        50 |          778 |        96 |          778 |
+| Random     | insert    |        68 |         3800 |        84 |         3736 |
+|            | overwrite |        68 |         4254 |        84 |         3911 |
+|            | lookup    |        68 |          779 |        84 |          779 |
+| Runs       | insert    |        63 |         2546 |        82 |         2815 |
+|            | overwrite |        63 |         2013 |        82 |         1986 |
+|            | lookup    |        63 |          778 |        82 |          779 |
++------------+-----------+-----------+--------------+-----------+--------------+
+
+   Ascending - keys are inserted in ascending order.
+   Descending - keys are inserted in descending order.
+   Random - keys are inserted in random order.
+   Runs - keys are split into ascending runs of ~20 length.  Then
+          the runs are shuffled.
+
+Signed-off-by: Joe Thornber <ejt@redhat.com>
+Signed-off-by: Colin Ian King <colin.king@canonical.com> # contains_key() fix
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Stable-dep-of: 09a65adc7d8b ("dm-thin: fix metadata refcount underflow")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/persistent-data/dm-btree.c               |  451 ++++++++++++++++++--
+ drivers/md/persistent-data/dm-transaction-manager.c |    9 
+ drivers/md/persistent-data/dm-transaction-manager.h |   10 
+ 3 files changed, 439 insertions(+), 31 deletions(-)
+
+--- a/drivers/md/persistent-data/dm-btree.c
++++ b/drivers/md/persistent-data/dm-btree.c
+@@ -502,6 +502,122 @@ out:
+ EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
++/*----------------------------------------------------------------*/
++
++/*
++ * Copies entries from one region of a btree node to another.  The regions
++ * must not overlap.
++ */
++static void copy_entries(struct btree_node *dest, unsigned dest_offset,
++                       struct btree_node *src, unsigned src_offset,
++                       unsigned count)
++{
++      size_t value_size = le32_to_cpu(dest->header.value_size);
++      memcpy(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
++      memcpy(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
++}
++
++/*
++ * Moves entries from one region fo a btree node to another.  The regions
++ * may overlap.
++ */
++static void move_entries(struct btree_node *dest, unsigned dest_offset,
++                       struct btree_node *src, unsigned src_offset,
++                       unsigned count)
++{
++      size_t value_size = le32_to_cpu(dest->header.value_size);
++      memmove(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
++      memmove(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
++}
++
++/*
++ * Erases the first 'count' entries of a btree node, shifting following
++ * entries down into their place.
++ */
++static void shift_down(struct btree_node *n, unsigned count)
++{
++      move_entries(n, 0, n, count, le32_to_cpu(n->header.nr_entries) - count);
++}
++
++/*
++ * Moves entries in a btree node up 'count' places, making space for
++ * new entries at the start of the node.
++ */
++static void shift_up(struct btree_node *n, unsigned count)
++{
++      move_entries(n, count, n, 0, le32_to_cpu(n->header.nr_entries));
++}
++
++/*
++ * Redistributes entries between two btree nodes to make them
++ * have similar numbers of entries.
++ */
++static void redistribute2(struct btree_node *left, struct btree_node *right)
++{
++      unsigned nr_left = le32_to_cpu(left->header.nr_entries);
++      unsigned nr_right = le32_to_cpu(right->header.nr_entries);
++      unsigned total = nr_left + nr_right;
++      unsigned target_left = total / 2;
++      unsigned target_right = total - target_left;
++
++      if (nr_left < target_left) {
++              unsigned delta = target_left - nr_left;
++              copy_entries(left, nr_left, right, 0, delta);
++              shift_down(right, delta);
++      } else if (nr_left > target_left) {
++              unsigned delta = nr_left - target_left;
++              if (nr_right)
++                      shift_up(right, delta);
++              copy_entries(right, 0, left, target_left, delta);
++      }
++
++      left->header.nr_entries = cpu_to_le32(target_left);
++      right->header.nr_entries = cpu_to_le32(target_right);
++}
++
++/*
++ * Redistribute entries between three nodes.  Assumes the central
++ * node is empty.
++ */
++static void redistribute3(struct btree_node *left, struct btree_node *center,
++                        struct btree_node *right)
++{
++      unsigned nr_left = le32_to_cpu(left->header.nr_entries);
++      unsigned nr_center = le32_to_cpu(center->header.nr_entries);
++      unsigned nr_right = le32_to_cpu(right->header.nr_entries);
++      unsigned total, target_left, target_center, target_right;
++
++      BUG_ON(nr_center);
++
++      total = nr_left + nr_right;
++      target_left = total / 3;
++      target_center = (total - target_left) / 2;
++      target_right = (total - target_left - target_center);
++
++      if (nr_left < target_left) {
++              unsigned left_short = target_left - nr_left;
++              copy_entries(left, nr_left, right, 0, left_short);
++              copy_entries(center, 0, right, left_short, target_center);
++              shift_down(right, nr_right - target_right);
++
++      } else if (nr_left < (target_left + target_center)) {
++              unsigned left_to_center = nr_left - target_left;
++              copy_entries(center, 0, left, target_left, left_to_center);
++              copy_entries(center, left_to_center, right, 0, target_center - left_to_center);
++              shift_down(right, nr_right - target_right);
++
++      } else {
++              unsigned right_short = target_right - nr_right;
++              shift_up(right, right_short);
++              copy_entries(right, 0, left, nr_left - right_short, right_short);
++              copy_entries(center, 0, left, target_left, nr_left - target_left);
++      }
++
++      left->header.nr_entries = cpu_to_le32(target_left);
++      center->header.nr_entries = cpu_to_le32(target_center);
++      right->header.nr_entries = cpu_to_le32(target_right);
++}
++
+ /*
+  * Splits a node by creating a sibling node and shifting half the nodes
+  * contents across.  Assumes there is a parent node, and it has room for
+@@ -532,12 +648,10 @@ EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
+  *
+  * Where A* is a shadow of A.
+  */
+-static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
+-                             uint64_t key)
++static int split_one_into_two(struct shadow_spine *s, unsigned parent_index,
++                            struct dm_btree_value_type *vt, uint64_t key)
+ {
+       int r;
+-      size_t size;
+-      unsigned nr_left, nr_right;
+       struct dm_block *left, *right, *parent;
+       struct btree_node *ln, *rn, *pn;
+       __le64 location;
+@@ -551,36 +665,18 @@ static int btree_split_sibling(struct sh
+       ln = dm_block_data(left);
+       rn = dm_block_data(right);
+-      nr_left = le32_to_cpu(ln->header.nr_entries) / 2;
+-      nr_right = le32_to_cpu(ln->header.nr_entries) - nr_left;
+-
+-      ln->header.nr_entries = cpu_to_le32(nr_left);
+-
+       rn->header.flags = ln->header.flags;
+-      rn->header.nr_entries = cpu_to_le32(nr_right);
++      rn->header.nr_entries = cpu_to_le32(0);
+       rn->header.max_entries = ln->header.max_entries;
+       rn->header.value_size = ln->header.value_size;
+-      memcpy(rn->keys, ln->keys + nr_left, nr_right * sizeof(rn->keys[0]));
+-
+-      size = le32_to_cpu(ln->header.flags) & INTERNAL_NODE ?
+-              sizeof(uint64_t) : s->info->value_type.size;
+-      memcpy(value_ptr(rn, 0), value_ptr(ln, nr_left),
+-             size * nr_right);
++      redistribute2(ln, rn);
+-      /*
+-       * Patch up the parent
+-       */
++      /* patch up the parent */
+       parent = shadow_parent(s);
+-
+       pn = dm_block_data(parent);
+-      location = cpu_to_le64(dm_block_location(left));
+-      __dm_bless_for_disk(&location);
+-      memcpy_disk(value_ptr(pn, parent_index),
+-                  &location, sizeof(__le64));
+       location = cpu_to_le64(dm_block_location(right));
+       __dm_bless_for_disk(&location);
+-
+       r = insert_at(sizeof(__le64), pn, parent_index + 1,
+                     le64_to_cpu(rn->keys[0]), &location);
+       if (r) {
+@@ -588,6 +684,7 @@ static int btree_split_sibling(struct sh
+               return r;
+       }
++      /* patch up the spine */
+       if (key < le64_to_cpu(rn->keys[0])) {
+               unlock_block(s->info, right);
+               s->nodes[1] = left;
+@@ -600,6 +697,121 @@ static int btree_split_sibling(struct sh
+ }
+ /*
++ * We often need to modify a sibling node.  This function shadows a particular
++ * child of the given parent node.  Making sure to update the parent to point
++ * to the new shadow.
++ */
++static int shadow_child(struct dm_btree_info *info, struct dm_btree_value_type *vt,
++                      struct btree_node *parent, unsigned index,
++                      struct dm_block **result)
++{
++      int r, inc;
++      dm_block_t root;
++      struct btree_node *node;
++
++      root = value64(parent, index);
++
++      r = dm_tm_shadow_block(info->tm, root, &btree_node_validator,
++                             result, &inc);
++      if (r)
++              return r;
++
++      node = dm_block_data(*result);
++
++      if (inc)
++              inc_children(info->tm, node, vt);
++
++      *((__le64 *) value_ptr(parent, index)) =
++              cpu_to_le64(dm_block_location(*result));
++
++      return 0;
++}
++
++/*
++ * Splits two nodes into three.  This is more work, but results in fuller
++ * nodes, so saves metadata space.
++ */
++static int split_two_into_three(struct shadow_spine *s, unsigned parent_index,
++                                struct dm_btree_value_type *vt, uint64_t key)
++{
++      int r;
++      unsigned middle_index;
++      struct dm_block *left, *middle, *right, *parent;
++      struct btree_node *ln, *rn, *mn, *pn;
++      __le64 location;
++
++      parent = shadow_parent(s);
++      pn = dm_block_data(parent);
++
++      if (parent_index == 0) {
++              middle_index = 1;
++              left = shadow_current(s);
++              r = shadow_child(s->info, vt, pn, parent_index + 1, &right);
++              if (r)
++                      return r;
++      } else {
++              middle_index = parent_index;
++              right = shadow_current(s);
++              r = shadow_child(s->info, vt, pn, parent_index - 1, &left);
++              if (r)
++                      return r;
++      }
++
++      r = new_block(s->info, &middle);
++      if (r < 0)
++              return r;
++
++      ln = dm_block_data(left);
++      mn = dm_block_data(middle);
++      rn = dm_block_data(right);
++
++      mn->header.nr_entries = cpu_to_le32(0);
++      mn->header.flags = ln->header.flags;
++      mn->header.max_entries = ln->header.max_entries;
++      mn->header.value_size = ln->header.value_size;
++
++      redistribute3(ln, mn, rn);
++
++      /* patch up the parent */
++      pn->keys[middle_index] = rn->keys[0];
++      location = cpu_to_le64(dm_block_location(middle));
++      __dm_bless_for_disk(&location);
++      r = insert_at(sizeof(__le64), pn, middle_index,
++                    le64_to_cpu(mn->keys[0]), &location);
++      if (r) {
++              if (shadow_current(s) != left)
++                      unlock_block(s->info, left);
++
++              unlock_block(s->info, middle);
++
++              if (shadow_current(s) != right)
++                      unlock_block(s->info, right);
++
++              return r;
++      }
++
++
++      /* patch up the spine */
++      if (key < le64_to_cpu(mn->keys[0])) {
++              unlock_block(s->info, middle);
++              unlock_block(s->info, right);
++              s->nodes[1] = left;
++      } else if (key < le64_to_cpu(rn->keys[0])) {
++              unlock_block(s->info, left);
++              unlock_block(s->info, right);
++              s->nodes[1] = middle;
++      } else {
++              unlock_block(s->info, left);
++              unlock_block(s->info, middle);
++              s->nodes[1] = right;
++      }
++
++      return 0;
++}
++
++/*----------------------------------------------------------------*/
++
++/*
+  * Splits a node by creating two new children beneath the given node.
+  *
+  * Before:
+@@ -692,6 +904,186 @@ static int btree_split_beneath(struct sh
+       return 0;
+ }
++/*----------------------------------------------------------------*/
++
++/*
++ * Redistributes a node's entries with its left sibling.
++ */
++static int rebalance_left(struct shadow_spine *s, struct dm_btree_value_type *vt,
++                        unsigned parent_index, uint64_t key)
++{
++      int r;
++      struct dm_block *sib;
++      struct btree_node *left, *right, *parent = dm_block_data(shadow_parent(s));
++
++      r = shadow_child(s->info, vt, parent, parent_index - 1, &sib);
++      if (r)
++              return r;
++
++      left = dm_block_data(sib);
++      right = dm_block_data(shadow_current(s));
++      redistribute2(left, right);
++      *key_ptr(parent, parent_index) = right->keys[0];
++
++      if (key < le64_to_cpu(right->keys[0])) {
++              unlock_block(s->info, s->nodes[1]);
++              s->nodes[1] = sib;
++      } else {
++              unlock_block(s->info, sib);
++      }
++
++      return 0;
++}
++
++/*
++ * Redistributes a nodes entries with its right sibling.
++ */
++static int rebalance_right(struct shadow_spine *s, struct dm_btree_value_type *vt,
++                         unsigned parent_index, uint64_t key)
++{
++      int r;
++      struct dm_block *sib;
++      struct btree_node *left, *right, *parent = dm_block_data(shadow_parent(s));
++
++      r = shadow_child(s->info, vt, parent, parent_index + 1, &sib);
++      if (r)
++              return r;
++
++      left = dm_block_data(shadow_current(s));
++      right = dm_block_data(sib);
++      redistribute2(left, right);
++      *key_ptr(parent, parent_index + 1) = right->keys[0];
++
++      if (key < le64_to_cpu(right->keys[0])) {
++              unlock_block(s->info, sib);
++      } else {
++              unlock_block(s->info, s->nodes[1]);
++              s->nodes[1] = sib;
++      }
++
++      return 0;
++}
++
++/*
++ * Returns the number of spare entries in a node.
++ */
++static int get_node_free_space(struct dm_btree_info *info, dm_block_t b, unsigned *space)
++{
++      int r;
++      unsigned nr_entries;
++      struct dm_block *block;
++      struct btree_node *node;
++
++      r = bn_read_lock(info, b, &block);
++      if (r)
++              return r;
++
++      node = dm_block_data(block);
++      nr_entries = le32_to_cpu(node->header.nr_entries);
++      *space = le32_to_cpu(node->header.max_entries) - nr_entries;
++
++      unlock_block(info, block);
++      return 0;
++}
++
++/*
++ * Make space in a node, either by moving some entries to a sibling,
++ * or creating a new sibling node.  SPACE_THRESHOLD defines the minimum
++ * number of free entries that must be in the sibling to make the move
++ * worth while.  If the siblings are shared (eg, part of a snapshot),
++ * then they are not touched, since this break sharing and so consume
++ * more space than we save.
++ */
++#define SPACE_THRESHOLD 8
++static int rebalance_or_split(struct shadow_spine *s, struct dm_btree_value_type *vt,
++                            unsigned parent_index, uint64_t key)
++{
++      int r;
++      struct btree_node *parent = dm_block_data(shadow_parent(s));
++      unsigned nr_parent = le32_to_cpu(parent->header.nr_entries);
++      unsigned free_space;
++      int left_shared = 0, right_shared = 0;
++
++      /* Should we move entries to the left sibling? */
++      if (parent_index > 0) {
++              dm_block_t left_b = value64(parent, parent_index - 1);
++              r = dm_tm_block_is_shared(s->info->tm, left_b, &left_shared);
++              if (r)
++                      return r;
++
++              if (!left_shared) {
++                      r = get_node_free_space(s->info, left_b, &free_space);
++                      if (r)
++                              return r;
++
++                      if (free_space >= SPACE_THRESHOLD)
++                              return rebalance_left(s, vt, parent_index, key);
++              }
++      }
++
++      /* Should we move entries to the right sibling? */
++      if (parent_index < (nr_parent - 1)) {
++              dm_block_t right_b = value64(parent, parent_index + 1);
++              r = dm_tm_block_is_shared(s->info->tm, right_b, &right_shared);
++              if (r)
++                      return r;
++
++              if (!right_shared) {
++                      r = get_node_free_space(s->info, right_b, &free_space);
++                      if (r)
++                              return r;
++
++                      if (free_space >= SPACE_THRESHOLD)
++                              return rebalance_right(s, vt, parent_index, key);
++              }
++      }
++
++      /*
++       * We need to split the node, normally we split two nodes
++       * into three.  But when inserting a sequence that is either
++       * monotonically increasing or decreasing it's better to split
++       * a single node into two.
++       */
++      if (left_shared || right_shared || (nr_parent <= 2) ||
++          (parent_index == 0) || (parent_index + 1 == nr_parent)) {
++              return split_one_into_two(s, parent_index, vt, key);
++      } else {
++              return split_two_into_three(s, parent_index, vt, key);
++      }
++}
++
++/*
++ * Does the node contain a particular key?
++ */
++static bool contains_key(struct btree_node *node, uint64_t key)
++{
++      int i = lower_bound(node, key);
++
++      if (i >= 0 && le64_to_cpu(node->keys[i]) == key)
++              return true;
++
++      return false;
++}
++
++/*
++ * In general we preemptively make sure there's a free entry in every
++ * node on the spine when doing an insert.  But we can avoid that with
++ * leaf nodes if we know it's an overwrite.
++ */
++static bool has_space_for_insert(struct btree_node *node, uint64_t key)
++{
++      if (node->header.nr_entries == node->header.max_entries) {
++              if (le32_to_cpu(node->header.flags) & LEAF_NODE) {
++                      /* we don't need space if it's an overwrite */
++                      return contains_key(node, key);
++              }
++
++              return false;
++      }
++
++      return true;
++}
++
+ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
+                           struct dm_btree_value_type *vt,
+                           uint64_t key, unsigned *index)
+@@ -721,17 +1113,18 @@ static int btree_insert_raw(struct shado
+               node = dm_block_data(shadow_current(s));
+-              if (node->header.nr_entries == node->header.max_entries) {
++              if (!has_space_for_insert(node, key)) {
+                       if (top)
+                               r = btree_split_beneath(s, key);
+                       else
+-                              r = btree_split_sibling(s, i, key);
++                              r = rebalance_or_split(s, vt, i, key);
+                       if (r < 0)
+                               return r;
+-              }
+-              node = dm_block_data(shadow_current(s));
++                      /* making space can cause the current node to change */
++                      node = dm_block_data(shadow_current(s));
++              }
+               i = lower_bound(node, key);
+--- a/drivers/md/persistent-data/dm-transaction-manager.c
++++ b/drivers/md/persistent-data/dm-transaction-manager.c
+@@ -379,6 +379,15 @@ int dm_tm_ref(struct dm_transaction_mana
+       return dm_sm_get_count(tm->sm, b, result);
+ }
++int dm_tm_block_is_shared(struct dm_transaction_manager *tm, dm_block_t b,
++                        int *result)
++{
++      if (tm->is_clone)
++              return -EWOULDBLOCK;
++
++      return dm_sm_count_is_more_than_one(tm->sm, b, result);
++}
++
+ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
+ {
+       return tm->bm;
+--- a/drivers/md/persistent-data/dm-transaction-manager.h
++++ b/drivers/md/persistent-data/dm-transaction-manager.h
+@@ -103,8 +103,14 @@ void dm_tm_inc(struct dm_transaction_man
+ void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b);
+-int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
+-            uint32_t *result);
++int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b, uint32_t *result);
++
++/*
++ * Finds out if a given block is shared (ie. has a reference count higher
++ * than one).
++ */
++int dm_tm_block_is_shared(struct dm_transaction_manager *tm, dm_block_t b,
++                        int *result);
+ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);
diff --git a/queue-5.10/dm-thin-fix-metadata-refcount-underflow.patch b/queue-5.10/dm-thin-fix-metadata-refcount-underflow.patch
new file mode 100644 (file)
index 0000000..103e61f
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-249087-greg=kroah.com@vger.kernel.org Sun May 17 19:22:00 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 09:51:49 -0400
+Subject: dm-thin: fix metadata refcount underflow
+To: stable@vger.kernel.org
+Cc: Mikulas Patocka <mpatocka@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260517135149.147613-2-sashal@kernel.org>
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+[ Upstream commit 09a65adc7d8bbfce06392cb6d375468e2728ead5 ]
+
+There's a bug in dm-thin in the function rebalance_children. If the
+internal btree node has one entry, the code tries to copy all btree
+entries from the node's child to the node itself and then decrement the
+child's reference count.
+
+If the child node is shared (it has reference count > 1), we won't free
+it, so there would be two pointers to each of the grandchildren nodes.
+But the reference counts of the grandchildren is not increased, thus the
+reference count doesn't match the number of pointers that point to the
+grandchildren. This results in "device mapper: space map common: unable
+to decrement block" errors.
+
+Fix this bug by incrementing reference counts on the grandchildren if the
+btree node is shared.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: 3241b1d3e0aa ("dm: add persistent data library")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/persistent-data/dm-btree-remove.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/md/persistent-data/dm-btree-remove.c
++++ b/drivers/md/persistent-data/dm-btree-remove.c
+@@ -415,12 +415,20 @@ static int rebalance_children(struct sha
+       if (le32_to_cpu(n->header.nr_entries) == 1) {
+               struct dm_block *child;
++              int is_shared;
+               dm_block_t b = value64(n, 0);
++              r = dm_tm_block_is_shared(info->tm, b, &is_shared);
++              if (r)
++                      return r;
++
+               r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child);
+               if (r)
+                       return r;
++              if (is_shared)
++                      inc_children(info->tm, dm_block_data(child), vt);
++
+               memcpy(n, dm_block_data(child),
+                      dm_bm_block_size(dm_tm_get_bm(info->tm)));
diff --git a/queue-5.10/drm-nouveau-fix-u32-overflow-in-pushbuf-reloc-bounds-check.patch b/queue-5.10/drm-nouveau-fix-u32-overflow-in-pushbuf-reloc-bounds-check.patch
new file mode 100644 (file)
index 0000000..b10dbd7
--- /dev/null
@@ -0,0 +1,54 @@
+From sashal@kernel.org Tue Apr 28 14:32:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Apr 2026 05:02:42 -0400
+Subject: drm/nouveau: fix u32 overflow in pushbuf reloc bounds check
+To: stable@vger.kernel.org
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Lyude Paul <lyude@redhat.com>, Danilo Krummrich <dakr@kernel.org>, Maarten Lankhorst <maarten.lankhorst@linux.intel.com>, Maxime Ripard <mripard@kernel.org>, Thomas Zimmermann <tzimmermann@suse.de>, David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>, stable <stable@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260428090242.2131744-1-sashal@kernel.org>
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[ Upstream commit 2fc87d37be1b730a149b035f9375fdb8cc5333a5 ]
+
+nouveau_gem_pushbuf_reloc_apply() validates each relocation with
+
+    if (r->reloc_bo_offset + 4 > nvbo->bo.base.size)
+
+but reloc_bo_offset is __u32 (uapi/drm/nouveau_drm.h) and the integer
+literal 4 promotes to unsigned int, so the addition is performed in 32
+bits and wraps before the comparison against the size_t bo size.
+
+Cast to u64 so the addition happens in 64-bit arithmetic.
+
+Cc: Lyude Paul <lyude@redhat.com>
+Cc: Danilo Krummrich <dakr@kernel.org>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: David Airlie <airlied@gmail.com>
+Cc: Simona Vetter <simona@ffwll.ch>
+Reported-by: Anthropic
+Cc: stable <stable@kernel.org>
+Assisted-by: gkh_clanker_t1000
+Fixes: a1606a9596e5 ("drm/nouveau: new gem pushbuf interface, bump to 0.0.16")
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ Add Fixes: tag. - Danilo ]
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+[ Kept 5.10's `nvbo->bo.mem.num_pages << PAGE_SHIFT` instead of upstream's `nvbo->bo.base.size` accessor. ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/nouveau/nouveau_gem.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
+@@ -618,7 +618,7 @@ nouveau_gem_pushbuf_reloc_apply(struct n
+               }
+               nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv;
+-              if (unlikely(r->reloc_bo_offset + 4 >
++              if (unlikely((u64)r->reloc_bo_offset + 4 >
+                            nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
+                       NV_PRINTK(err, cli, "reloc outside of bo\n");
+                       ret = -EINVAL;
diff --git a/queue-5.10/erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch b/queue-5.10/erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch
new file mode 100644 (file)
index 0000000..c102441
--- /dev/null
@@ -0,0 +1,95 @@
+From stable+bounces-242495-greg=kroah.com@vger.kernel.org Sat May  2 00:42:00 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 15:11:50 -0400
+Subject: erofs: fix the out-of-bounds nameoff handling for trailing dirents
+To: stable@vger.kernel.org
+Cc: Gao Xiang <hsiangkao@linux.alibaba.com>, Yuhao Jiang <danisjiang@gmail.com>, Junrui Luo <moonafterrain@outlook.com>, Chao Yu <chao@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501191150.3973995-1-sashal@kernel.org>
+
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+
+[ Upstream commit d18a3b5d337fa412a38e776e6b4b857a58836575 ]
+
+Currently we already have boundary-checks for nameoffs, but the trailing
+dirents are special since the namelens are calculated with strnlen()
+with unchecked nameoffs.
+
+If a crafted EROFS has a trailing dirent with nameoff >= maxsize,
+maxsize - nameoff can underflow, causing strnlen() to read past the
+directory block.
+
+nameoff0 should also be verified to be a multiple of
+`sizeof(struct erofs_dirent)` as well [1].
+
+[1] https://sashiko.dev/#/patchset/20260416063511.3173774-1-hsiangkao%40linux.alibaba.com
+
+Fixes: 3aa8ec716e52 ("staging: erofs: add directory operations")
+Fixes: 33bac912840f ("staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()")
+Reported-by: Yuhao Jiang <danisjiang@gmail.com>
+Reported-by: Junrui Luo <moonafterrain@outlook.com>
+Closes: https://lore.kernel.org/r/A0FD7E0F-7558-49B0-8BC8-EB1ECDB2479A@outlook.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+[ replaced upstream `bsz` with `PAGE_SIZE` and `sizeof(*de)` with `sizeof(struct erofs_dirent)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/erofs/dir.c |   30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/fs/erofs/dir.c
++++ b/fs/erofs/dir.c
+@@ -38,20 +38,18 @@ static int erofs_fill_dentries(struct in
+               nameoff = le16_to_cpu(de->nameoff);
+               de_name = (char *)dentry_blk + nameoff;
+-              /* the last dirent in the block? */
+-              if (de + 1 >= end)
+-                      de_namelen = strnlen(de_name, maxsize - nameoff);
+-              else
++              /* non-trailing dirent in the directory block? */
++              if (de + 1 < end)
+                       de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
++              else if (maxsize <= nameoff)
++                      goto err_bogus;
++              else
++                      de_namelen = strnlen(de_name, maxsize - nameoff);
+-              /* a corrupted entry is found */
+-              if (nameoff + de_namelen > maxsize ||
+-                  de_namelen > EROFS_NAME_LEN) {
+-                      erofs_err(dir->i_sb, "bogus dirent @ nid %llu",
+-                                EROFS_I(dir)->nid);
+-                      DBG_BUGON(1);
+-                      return -EFSCORRUPTED;
+-              }
++              /* a corrupted entry is found (including negative namelen) */
++              if (!in_range32(de_namelen, 1, EROFS_NAME_LEN) ||
++                  nameoff + de_namelen > maxsize)
++                      goto err_bogus;
+               debug_one_dentry(d_type, de_name, de_namelen);
+               if (!dir_emit(ctx, de_name, de_namelen,
+@@ -63,6 +61,10 @@ static int erofs_fill_dentries(struct in
+       }
+       *ofs = maxsize;
+       return 0;
++err_bogus:
++      erofs_err(dir->i_sb, "bogus dirent @ nid %llu", EROFS_I(dir)->nid);
++      DBG_BUGON(1);
++      return -EFSCORRUPTED;
+ }
+ static int erofs_readdir(struct file *f, struct dir_context *ctx)
+@@ -96,8 +98,8 @@ static int erofs_readdir(struct file *f,
+               nameoff = le16_to_cpu(de->nameoff);
+-              if (nameoff < sizeof(struct erofs_dirent) ||
+-                  nameoff >= PAGE_SIZE) {
++              if (!nameoff || nameoff >= PAGE_SIZE ||
++                  (nameoff % sizeof(struct erofs_dirent))) {
+                       erofs_err(dir->i_sb,
+                                 "invalid de[0].nameoff %u @ nid %llu",
+                                 nameoff, EROFS_I(dir)->nid);
diff --git a/queue-5.10/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch b/queue-5.10/f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
new file mode 100644 (file)
index 0000000..a4b07c7
--- /dev/null
@@ -0,0 +1,68 @@
+From stable+bounces-249895-greg=kroah.com@vger.kernel.org Wed May 20 17:25:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 07:46:53 -0400
+Subject: f2fs: fix incorrect file address mapping when inline inode is unwritten
+To: stable@vger.kernel.org
+Cc: Yongpeng Yang <yangyongpeng@xiaomi.com>, stable@kernel.org, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520114653.3469848-1-sashal@kernel.org>
+
+From: Yongpeng Yang <yangyongpeng@xiaomi.com>
+
+[ 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 <yangyongpeng@xiaomi.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ renamed `ifolio` to `ipage` in `inline_data_addr()` and `F2FS_INODE()` calls ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inline.c |   13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -761,7 +761,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;
+@@ -794,9 +794,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-5.10/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch b/queue-5.10/f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch
new file mode 100644 (file)
index 0000000..c319d88
--- /dev/null
@@ -0,0 +1,76 @@
+From stable+bounces-240974-greg=kroah.com@vger.kernel.org Fri Apr 24 19:39:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:07:49 -0400
+Subject: f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
+To: stable@vger.kernel.org
+Cc: Yongpeng Yang <yangyongpeng@xiaomi.com>, stable@kernel.org, syzbot+6e4cb1cac5efc96ea0ca@syzkaller.appspotmail.com, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424140749.2151644-1-sashal@kernel.org>
+
+From: Yongpeng Yang <yangyongpeng@xiaomi.com>
+
+[ Upstream commit 2d9c4a4ed4eef1f82c5b16b037aee8bad819fd53 ]
+
+The xfstests case "generic/107" and syzbot have both reported a NULL
+pointer dereference.
+
+The concurrent scenario that triggers the panic is as follows:
+
+F2FS_WB_CP_DATA write callback          umount
+                                        - f2fs_write_checkpoint
+                                         - f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA)
+- blk_mq_end_request
+ - bio_endio
+  - f2fs_write_end_io
+   : dec_page_count(sbi, F2FS_WB_CP_DATA)
+   : wake_up(&sbi->cp_wait)
+                                        - kill_f2fs_super
+                                         - kill_block_super
+                                          - f2fs_put_super
+                                           : iput(sbi->node_inode)
+                                           : sbi->node_inode = NULL
+   : f2fs_in_warm_node_list
+    - is_node_folio // sbi->node_inode is NULL and panic
+
+The root cause is that f2fs_put_super() calls iput(sbi->node_inode) and
+sets sbi->node_inode to NULL after sbi->nr_pages[F2FS_WB_CP_DATA] is
+decremented to zero. As a result, f2fs_in_warm_node_list() may
+dereference a NULL node_inode when checking whether a folio belongs to
+the node inode, leading to a panic.
+
+This patch fixes the issue by calling f2fs_in_warm_node_list() before
+decrementing sbi->nr_pages[F2FS_WB_CP_DATA], thus preventing the
+use-after-free condition.
+
+Cc: stable@kernel.org
+Fixes: 50fa53eccf9f ("f2fs: fix to avoid broken of dnode block list")
+Reported-by: syzbot+6e4cb1cac5efc96ea0ca@syzkaller.appspotmail.com
+Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ folio => page ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/data.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -377,6 +377,8 @@ static void f2fs_write_end_io(struct bio
+               f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
+                                       page->index != nid_of_node(page));
++              if (f2fs_in_warm_node_list(sbi, page))
++                      f2fs_del_fsync_node_entry(sbi, page);
+               dec_page_count(sbi, type);
+@@ -388,8 +390,6 @@ static void f2fs_write_end_io(struct bio
+                               wq_has_sleeper(&sbi->cp_wait))
+                       wake_up(&sbi->cp_wait);
+-              if (f2fs_in_warm_node_list(sbi, page))
+-                      f2fs_del_fsync_node_entry(sbi, page);
+               clear_cold_data(page);
+               end_page_writeback(page);
+       }
diff --git a/queue-5.10/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch b/queue-5.10/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch
new file mode 100644 (file)
index 0000000..cceaf4e
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247713-greg=kroah.com@vger.kernel.org Fri May 15 17:42:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 07:56:13 -0400
+Subject: fbcon: Avoid OOB font access if console rotation fails
+To: stable@vger.kernel.org
+Cc: Thomas Zimmermann <tzimmermann@suse.de>, Helge Deller <deller@gmx.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515115613.3041015-1-sashal@kernel.org>
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ 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 <tzimmermann@suse.de>
+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 <deller@gmx.de>
+[ renamed `par` to `ops` to match the 6.12 local pointer name ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch b/queue-5.10/hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch
new file mode 100644 (file)
index 0000000..875b6d3
--- /dev/null
@@ -0,0 +1,142 @@
+From stable+bounces-244876-greg=kroah.com@vger.kernel.org Sat May  9 06:53:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 21:22:58 -0400
+Subject: hfsplus: fix held lock freed on hfsplus_fill_super()
+To: stable@vger.kernel.org
+Cc: Zilin Guan <zilin@seu.edu.cn>, Viacheslav Dubeyko <slava@dubeyko.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509012258.2847375-2-sashal@kernel.org>
+
+From: Zilin Guan <zilin@seu.edu.cn>
+
+[ 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:
+       <TASK>
+       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
+       </TASK>
+
+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 <zilin@seu.edu.cn>
+Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Tested-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch b/queue-5.10/hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch
new file mode 100644 (file)
index 0000000..82b5e3a
--- /dev/null
@@ -0,0 +1,189 @@
+From stable+bounces-244875-greg=kroah.com@vger.kernel.org Sat May  9 06:53:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 21:22:57 -0400
+Subject: hfsplus: fix uninit-value by validating catalog record size
+To: stable@vger.kernel.org
+Cc: Deepanshu Kartikey <kartikey406@gmail.com>, syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com, Viacheslav Dubeyko <slava@dubeyko.com>, Charalampos Mitrodimas <charmitro@posteo.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509012258.2847375-1-sashal@kernel.org>
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ 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 <slava@dubeyko.com>
+Tested-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Suggested-by: Charalampos Mitrodimas <charmitro@posteo.net>
+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 <kartikey406@gmail.com>
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Link: https://lore.kernel.org/r/20260307010302.41547-1-kartikey406@gmail.com
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Stable-dep-of: 90c500e4fd83 ("hfsplus: fix held lock freed on hfsplus_fill_super()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -536,6 +536,15 @@ int hfsplus_submit_bio(struct super_bloc
+                      void **data, int op, int op_flags);
+ 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-5.10/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch b/queue-5.10/hv_netvsc-use-kmap_local_page-in-netvsc_copy_to_send_buf.patch
new file mode 100644 (file)
index 0000000..0328279
--- /dev/null
@@ -0,0 +1,91 @@
+From stable+bounces-263454-greg=kroah.com@vger.kernel.org Tue Jun 16 02:19:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 16:49:43 -0400
+Subject: hv_netvsc: use kmap_local_page in netvsc_copy_to_send_buf
+To: stable@vger.kernel.org
+Cc: Anton Leontev <leontyevantony@gmail.com>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260615204943.2445304-1-sashal@kernel.org>
+
+From: Anton Leontev <leontyevantony@gmail.com>
+
+[ 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 <leontyevantony@gmail.com>
+Link: https://patch.msgid.link/20260604165938.32033-1-leontyevantony@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/sched.h>
+ #include <linux/wait.h>
+ #include <linux/mm.h>
++#include <linux/highmem.h>
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -889,12 +890,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_atomic(page);
++
++                      memcpy(dest, src + off, chunk);
++                      kunmap_atomic(src);
++                      dest += chunk;
++                      paddr += chunk;
++                      len -= chunk;
++              }
+       }
+       if (padding)
diff --git a/queue-5.10/ice-fix-vf-queue-configuration-with-low-mtu-values.patch b/queue-5.10/ice-fix-vf-queue-configuration-with-low-mtu-values.patch
new file mode 100644 (file)
index 0000000..99ad725
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-256879-greg=kroah.com@vger.kernel.org Sat May 30 17:14:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 07:44:06 -0400
+Subject: ice: fix VF queue configuration with low MTU values
+To: stable@vger.kernel.org
+Cc: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>, Jacob Keller <jacob.e.keller@intel.com>, Michal Swiatkowski <michal.swiatkowski@linux.intel.com>, Paul Menzel <pmenzel@molgen.mpg.de>, Rafal Romanowski <rafal.romanowski@intel.com>, Tony Nguyen <anthony.l.nguyen@intel.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530114406.1959724-1-sashal@kernel.org>
+
+From: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
+
+[ 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 <jtornosm@redhat.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Link: https://patch.msgid.link/20260515182419.1597859-3-anthony.l.nguyen@intel.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+@@ -2990,7 +2990,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)) {
+                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                               goto error_param;
+                       }
diff --git a/queue-5.10/ktest-fix-the-month-in-the-name-of-the-failure-directory.patch b/queue-5.10/ktest-fix-the-month-in-the-name-of-the-failure-directory.patch
new file mode 100644 (file)
index 0000000..c473a97
--- /dev/null
@@ -0,0 +1,46 @@
+From stable+bounces-244964-greg=kroah.com@vger.kernel.org Sat May  9 20:52:32 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  9 May 2026 11:22:22 -0400
+Subject: ktest: Fix the month in the name of the failure directory
+To: stable@vger.kernel.org
+Cc: Steven Rostedt <rostedt@goodmis.org>, John 'Warthog9' Hawley <warthog9@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509152222.3511536-2-sashal@kernel.org>
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ Upstream commit 768059ede35f197575a38b10797b52402d9d4d2f ]
+
+The Perl localtime() function returns the month starting at 0 not 1. This
+caused the date produced to create the directory for saving files of a
+failed run to have the month off by one.
+
+  machine-test-useconfig-fail-20260314073628
+
+The above happened in April, not March. The correct name should have been:
+
+  machine-test-useconfig-fail-20260414073628
+
+This was somewhat confusing.
+
+Cc: stable@vger.kernel.org
+Cc: John 'Warthog9' Hawley <warthog9@kernel.org>
+Link: https://patch.msgid.link/20260420142426.33ad0293@fedora
+Fixes: 7faafbd69639b ("ktest: Add open and close console and start stop monitor")
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/ktest/ktest.pl |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -1739,7 +1739,7 @@ sub save_logs {
+     my ($result, $basedir) = @_;
+     my @t = localtime;
+     my $date = sprintf "%04d%02d%02d%02d%02d%02d",
+-      1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
++      1900+$t[5],$t[4]+1,$t[3],$t[2],$t[1],$t[0];
+     my $type = $build_type;
+     if ($type =~ /useconfig/) {
diff --git a/queue-5.10/ktest-fixing-indentation-to-match-expected-pattern.patch b/queue-5.10/ktest-fixing-indentation-to-match-expected-pattern.patch
new file mode 100644 (file)
index 0000000..f9056c3
--- /dev/null
@@ -0,0 +1,372 @@
+From stable+bounces-244963-greg=kroah.com@vger.kernel.org Sat May  9 20:52:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  9 May 2026 11:22:21 -0400
+Subject: ktest: Fixing indentation to match expected pattern
+To: stable@vger.kernel.org
+Cc: "John 'Warthog9' Hawley (VMware)" <warthog9@eaglescrag.net>, "Steven Rostedt (VMware)" <rostedt@goodmis.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509152222.3511536-1-sashal@kernel.org>
+
+From: "John 'Warthog9' Hawley (VMware)" <warthog9@eaglescrag.net>
+
+[ Upstream commit 12d4cddda2043466a5af8fc0c49e49f24f1d4c59 ]
+
+This is a followup to "ktest: Adding editor hints to improve
+consistency" to actually adjust the existing indentation to match
+the, now, expected pattern (first column 4 spaces, 2nd tab, 3rd
+tab + 4 spaces, etc).  This should, at least help, keep things
+consistent going forward now.
+
+Signed-off-by: John 'Warthog9' Hawley (VMware) <warthog9@eaglescrag.net>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 768059ede35f ("ktest: Fix the month in the name of the failure directory")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/ktest/ktest.pl |  188 +++++++++++++++++++++----------------------
+ 1 file changed, 93 insertions(+), 95 deletions(-)
+
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -763,7 +763,7 @@ sub process_variables {
+     # remove the space added in the beginning
+     $retval =~ s/ //;
+-    return "$retval"
++    return "$retval";
+ }
+ sub set_value {
+@@ -1099,7 +1099,7 @@ sub __read_config {
+                   }
+               }
+           }
+-              
++
+           if ( ! -r $file ) {
+               die "$name: $.: Can't read file $file\n$_";
+           }
+@@ -1190,13 +1190,13 @@ sub __read_config {
+ }
+ sub get_test_case {
+-      print "What test case would you like to run?\n";
+-      print " (build, install or boot)\n";
+-      print " Other tests are available but require editing ktest.conf\n";
+-      print " (see tools/testing/ktest/sample.conf)\n";
+-      my $ans = <STDIN>;
+-      chomp $ans;
+-      $default{"TEST_TYPE"} = $ans;
++    print "What test case would you like to run?\n";
++    print " (build, install or boot)\n";
++    print " Other tests are available but require editing ktest.conf\n";
++    print " (see tools/testing/ktest/sample.conf)\n";
++    my $ans = <STDIN>;
++    chomp $ans;
++    $default{"TEST_TYPE"} = $ans;
+ }
+ sub read_config {
+@@ -1545,13 +1545,13 @@ sub dodie {
+           close O;
+           close L;
+       }
+-        send_email("KTEST: critical failure for test $i [$name]",
+-                "Your test started at $script_start_time has failed with:\n@_\n", $log_file);
++      send_email("KTEST: critical failure for test $i [$name]",
++              "Your test started at $script_start_time has failed with:\n@_\n", $log_file);
+     }
+     if ($monitor_cnt) {
+-          # restore terminal settings
+-          system("stty $stty_orig");
++      # restore terminal settings
++      system("stty $stty_orig");
+     }
+     if (defined($post_test)) {
+@@ -1736,81 +1736,81 @@ sub wait_for_monitor {
+ }
+ sub save_logs {
+-      my ($result, $basedir) = @_;
+-      my @t = localtime;
+-      my $date = sprintf "%04d%02d%02d%02d%02d%02d",
+-              1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
++    my ($result, $basedir) = @_;
++    my @t = localtime;
++    my $date = sprintf "%04d%02d%02d%02d%02d%02d",
++      1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
+-      my $type = $build_type;
+-      if ($type =~ /useconfig/) {
+-          $type = "useconfig";
+-      }
++    my $type = $build_type;
++    if ($type =~ /useconfig/) {
++      $type = "useconfig";
++    }
+-      my $dir = "$machine-$test_type-$type-$result-$date";
++    my $dir = "$machine-$test_type-$type-$result-$date";
+-      $dir = "$basedir/$dir";
++    $dir = "$basedir/$dir";
+-      if (!-d $dir) {
+-          mkpath($dir) or
+-              dodie "can't create $dir";
+-      }
++    if (!-d $dir) {
++      mkpath($dir) or
++          dodie "can't create $dir";
++    }
+-      my %files = (
+-              "config" => $output_config,
+-              "buildlog" => $buildlog,
+-              "dmesg" => $dmesg,
+-              "testlog" => $testlog,
+-      );
++    my %files = (
++      "config" => $output_config,
++      "buildlog" => $buildlog,
++      "dmesg" => $dmesg,
++      "testlog" => $testlog,
++    );
+-      while (my ($name, $source) = each(%files)) {
+-              if (-f "$source") {
+-                      cp "$source", "$dir/$name" or
+-                              dodie "failed to copy $source";
+-              }
++    while (my ($name, $source) = each(%files)) {
++      if (-f "$source") {
++          cp "$source", "$dir/$name" or
++              dodie "failed to copy $source";
+       }
++    }
+-      doprint "*** Saved info to $dir ***\n";
++    doprint "*** Saved info to $dir ***\n";
+ }
+ sub fail {
+-      if ($die_on_failure) {
+-              dodie @_;
+-      }
++    if ($die_on_failure) {
++      dodie @_;
++    }
+-      doprint "FAILED\n";
++    doprint "FAILED\n";
+-      my $i = $iteration;
++    my $i = $iteration;
+-      # no need to reboot for just building.
+-      if (!do_not_reboot) {
+-          doprint "REBOOTING\n";
+-          reboot_to_good $sleep_time;
+-      }
++    # no need to reboot for just building.
++    if (!do_not_reboot) {
++      doprint "REBOOTING\n";
++      reboot_to_good $sleep_time;
++    }
+-      my $name = "";
++    my $name = "";
+-      if (defined($test_name)) {
+-          $name = " ($test_name)";
+-      }
++    if (defined($test_name)) {
++      $name = " ($test_name)";
++    }
+-      print_times;
++    print_times;
+-      doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+-      doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+-      doprint "KTEST RESULT: TEST $i$name Failed: ", @_, "\n";
+-      doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+-      doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+-
+-      if (defined($store_failures)) {
+-          save_logs "fail", $store_failures;
+-        }
++    doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
++    doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
++    doprint "KTEST RESULT: TEST $i$name Failed: ", @_, "\n";
++    doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
++    doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+-      if (defined($post_test)) {
+-              run_command $post_test;
+-      }
++    if (defined($store_failures)) {
++      save_logs "fail", $store_failures;
++    }
+-      return 1;
++    if (defined($post_test)) {
++      run_command $post_test;
++    }
++
++    return 1;
+ }
+ sub run_command {
+@@ -2011,9 +2011,9 @@ sub get_grub_index {
+       $skip = '^\s*menuentry\s';
+       $submenu = '^\s*submenu\s';
+     } elsif ($reboot_type eq "grub2bls") {
+-        $command = $grub_bls_get;
+-        $target = '^title=.*' . $grub_menu_qt;
+-        $skip = '^title=';
++      $command = $grub_bls_get;
++      $target = '^title=.*' . $grub_menu_qt;
++      $skip = '^title=';
+     } else {
+       return;
+     }
+@@ -2446,7 +2446,7 @@ sub check_buildlog {
+       while (<IN>) {
+           if (/$check_build_re/) {
+               my $warning = process_warning_line $_;
+-              
++
+               $warnings_list{$warning} = 1;
+           }
+       }
+@@ -2708,7 +2708,7 @@ sub success {
+     doprint     "*******************************************\n";
+     if (defined($store_successes)) {
+-        save_logs "success", $store_successes;
++      save_logs "success", $store_successes;
+     }
+     if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
+@@ -3293,13 +3293,13 @@ sub run_config_bisect {
+     $ret = run_config_bisect_test $config_bisect_type;
+     if ($ret) {
+-        doprint "NEW GOOD CONFIG ($pass)\n";
++      doprint "NEW GOOD CONFIG ($pass)\n";
+       system("cp $output_config $tmpdir/good_config.tmp.$pass");
+       $pass++;
+       # Return 3 for good config
+       return 3;
+     } else {
+-        doprint "NEW BAD CONFIG ($pass)\n";
++      doprint "NEW BAD CONFIG ($pass)\n";
+       system("cp $output_config $tmpdir/bad_config.tmp.$pass");
+       $pass++;
+       # Return 4 for bad config
+@@ -3418,7 +3418,7 @@ sub config_bisect {
+     } while ($ret == 3 || $ret == 4);
+     if ($ret == 2) {
+-        config_bisect_end "$good_config.tmp", "$bad_config.tmp";
++      config_bisect_end "$good_config.tmp", "$bad_config.tmp";
+     }
+     return $ret if ($ret < 0);
+@@ -3598,7 +3598,6 @@ sub read_kconfig {
+     my $cont = 0;
+     my $line;
+-
+     if (! -f $kconfig) {
+       doprint "file $kconfig does not exist, skipping\n";
+       return;
+@@ -3707,7 +3706,7 @@ sub read_depends {
+     if (! -f $kconfig && $arch =~ /\d$/) {
+       my $orig = $arch;
+-      # some subarchs have numbers, truncate them
++      # some subarchs have numbers, truncate them
+       $arch =~ s/\d*$//;
+       $kconfig = "$builddir/arch/$arch/Kconfig";
+       if (! -f $kconfig) {
+@@ -3903,7 +3902,7 @@ sub make_min_config {
+     foreach my $config (@config_keys) {
+       my $kconfig = chomp_config $config;
+       if (!defined $depcount{$kconfig}) {
+-              $depcount{$kconfig} = 0;
++          $depcount{$kconfig} = 0;
+       }
+     }
+@@ -4005,13 +4004,13 @@ sub make_min_config {
+       my $failed = 0;
+       build "oldconfig" or $failed = 1;
+       if (!$failed) {
+-              start_monitor_and_install or $failed = 1;
++          start_monitor_and_install or $failed = 1;
+-              if ($type eq "test" && !$failed) {
+-                  do_run_test or $failed = 1;
+-              }
++          if ($type eq "test" && !$failed) {
++              do_run_test or $failed = 1;
++          }
+-              end_monitor;
++          end_monitor;
+       }
+       $in_bisect = 0;
+@@ -4330,8 +4329,8 @@ sub cancel_test {
+     }
+     if ($email_when_canceled) {
+       my $name = get_test_name;
+-        send_email("KTEST: Your [$name] test was cancelled",
+-                "Your test started at $script_start_time was cancelled: sig int");
++      send_email("KTEST: Your [$name] test was cancelled",
++              "Your test started at $script_start_time was cancelled: sig int");
+     }
+     run_post_ktest;
+     die "\nCaught Sig Int, test interrupted: $!\n"
+@@ -4380,15 +4379,15 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"};
+     # The first test may override the PRE_KTEST option
+     if ($i == 1) {
+-        if (defined($pre_ktest)) {
+-            doprint "\n";
+-            run_command $pre_ktest;
+-        }
+-        if ($email_when_started) {
++      if (defined($pre_ktest)) {
++          doprint "\n";
++          run_command $pre_ktest;
++      }
++      if ($email_when_started) {
+           my $name = get_test_name;
+-            send_email("KTEST: Your [$name] test was started",
+-                "Your test was started on $script_start_time");
+-        }
++          send_email("KTEST: Your [$name] test was started",
++              "Your test was started on $script_start_time");
++      }
+     }
+     # Any test can override the POST_KTEST option
+@@ -4556,12 +4555,11 @@ if ($opt{"POWEROFF_ON_SUCCESS"}) {
+     run_command $switch_to_good;
+ }
+-
+ doprint "\n    $successes of $opt{NUM_TESTS} tests were successful\n\n";
+ if ($email_when_finished) {
+     send_email("KTEST: Your test has finished!",
+-            "$successes of $opt{NUM_TESTS} tests started at $script_start_time were successful!");
++          "$successes of $opt{NUM_TESTS} tests started at $script_start_time were successful!");
+ }
+ if (defined($opt{"LOG_FILE"})) {
diff --git a/queue-5.10/media-rc-igorplugusb-heed-coherency-rules.patch b/queue-5.10/media-rc-igorplugusb-heed-coherency-rules.patch
new file mode 100644 (file)
index 0000000..ee40410
--- /dev/null
@@ -0,0 +1,93 @@
+From stable+bounces-242574-greg=kroah.com@vger.kernel.org Sat May  2 08:08:00 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 22:37:48 -0400
+Subject: media: rc: igorplugusb: heed coherency rules
+To: stable@vger.kernel.org
+Cc: Oliver Neukum <oneukum@suse.com>, Sean Young <sean@mess.org>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260502023748.96270-1-sashal@kernel.org>
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit eac69475b01fe1e861dfe3960b57fa95671c132e ]
+
+In a control request, the USB request structure
+can be subject to DMA on some HCs. Hence it must obey
+the rules for DMA coherency. Allocate it separately.
+
+Fixes: b1c97193c6437 ("[media] rc: port IgorPlug-USB to rc-core")
+Cc: stable@vger.kernel.org
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ replaced kzalloc_obj() with kzalloc(sizeof(*ir->request), GFP_KERNEL) ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/rc/igorplugusb.c |   17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/media/rc/igorplugusb.c
++++ b/drivers/media/rc/igorplugusb.c
+@@ -14,6 +14,7 @@
+ #include <linux/device.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/slab.h>
+ #include <linux/usb.h>
+ #include <linux/usb/input.h>
+ #include <media/rc-core.h>
+@@ -34,7 +35,7 @@ struct igorplugusb {
+       struct device *dev;
+       struct urb *urb;
+-      struct usb_ctrlrequest request;
++      struct usb_ctrlrequest *request;
+       struct timer_list timer;
+@@ -123,7 +124,7 @@ static void igorplugusb_cmd(struct igorp
+ {
+       int ret;
+-      ir->request.bRequest = cmd;
++      ir->request->bRequest = cmd;
+       ir->urb->transfer_flags = 0;
+       ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
+       if (ret)
+@@ -165,13 +166,17 @@ static int igorplugusb_probe(struct usb_
+       if (!ir)
+               return -ENOMEM;
++      ir->request = kzalloc(sizeof(*ir->request), GFP_KERNEL);
++      if (!ir->request)
++              goto fail;
++
+       ir->dev = &intf->dev;
+       timer_setup(&ir->timer, igorplugusb_timer, 0);
+-      ir->request.bRequest = GET_INFRACODE;
+-      ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
+-      ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in));
++      ir->request->bRequest = GET_INFRACODE;
++      ir->request->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
++      ir->request->wLength = cpu_to_le16(sizeof(ir->buf_in));
+       ir->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ir->urb)
+@@ -223,6 +228,7 @@ fail:
+       rc_free_device(ir->rc);
+       usb_free_urb(ir->urb);
+       del_timer(&ir->timer);
++      kfree(ir->request);
+       return ret;
+ }
+@@ -236,6 +242,7 @@ static void igorplugusb_disconnect(struc
+       usb_set_intfdata(intf, NULL);
+       usb_kill_urb(ir->urb);
+       usb_free_urb(ir->urb);
++      kfree(ir->request);
+ }
+ static const struct usb_device_id igorplugusb_table[] = {
diff --git a/queue-5.10/media-rc-ttusbir-respect-dma-coherency-rules.patch b/queue-5.10/media-rc-ttusbir-respect-dma-coherency-rules.patch
new file mode 100644 (file)
index 0000000..6cea595
--- /dev/null
@@ -0,0 +1,83 @@
+From stable+bounces-242482-greg=kroah.com@vger.kernel.org Fri May  1 23:10:33 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  1 May 2026 13:40:21 -0400
+Subject: media: rc: ttusbir: respect DMA coherency rules
+To: stable@vger.kernel.org
+Cc: Oliver Neukum <oneukum@suse.com>, Sean Young <sean@mess.org>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501174021.3858601-1-sashal@kernel.org>
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit 50acaad3d202c064779db8dc3d010007347f59c7 ]
+
+Buffers must not share a cache line with other data structures.
+Allocate separately.
+
+Fixes: 0938069fa0897 ("[media] rc: Add support for the TechnoTrend USB IR Receiver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ kept kzalloc(sizeof(*tt), GFP_KERNEL) instead of kzalloc_obj() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/rc/ttusbir.c |   13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/rc/ttusbir.c
++++ b/drivers/media/rc/ttusbir.c
+@@ -32,7 +32,7 @@ struct ttusbir {
+       struct led_classdev led;
+       struct urb *bulk_urb;
+-      uint8_t bulk_buffer[5];
++      u8 *bulk_buffer;
+       int bulk_out_endp, iso_in_endp;
+       bool led_on, is_led_on;
+       atomic_t led_complete;
+@@ -188,13 +188,16 @@ static int ttusbir_probe(struct usb_inte
+       struct rc_dev *rc;
+       int i, j, ret;
+       int altsetting = -1;
++      u8 *buffer;
+       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
++      buffer = kzalloc(5, GFP_KERNEL);
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+-      if (!tt || !rc) {
++      if (!tt || !rc || buffer) {
+               ret = -ENOMEM;
+               goto out;
+       }
++      tt->bulk_buffer = buffer;
+       /* find the correct alt setting */
+       for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
+@@ -283,8 +286,8 @@ static int ttusbir_probe(struct usb_inte
+       tt->bulk_buffer[3] = 0x01;
+       usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
+-              tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
+-                                              ttusbir_bulk_complete, tt);
++                        tt->bulk_out_endp), tt->bulk_buffer, 5,
++                        ttusbir_bulk_complete, tt);
+       tt->led.name = "ttusbir:green:power";
+       tt->led.default_trigger = "rc-feedback";
+@@ -353,6 +356,7 @@ out:
+               kfree(tt);
+       }
+       rc_free_device(rc);
++      kfree(buffer);
+       return ret;
+ }
+@@ -375,6 +379,7 @@ static void ttusbir_disconnect(struct us
+       }
+       usb_kill_urb(tt->bulk_urb);
+       usb_free_urb(tt->bulk_urb);
++      kfree(tt->bulk_buffer);
+       usb_set_intfdata(intf, NULL);
+       kfree(tt);
+ }
diff --git a/queue-5.10/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch b/queue-5.10/mm-huge_memory-update-file-pmd-counter-before-folio_put.patch
new file mode 100644 (file)
index 0000000..6be0f1a
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-263527-greg=kroah.com@vger.kernel.org Tue Jun 16 08:47:59 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 23:17:12 -0400
+Subject: mm/huge_memory: update file PMD counter before folio_put()
+To: stable@vger.kernel.org
+Cc: Yin Tirui <yintirui@huawei.com>, Lorenzo Stoakes <ljs@kernel.org>, "David Hildenbrand (arm)" <david@kernel.org>, Lance Yang <lance.yang@linux.dev>, Dev Jain <dev.jain@arm.com>, Baolin Wang <baolin.wang@linux.alibaba.com>, Barry Song <baohua@kernel.org>, Chen Jun <chenjun102@huawei.com>, Kefeng Wang <wangkefeng.wang@huawei.com>, "Liam R. Howlett" <liam@infradead.org>, Nico Pache <npache@redhat.com>, Ryan Roberts <ryan.roberts@arm.com>, Vlastimil Babka <vbabka@kernel.org>, Yang Shi <yang.shi@linux.alibaba.com>, Zi Yan <ziy@nvidia.com>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616031712.2780366-1-sashal@kernel.org>
+
+From: Yin Tirui <yintirui@huawei.com>
+
+[ Upstream commit 8d878059924f12c1bc24556a92ec56add74de3c8 ]
+
+__split_huge_pmd_locked() updates the file/shmem RSS counter after
+dropping the PMD mapping's folio reference.  If folio_put() drops the last
+reference, mm_counter_file() can later read freed folio state via
+folio_test_swapbacked().
+
+Move the counter update before folio_put().
+
+Link: https://lore.kernel.org/20260526101337.1984081-1-yintirui@huawei.com
+Fixes: fadae2953072 ("thp: use mm_file_counter to determine update which rss counter")
+Signed-off-by: Yin Tirui <yintirui@huawei.com>
+Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
+Acked-by: David Hildenbrand (arm) <david@kernel.org>
+Reviewed-by: Lance Yang <lance.yang@linux.dev>
+Reviewed-by: Dev Jain <dev.jain@arm.com>
+Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
+Cc: Barry Song <baohua@kernel.org>
+Cc: Chen Jun <chenjun102@huawei.com>
+Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Nico Pache <npache@redhat.com>
+Cc: Ryan Roberts <ryan.roberts@arm.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Cc: Yang Shi <yang.shi@linux.alibaba.com>
+Cc: Zi Yan <ziy@nvidia.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/huge_memory.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2066,7 +2066,9 @@ static void __split_huge_pmd_locked(stru
+                       if (!PageReferenced(page) && pmd_young(old_pmd))
+                               SetPageReferenced(page);
+                       page_remove_rmap(page, true);
++                      add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
+                       put_page(page);
++                      return;
+               }
+               add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
+               return;
diff --git a/queue-5.10/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch b/queue-5.10/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
new file mode 100644 (file)
index 0000000..11d3649
--- /dev/null
@@ -0,0 +1,79 @@
+From stable+bounces-247268-greg=kroah.com@vger.kernel.org Thu May 14 23:28:55 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 13:58:48 -0400
+Subject: mm/hugetlb_cma: round up per_node before logging it
+To: stable@vger.kernel.org
+Cc: Sang-Heon Jeon <ekffu200098@gmail.com>, Muchun Song <muchun.song@linux.dev>, David Hildenbrand <david@kernel.org>, Oscar Salvador <osalvador@suse.de>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514175848.530234-1-sashal@kernel.org>
+
+From: Sang-Heon Jeon <ekffu200098@gmail.com>
+
+[ 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 <ekffu200098@gmail.com>
+Reviewed-by: Muchun Song <muchun.song@linux.dev>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+[ applied the one-line `round_up` to `mm/hugetlb.c` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/hugetlb.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5842,6 +5842,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-5.10/mptcp-do-not-drop-partial-packets.patch b/queue-5.10/mptcp-do-not-drop-partial-packets.patch
new file mode 100644 (file)
index 0000000..c4bb2f4
--- /dev/null
@@ -0,0 +1,77 @@
+From stable+bounces-259295-greg=kroah.com@vger.kernel.org Sun May 31 01:37:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 16:07:11 -0400
+Subject: mptcp: do not drop partial packets
+To: stable@vger.kernel.org
+Cc: Shardul Bankar <shardul.b@mpiricsoftware.com>, Paolo Abeni <pabeni@redhat.com>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530200711.3281969-1-sashal@kernel.org>
+
+From: Shardul Bankar <shardul.b@mpiricsoftware.com>
+
+[ 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 <shardul.b@mpiricsoftware.com>
+[pabeni@redhat.com: update map]
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-1-701e96419f2f@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ dropped `msk->bytes_received += copy_len;` and relocated the `drop:` label to the function end for the existing RCVPRUNED `goto drop;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/protocol.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -314,10 +314,26 @@ 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);
++
++      skb_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-5.10/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch b/queue-5.10/mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
new file mode 100644 (file)
index 0000000..2ea6bf4
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-249415-greg=kroah.com@vger.kernel.org Tue May 19 06:18:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 May 2026 20:46:04 -0400
+Subject: mptcp: pm: ADD_ADDR rtx: fix potential data-race
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Mat Martineau <martineau@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260519004604.1930911-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ 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 <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260505-net-mptcp-pm-fixes-7-1-rc3-v1-3-fca8091060a4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ relocated change from net/mptcp/pm.c to net/mptcp/pm_netlink.c ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -226,6 +226,13 @@ static void mptcp_pm_add_timer(struct ti
+       if (!entry->addr.id)
+               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(msk)) {
+               sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8);
+               goto out;
+@@ -245,6 +252,7 @@ static void mptcp_pm_add_timer(struct ti
+       spin_unlock_bh(&msk->pm.lock);
+ out:
++      bh_unlock_sock(sk);
+       __sock_put(sk);
+ }
diff --git a/queue-5.10/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch b/queue-5.10/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch
new file mode 100644 (file)
index 0000000..d1b2d74
--- /dev/null
@@ -0,0 +1,66 @@
+From stable+bounces-244848-greg=kroah.com@vger.kernel.org Sat May  9 05:29:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 19:59:24 -0400
+Subject: mtd: spi-nor: sst: Fix write enable before AAI sequence
+To: stable@vger.kernel.org
+Cc: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>, Hendrik Donner <hd@os-cillation.de>, "Pratyush Yadav (Google)" <pratyush@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260508235924.2244851-1-sashal@kernel.org>
+
+From: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>
+
+[ Upstream commit a0f64241d3566a49c0a9b33ba7ae458ae22003a9 ]
+
+When writing to SST flash starting at an odd address, a single byte is
+first programmed using the byte program (BP) command. After this
+operation completes, the flash hardware automatically clears the Write
+Enable Latch (WEL) bit.
+
+If an AAI (Auto Address Increment) word program sequence follows, it
+requires WEL to be set. Without re-enabling writes, the AAI sequence
+fails.
+
+Add spi_nor_write_enable() after the odd-address byte program when more
+data needs to be written. Use a local boolean for clarity.
+
+Fixes: b199489d37b2 ("mtd: spi-nor: add the framework for SPI NOR")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>
+Tested-by: Hendrik Donner <hd@os-cillation.de>
+Reviewed-by: Hendrik Donner <hd@os-cillation.de>
+Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org>
+[ kept inline `nor->program_opcode = SPINOR_OP_BP;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/spi-nor/sst.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/mtd/spi-nor/sst.c
++++ b/drivers/mtd/spi-nor/sst.c
+@@ -63,6 +63,8 @@ static int sst_write(struct mtd_info *mt
+       /* Start write from odd address. */
+       if (to % 2) {
++              bool needs_write_enable = (len > 1);
++
+               nor->program_opcode = SPINOR_OP_BP;
+               /* write one byte. */
+@@ -76,6 +78,17 @@ static int sst_write(struct mtd_info *mt
+               to++;
+               actual++;
++
++              /*
++               * Byte program clears the write enable latch. If more
++               * data needs to be written using the AAI sequence,
++               * re-enable writes.
++               */
++              if (needs_write_enable) {
++                      ret = spi_nor_write_enable(nor);
++                      if (ret)
++                              goto out;
++              }
+       }
+       /* Write out most of the data here. */
diff --git a/queue-5.10/net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch b/queue-5.10/net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch
new file mode 100644 (file)
index 0000000..800ba92
--- /dev/null
@@ -0,0 +1,176 @@
+From stable+bounces-243031-greg=kroah.com@vger.kernel.org Mon May  4 18:26:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  4 May 2026 08:56:17 -0400
+Subject: net: bridge: use a stable FDB dst snapshot in RCU readers
+To: stable@vger.kernel.org
+Cc: Zhengchuan Liang <zcliangcn@gmail.com>, stable@kernel.org, Yifan Wu <yifanwucs@gmail.com>, Juefei Pu <tomapufckgml@gmail.com>, Yuan Tan <yuantan098@gmail.com>, Xin Liu <bird@lzu.edu.cn>, Ren Wei <enjou1224z@gmail.com>, Ren Wei <n05ec@lzu.edu.cn>, Ido Schimmel <idosch@nvidia.com>, Nikolay Aleksandrov <razor@blackwall.org>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504125617.2211840-1-sashal@kernel.org>
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit df4601653201de21b487c3e7fffd464790cab808 ]
+
+Local FDB entries can be rewritten in place by `fdb_delete_local()`, which
+updates `f->dst` to another port or to `NULL` while keeping the entry
+alive. Several bridge RCU readers inspect `f->dst`, including
+`br_fdb_fillbuf()` through the `brforward_read()` sysfs path.
+
+These readers currently load `f->dst` multiple times and can therefore
+observe inconsistent values across the check and later dereference.
+In `br_fdb_fillbuf()`, this means a concurrent local-FDB update can change
+`f->dst` after the NULL check and before the `port_no` dereference,
+leading to a NULL-ptr-deref.
+
+Fix this by taking a single `READ_ONCE()` snapshot of `f->dst` in each
+affected RCU reader and using that snapshot for the rest of the access
+sequence. Also publish the in-place `f->dst` updates in `fdb_delete_local()`
+with `WRITE_ONCE()` so the readers and writer use matching access patterns.
+
+Fixes: 960b589f86c7 ("bridge: Properly check if local fdb entry can be deleted in br_fdb_change_mac_address")
+Cc: stable@kernel.org
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/6570fabb85ecadb8baaf019efe856f407711c7b9.1776043229.git.zcliangcn@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ kept combined `BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS` check and `cb->args[2]` instead of `br_is_neigh_suppress_enabled()` helper and `ctx->fdb_idx` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bridge/br_arp_nd_proxy.c |    8 +++++---
+ net/bridge/br_fdb.c          |   28 ++++++++++++++++++----------
+ 2 files changed, 23 insertions(+), 13 deletions(-)
+
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -199,11 +199,12 @@ void br_do_proxy_suppress_arp(struct sk_
+               f = br_fdb_find_rcu(br, n->ha, vid);
+               if (f) {
++                      const struct net_bridge_port *dst = READ_ONCE(f->dst);
+                       bool replied = false;
+                       if ((p && (p->flags & BR_PROXYARP)) ||
+-                          (f->dst && (f->dst->flags & (BR_PROXYARP_WIFI |
+-                                                       BR_NEIGH_SUPPRESS)))) {
++                          (dst && (dst->flags & (BR_PROXYARP_WIFI |
++                                                 BR_NEIGH_SUPPRESS)))) {
+                               if (!vid)
+                                       br_arp_send(br, p, skb->dev, sip, tip,
+                                                   sha, n->ha, sha, 0, 0);
+@@ -463,9 +464,10 @@ void br_do_suppress_nd(struct sk_buff *s
+               f = br_fdb_find_rcu(br, n->ha, vid);
+               if (f) {
++                      const struct net_bridge_port *dst = READ_ONCE(f->dst);
+                       bool replied = false;
+-                      if (f->dst && (f->dst->flags & BR_NEIGH_SUPPRESS)) {
++                      if (dst && (dst->flags & BR_NEIGH_SUPPRESS)) {
+                               if (vid != 0)
+                                       br_nd_send(br, p, skb, n,
+                                                  skb->vlan_proto,
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -121,6 +121,7 @@ struct net_device *br_fdb_find_port(cons
+                                   const unsigned char *addr,
+                                   __u16 vid)
+ {
++      const struct net_bridge_port *dst;
+       struct net_bridge_fdb_entry *f;
+       struct net_device *dev = NULL;
+       struct net_bridge *br;
+@@ -133,8 +134,11 @@ struct net_device *br_fdb_find_port(cons
+       br = netdev_priv(br_dev);
+       rcu_read_lock();
+       f = br_fdb_find_rcu(br, addr, vid);
+-      if (f && f->dst)
+-              dev = f->dst->dev;
++      if (f) {
++              dst = READ_ONCE(f->dst);
++              if (dst)
++                      dev = dst->dev;
++      }
+       rcu_read_unlock();
+       return dev;
+@@ -224,7 +228,7 @@ static void fdb_delete_local(struct net_
+               vg = nbp_vlan_group(op);
+               if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
+                   (!vid || br_vlan_find(vg, vid))) {
+-                      f->dst = op;
++                      WRITE_ONCE(f->dst, op);
+                       clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
+                       return;
+               }
+@@ -235,7 +239,7 @@ static void fdb_delete_local(struct net_
+       /* Maybe bridge device has same hw addr? */
+       if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
+           (!vid || (v && br_vlan_should_use(v)))) {
+-              f->dst = NULL;
++              WRITE_ONCE(f->dst, NULL);
+               clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
+               return;
+       }
+@@ -457,6 +461,7 @@ int br_fdb_test_addr(struct net_device *
+ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
+                  unsigned long maxnum, unsigned long skip)
+ {
++      const struct net_bridge_port *dst;
+       struct net_bridge_fdb_entry *f;
+       struct __fdb_entry *fe = buf;
+       int num = 0;
+@@ -472,7 +477,8 @@ int br_fdb_fillbuf(struct net_bridge *br
+                       continue;
+               /* ignore pseudo entry for local MAC address */
+-              if (!f->dst)
++              dst = READ_ONCE(f->dst);
++              if (!dst)
+                       continue;
+               if (skip) {
+@@ -484,8 +490,8 @@ int br_fdb_fillbuf(struct net_bridge *br
+               memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
+               /* due to ABI compat need to split into hi/lo */
+-              fe->port_no = f->dst->port_no;
+-              fe->port_hi = f->dst->port_no >> 8;
++              fe->port_no = dst->port_no;
++              fe->port_hi = dst->port_no >> 8;
+               fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
+               if (!test_bit(BR_FDB_STATIC, &f->flags))
+@@ -775,9 +781,11 @@ int br_fdb_dump(struct sk_buff *skb,
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
++              const struct net_bridge_port *dst = READ_ONCE(f->dst);
++
+               if (*idx < cb->args[2])
+                       goto skip;
+-              if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
++              if (filter_dev && (!dst || dst->dev != filter_dev)) {
+                       if (filter_dev != dev)
+                               goto skip;
+                       /* !f->dst is a special case for bridge
+@@ -785,10 +793,10 @@ int br_fdb_dump(struct sk_buff *skb,
+                        * Therefore need a little more filtering
+                        * we only want to dump the !f->dst case
+                        */
+-                      if (f->dst)
++                      if (dst)
+                               goto skip;
+               }
+-              if (!filter_dev && f->dst)
++              if (!filter_dev && dst)
+                       goto skip;
+               err = fdb_fill_info(skb, br, f,
diff --git a/queue-5.10/net-hsr-defer-node-table-free-until-after-rcu-readers.patch b/queue-5.10/net-hsr-defer-node-table-free-until-after-rcu-readers.patch
new file mode 100644 (file)
index 0000000..99ff9ea
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-256839-greg=kroah.com@vger.kernel.org Sat May 30 05:53:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 20:20:41 -0400
+Subject: net: hsr: defer node table free until after RCU readers
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530002041.2171280-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ 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 <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260513233838.3064715-2-michael.bommarito@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ replaced `list_del`+`call_rcu(hsr_free_node_rcu)` with `list_del_rcu`+`kfree_rcu(node, rcu_head)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -123,8 +123,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-5.10/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch b/queue-5.10/net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch
new file mode 100644 (file)
index 0000000..22613f8
--- /dev/null
@@ -0,0 +1,96 @@
+From stable+bounces-241121-greg=kroah.com@vger.kernel.org Sat Apr 25 15:37:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Apr 2026 06:07:11 -0400
+Subject: net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
+To: stable@vger.kernel.org
+Cc: Bingquan Chen <patzilla007@gmail.com>, Willem de Bruijn <willemb@google.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260425100711.3493958-1-sashal@kernel.org>
+
+From: Bingquan Chen <patzilla007@gmail.com>
+
+[ Upstream commit 2c054e17d9d41f1020376806c7f750834ced4dc5 ]
+
+In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points
+directly into the mmap'd TX ring buffer shared with userspace. The
+kernel validates the header via __packet_snd_vnet_parse() but then
+re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent
+userspace thread can modify the vnet_hdr fields between validation
+and use, bypassing all safety checks.
+
+The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr
+to a stack-local variable. All other vnet_hdr consumers in the kernel
+(tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX
+path is the only caller of virtio_net_hdr_to_skb() that reads directly
+from user-controlled shared memory.
+
+Fix this by copying vnet_hdr from the mmap'd ring buffer to a
+stack-local variable before validation and use, consistent with the
+approach used in packet_snd() and all other callers.
+
+Fixes: 1d036d25e560 ("packet: tpacket_snd gso and checksum offload")
+Signed-off-by: Bingquan Chen <patzilla007@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260418112006.78823-1-patzilla007@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ replaced `vnet_hdr_sz` with `sizeof(vnet_hdr)` and `if (vnet_hdr_sz)` with `if (po->has_vnet_hdr)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/packet/af_packet.c |   25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -2726,7 +2726,8 @@ static int tpacket_snd(struct packet_soc
+ {
+       struct sk_buff *skb = NULL;
+       struct net_device *dev;
+-      struct virtio_net_hdr *vnet_hdr = NULL;
++      struct virtio_net_hdr vnet_hdr;
++      bool has_vnet_hdr = false;
+       struct sockcm_cookie sockc;
+       __be16 proto;
+       int err, reserve = 0;
+@@ -2826,16 +2827,20 @@ static int tpacket_snd(struct packet_soc
+               hlen = LL_RESERVED_SPACE(dev);
+               tlen = dev->needed_tailroom;
+               if (po->has_vnet_hdr) {
+-                      vnet_hdr = data;
+-                      data += sizeof(*vnet_hdr);
+-                      tp_len -= sizeof(*vnet_hdr);
+-                      if (tp_len < 0 ||
+-                          __packet_snd_vnet_parse(vnet_hdr, tp_len)) {
++                      data += sizeof(vnet_hdr);
++                      tp_len -= sizeof(vnet_hdr);
++                      if (tp_len < 0) {
++                              tp_len = -EINVAL;
++                              goto tpacket_error;
++                      }
++                      memcpy(&vnet_hdr, data - sizeof(vnet_hdr), sizeof(vnet_hdr));
++                      if (__packet_snd_vnet_parse(&vnet_hdr, tp_len)) {
+                               tp_len = -EINVAL;
+                               goto tpacket_error;
+                       }
+                       copylen = __virtio16_to_cpu(vio_le(),
+-                                                  vnet_hdr->hdr_len);
++                                                  vnet_hdr.hdr_len);
++                      has_vnet_hdr = true;
+               }
+               copylen = max_t(int, copylen, dev->hard_header_len);
+               skb = sock_alloc_send_skb(&po->sk,
+@@ -2872,12 +2877,12 @@ tpacket_error:
+                       }
+               }
+-              if (po->has_vnet_hdr) {
+-                      if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) {
++              if (has_vnet_hdr) {
++                      if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le())) {
+                               tp_len = -EINVAL;
+                               goto tpacket_error;
+                       }
+-                      virtio_net_hdr_set_proto(skb, vnet_hdr);
++                      virtio_net_hdr_set_proto(skb, &vnet_hdr);
+               }
+               skb->destructor = tpacket_destruct_skb;
diff --git a/queue-5.10/net-qrtr-ns-change-servers-radix-tree-to-xarray.patch b/queue-5.10/net-qrtr-ns-change-servers-radix-tree-to-xarray.patch
new file mode 100644 (file)
index 0000000..5aaab42
--- /dev/null
@@ -0,0 +1,310 @@
+From stable+bounces-242842-greg=kroah.com@vger.kernel.org Mon May  4 11:18:02 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  4 May 2026 01:47:51 -0400
+Subject: net: qrtr: ns: Change servers radix tree to xarray
+To: stable@vger.kernel.org
+Cc: Vignesh Viswanathan <quic_viswanat@quicinc.com>, Chris Lew <quic_clew@quicinc.com>, Simon Horman <simon.horman@corigine.com>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504054752.1775840-1-sashal@kernel.org>
+
+From: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+
+[ Upstream commit 608a147a88728f84bbd2efdde3d4984339f1d872 ]
+
+There is a use after free scenario while iterating through the servers
+radix tree despite the ns being a single threaded process. This can
+happen when the radix tree APIs are not synchronized with the
+rcu_read_lock() APIs.
+
+Convert the radix tree for servers to xarray to take advantage of the
+built in rcu lock usage provided by xarray.
+
+Signed-off-by: Chris Lew <quic_clew@quicinc.com>
+Signed-off-by: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 68efba36446a ("net: qrtr: ns: Free the node during ctrl_cmd_bye()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c |  133 ++++++++++------------------------------------------------
+ 1 file changed, 24 insertions(+), 109 deletions(-)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -67,7 +67,7 @@ struct qrtr_server {
+ struct qrtr_node {
+       unsigned int id;
+-      struct radix_tree_root servers;
++      struct xarray servers;
+ };
+ /* Max lookup limit is chosen based on the current platform requirements. If the
+@@ -89,6 +89,7 @@ static struct qrtr_node *node_get(unsign
+               return NULL;
+       node->id = node_id;
++      xa_init(&node->servers);
+       if (radix_tree_insert(&nodes, node_id, node)) {
+               kfree(node);
+@@ -199,40 +200,23 @@ static void lookup_notify(struct sockadd
+ static int announce_servers(struct sockaddr_qrtr *sq)
+ {
+-      struct radix_tree_iter iter;
+       struct qrtr_server *srv;
+       struct qrtr_node *node;
+-      void __rcu **slot;
++      unsigned long index;
+       int ret;
+       node = node_get(qrtr_ns.local_node);
+       if (!node)
+               return 0;
+-      rcu_read_lock();
+       /* Announce the list of servers registered in this node */
+-      radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+-              srv = radix_tree_deref_slot(slot);
+-              if (!srv)
+-                      continue;
+-              if (radix_tree_deref_retry(srv)) {
+-                      slot = radix_tree_iter_retry(&iter);
+-                      continue;
+-              }
+-              slot = radix_tree_iter_resume(slot, &iter);
+-              rcu_read_unlock();
+-
++      xa_for_each(&node->servers, index, srv) {
+               ret = service_announce_new(sq, srv);
+               if (ret < 0) {
+                       pr_err("failed to announce new service\n");
+                       return ret;
+               }
+-
+-              rcu_read_lock();
+       }
+-
+-      rcu_read_unlock();
+-
+       return 0;
+ }
+@@ -262,14 +246,17 @@ static struct qrtr_server *server_add(un
+               goto err;
+       /* Delete the old server on the same port */
+-      old = radix_tree_lookup(&node->servers, port);
++      old = xa_store(&node->servers, port, srv, GFP_KERNEL);
+       if (old) {
+-              radix_tree_delete(&node->servers, port);
+-              kfree(old);
++              if (xa_is_err(old)) {
++                      pr_err("failed to add server [0x%x:0x%x] ret:%d\n",
++                             srv->service, srv->instance, xa_err(old));
++                      goto err;
++              } else {
++                      kfree(old);
++              }
+       }
+-      radix_tree_insert(&node->servers, port, srv);
+-
+       trace_qrtr_ns_server_add(srv->service, srv->instance,
+                                srv->node, srv->port);
+@@ -286,11 +273,11 @@ static int server_del(struct qrtr_node *
+       struct qrtr_server *srv;
+       struct list_head *li;
+-      srv = radix_tree_lookup(&node->servers, port);
++      srv = xa_load(&node->servers, port);
+       if (!srv)
+               return -ENOENT;
+-      radix_tree_delete(&node->servers, port);
++      xa_erase(&node->servers, port);
+       /* Broadcast the removal of local servers */
+       if (srv->node == qrtr_ns.local_node && bcast)
+@@ -350,13 +337,12 @@ static int ctrl_cmd_hello(struct sockadd
+ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ {
+       struct qrtr_node *local_node;
+-      struct radix_tree_iter iter;
+       struct qrtr_ctrl_pkt pkt;
+       struct qrtr_server *srv;
+       struct sockaddr_qrtr sq;
+       struct msghdr msg = { };
+       struct qrtr_node *node;
+-      void __rcu **slot;
++      unsigned long index;
+       struct kvec iv;
+       int ret;
+@@ -367,22 +353,9 @@ static int ctrl_cmd_bye(struct sockaddr_
+       if (!node)
+               return 0;
+-      rcu_read_lock();
+       /* Advertise removal of this client to all servers of remote node */
+-      radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+-              srv = radix_tree_deref_slot(slot);
+-              if (!srv)
+-                      continue;
+-              if (radix_tree_deref_retry(srv)) {
+-                      slot = radix_tree_iter_retry(&iter);
+-                      continue;
+-              }
+-              slot = radix_tree_iter_resume(slot, &iter);
+-              rcu_read_unlock();
++      xa_for_each(&node->servers, index, srv)
+               server_del(node, srv->port, true);
+-              rcu_read_lock();
+-      }
+-      rcu_read_unlock();
+       /* Advertise the removal of this client to all local servers */
+       local_node = node_get(qrtr_ns.local_node);
+@@ -393,18 +366,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+       pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
+       pkt.client.node = cpu_to_le32(from->sq_node);
+-      rcu_read_lock();
+-      radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+-              srv = radix_tree_deref_slot(slot);
+-              if (!srv)
+-                      continue;
+-              if (radix_tree_deref_retry(srv)) {
+-                      slot = radix_tree_iter_retry(&iter);
+-                      continue;
+-              }
+-              slot = radix_tree_iter_resume(slot, &iter);
+-              rcu_read_unlock();
+-
++      xa_for_each(&local_node->servers, index, srv) {
+               sq.sq_family = AF_QIPCRTR;
+               sq.sq_node = srv->node;
+               sq.sq_port = srv->port;
+@@ -417,11 +379,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+                       pr_err("failed to send bye cmd\n");
+                       return ret;
+               }
+-              rcu_read_lock();
+       }
+-
+-      rcu_read_unlock();
+-
+       return 0;
+ }
+@@ -429,7 +387,6 @@ static int ctrl_cmd_del_client(struct so
+                              unsigned int node_id, unsigned int port)
+ {
+       struct qrtr_node *local_node;
+-      struct radix_tree_iter iter;
+       struct qrtr_lookup *lookup;
+       struct qrtr_ctrl_pkt pkt;
+       struct msghdr msg = { };
+@@ -438,7 +395,7 @@ static int ctrl_cmd_del_client(struct so
+       struct qrtr_node *node;
+       struct list_head *tmp;
+       struct list_head *li;
+-      void __rcu **slot;
++      unsigned long index;
+       struct kvec iv;
+       int ret;
+@@ -484,18 +441,7 @@ static int ctrl_cmd_del_client(struct so
+       pkt.client.node = cpu_to_le32(node_id);
+       pkt.client.port = cpu_to_le32(port);
+-      rcu_read_lock();
+-      radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+-              srv = radix_tree_deref_slot(slot);
+-              if (!srv)
+-                      continue;
+-              if (radix_tree_deref_retry(srv)) {
+-                      slot = radix_tree_iter_retry(&iter);
+-                      continue;
+-              }
+-              slot = radix_tree_iter_resume(slot, &iter);
+-              rcu_read_unlock();
+-
++      xa_for_each(&local_node->servers, index, srv) {
+               sq.sq_family = AF_QIPCRTR;
+               sq.sq_node = srv->node;
+               sq.sq_port = srv->port;
+@@ -508,11 +454,7 @@ static int ctrl_cmd_del_client(struct so
+                       pr_err("failed to send del client cmd\n");
+                       return ret;
+               }
+-              rcu_read_lock();
+       }
+-
+-      rcu_read_unlock();
+-
+       return 0;
+ }
+@@ -593,13 +535,12 @@ static int ctrl_cmd_del_server(struct so
+ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
+                              unsigned int service, unsigned int instance)
+ {
+-      struct radix_tree_iter node_iter;
+       struct qrtr_server_filter filter;
+-      struct radix_tree_iter srv_iter;
+       struct qrtr_lookup *lookup;
++      struct qrtr_server *srv;
+       struct qrtr_node *node;
+-      void __rcu **node_slot;
+-      void __rcu **srv_slot;
++      unsigned long node_idx;
++      unsigned long srv_idx;
+       /* Accept only local observers */
+       if (from->sq_node != qrtr_ns.local_node)
+@@ -624,40 +565,14 @@ static int ctrl_cmd_new_lookup(struct so
+       filter.service = service;
+       filter.instance = instance;
+-      rcu_read_lock();
+-      radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
+-              node = radix_tree_deref_slot(node_slot);
+-              if (!node)
+-                      continue;
+-              if (radix_tree_deref_retry(node)) {
+-                      node_slot = radix_tree_iter_retry(&node_iter);
+-                      continue;
+-              }
+-              node_slot = radix_tree_iter_resume(node_slot, &node_iter);
+-
+-              radix_tree_for_each_slot(srv_slot, &node->servers,
+-                                       &srv_iter, 0) {
+-                      struct qrtr_server *srv;
+-
+-                      srv = radix_tree_deref_slot(srv_slot);
+-                      if (!srv)
+-                              continue;
+-                      if (radix_tree_deref_retry(srv)) {
+-                              srv_slot = radix_tree_iter_retry(&srv_iter);
+-                              continue;
+-                      }
+-
++      xa_for_each(&nodes, node_idx, node) {
++              xa_for_each(&node->servers, srv_idx, srv) {
+                       if (!server_match(srv, &filter))
+                               continue;
+-                      srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
+-
+-                      rcu_read_unlock();
+                       lookup_notify(from, srv, true);
+-                      rcu_read_lock();
+               }
+       }
+-      rcu_read_unlock();
+       /* Empty notification, to indicate end of listing */
+       lookup_notify(from, NULL, true);
diff --git a/queue-5.10/net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch b/queue-5.10/net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch
new file mode 100644 (file)
index 0000000..fed6f5e
--- /dev/null
@@ -0,0 +1,77 @@
+From stable+bounces-242843-greg=kroah.com@vger.kernel.org Mon May  4 11:18:03 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  4 May 2026 01:47:52 -0400
+Subject: net: qrtr: ns: Free the node during ctrl_cmd_bye()
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504054752.1775840-2-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 68efba36446a7774ea5b971257ade049272a07ac ]
+
+A node sends the BYE packet when it is about to go down. So the nameserver
+should advertise the removal of the node to all remote and local observers
+and free the node finally. But currently, the nameserver doesn't free the
+node memory even after processing the BYE packet. This causes the node
+memory to leak.
+
+Hence, remove the node from Xarray list and free the node memory during
+both success and failure case of ctrl_cmd_bye().
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-3-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c |   20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -344,7 +344,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+       struct qrtr_node *node;
+       unsigned long index;
+       struct kvec iv;
+-      int ret;
++      int ret = 0;
+       iv.iov_base = &pkt;
+       iv.iov_len = sizeof(pkt);
+@@ -359,8 +359,10 @@ static int ctrl_cmd_bye(struct sockaddr_
+       /* Advertise the removal of this client to all local servers */
+       local_node = node_get(qrtr_ns.local_node);
+-      if (!local_node)
+-              return 0;
++      if (!local_node) {
++              ret = 0;
++              goto delete_node;
++      }
+       memset(&pkt, 0, sizeof(pkt));
+       pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
+@@ -377,10 +379,18 @@ static int ctrl_cmd_bye(struct sockaddr_
+               ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
+               if (ret < 0) {
+                       pr_err("failed to send bye cmd\n");
+-                      return ret;
++                      goto delete_node;
+               }
+       }
+-      return 0;
++
++      /* Ignore -ENODEV */
++      ret = 0;
++
++delete_node:
++      xa_erase(&nodes, from->sq_node);
++      kfree(node);
++
++      return ret;
+ }
+ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
diff --git a/queue-5.10/net-qrtr-ns-limit-the-maximum-number-of-lookups.patch b/queue-5.10/net-qrtr-ns-limit-the-maximum-number-of-lookups.patch
new file mode 100644 (file)
index 0000000..1c72b90
--- /dev/null
@@ -0,0 +1,95 @@
+From stable+bounces-242837-greg=kroah.com@vger.kernel.org Mon May  4 10:49:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  4 May 2026 01:19:12 -0400
+Subject: net: qrtr: ns: Limit the maximum number of lookups
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504051912.1723447-1-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 5640227d9a21c6a8be249a10677b832e7f40dc55 ]
+
+Current code does no bound checking on the number of lookups a client can
+perform. Though the code restricts the lookups to local clients, there is
+still a possibility of a malicious local client sending a flood of
+NEW_LOOKUP messages over the same socket.
+
+Fix this issue by limiting the maximum number of lookups to 64 globally.
+Since the nameserver allows only atmost one local observer, this global
+lookup count will ensure that the lookups stay within the limit.
+
+Note that, limit of 64 is chosen based on the current platform
+requirements. If requirement changes in the future, this limit can be
+increased.
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-2-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ adapted comment block to only mention QRTR_NS_MAX_LOOKUPS and kept kzalloc() instead of kzalloc_obj() due to missing prerequisite commits ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -21,6 +21,7 @@ static struct {
+       struct socket *sock;
+       struct sockaddr_qrtr bcast_sq;
+       struct list_head lookups;
++      u32 lookup_count;
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+       void (*saved_data_ready)(struct sock *sk);
+@@ -69,6 +70,11 @@ struct qrtr_node {
+       struct radix_tree_root servers;
+ };
++/* Max lookup limit is chosen based on the current platform requirements. If the
++ * requirement changes in the future, this value can be increased.
++ */
++#define QRTR_NS_MAX_LOOKUPS 64
++
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+       struct qrtr_node *node;
+@@ -457,6 +463,7 @@ static int ctrl_cmd_del_client(struct so
+               list_del(&lookup->li);
+               kfree(lookup);
++              qrtr_ns.lookup_count--;
+       }
+       /* Remove the server belonging to this port but don't broadcast
+@@ -598,6 +605,11 @@ static int ctrl_cmd_new_lookup(struct so
+       if (from->sq_node != qrtr_ns.local_node)
+               return -EINVAL;
++      if (qrtr_ns.lookup_count >= QRTR_NS_MAX_LOOKUPS) {
++              pr_err_ratelimited("QRTR client node exceeds max lookup limit!\n");
++              return -ENOSPC;
++      }
++
+       lookup = kzalloc(sizeof(*lookup), GFP_KERNEL);
+       if (!lookup)
+               return -ENOMEM;
+@@ -606,6 +618,7 @@ static int ctrl_cmd_new_lookup(struct so
+       lookup->service = service;
+       lookup->instance = instance;
+       list_add_tail(&lookup->li, &qrtr_ns.lookups);
++      qrtr_ns.lookup_count++;
+       memset(&filter, 0, sizeof(filter));
+       filter.service = service;
+@@ -672,6 +685,7 @@ static void ctrl_cmd_del_lookup(struct s
+               list_del(&lookup->li);
+               kfree(lookup);
++              qrtr_ns.lookup_count--;
+       }
+ }
diff --git a/queue-5.10/net-qrtr-ns-limit-the-total-number-of-nodes.patch b/queue-5.10/net-qrtr-ns-limit-the-total-number-of-nodes.patch
new file mode 100644 (file)
index 0000000..dc16936
--- /dev/null
@@ -0,0 +1,72 @@
+From stable+bounces-242997-greg=kroah.com@vger.kernel.org Mon May  4 17:02:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  4 May 2026 07:32:41 -0400
+Subject: net: qrtr: ns: Limit the total number of nodes
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504113241.2090164-1-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 27d5e84e810b0849d08b9aec68e48570461ce313 ]
+
+Currently, the nameserver doesn't limit the number of nodes it handles.
+This can be an attack vector if a malicious client starts registering
+random nodes, leading to memory exhaustion.
+
+Hence, limit the maximum number of nodes to 64. Note that, limit of 64 is
+chosen based on the current platform requirements. If requirement changes
+in the future, this limit can be increased.
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-4-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ dropped node_count-- hunk since ctrl_cmd_bye() has no delete_node ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c |   17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -75,6 +75,16 @@ struct qrtr_node {
+  */
+ #define QRTR_NS_MAX_LOOKUPS 64
++/* Max nodes, server, lookup limits are chosen based on the current platform
++ * requirements. If the requirement changes in the future, these values can be
++ * increased.
++ */
++#define QRTR_NS_MAX_NODES   64
++#define QRTR_NS_MAX_SERVERS 256
++#define QRTR_NS_MAX_LOOKUPS 64
++
++static u8 node_count;
++
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+       struct qrtr_node *node;
+@@ -83,6 +93,11 @@ static struct qrtr_node *node_get(unsign
+       if (node)
+               return node;
++      if (node_count >= QRTR_NS_MAX_NODES) {
++              pr_err_ratelimited("QRTR clients exceed max node limit!\n");
++              return NULL;
++      }
++
+       /* If node didn't exist, allocate and insert it to the tree */
+       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       if (!node)
+@@ -96,6 +111,8 @@ static struct qrtr_node *node_get(unsign
+               return NULL;
+       }
++      node_count++;
++
+       return node;
+ }
diff --git a/queue-5.10/net-remove-redundant-if-statements.patch b/queue-5.10/net-remove-redundant-if-statements.patch
new file mode 100644 (file)
index 0000000..3494838
--- /dev/null
@@ -0,0 +1,752 @@
+From stable+bounces-256828-greg=kroah.com@vger.kernel.org Sat May 30 05:19:52 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:49:41 -0400
+Subject: net: Remove redundant if statements
+To: stable@vger.kernel.org
+Cc: Yajun Deng <yajun.deng@linux.dev>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529234942.1939638-1-sashal@kernel.org>
+
+From: Yajun Deng <yajun.deng@linux.dev>
+
+[ Upstream commit 1160dfa178eb848327e9dec39960a735f4dc1685 ]
+
+The 'if (dev)' statement already move into dev_{put , hold}, so remove
+redundant if statements.
+
+Signed-off-by: Yajun Deng <yajun.deng@linux.dev>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: e196115ec330 ("netfilter: nf_queue: hold bridge skb->dev while queued")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/batman-adv/bridge_loop_avoidance.c |    6 ++----
+ net/batman-adv/distributed-arp-table.c |    3 +--
+ net/batman-adv/gateway_client.c        |    3 +--
+ net/batman-adv/multicast.c             |    9 +++------
+ net/batman-adv/originator.c            |   12 ++++--------
+ net/batman-adv/translation-table.c     |    9 +++------
+ net/can/raw.c                          |    8 ++------
+ net/core/dev.c                         |    6 ++----
+ net/core/drop_monitor.c                |    6 ++----
+ net/core/dst.c                         |    6 ++----
+ net/core/neighbour.c                   |   15 +++++----------
+ net/ethtool/netlink.c                  |    6 ++----
+ net/ieee802154/nl-phy.c                |    3 +--
+ net/ieee802154/nl802154.c              |    3 +--
+ net/ieee802154/socket.c                |    3 +--
+ net/ipv4/fib_semantics.c               |    4 +---
+ net/ipv4/route.c                       |    3 +--
+ net/ipv6/addrconf.c                    |    6 ++----
+ net/ipv6/ip6mr.c                       |    3 +--
+ net/ipv6/route.c                       |    3 +--
+ net/netfilter/nf_queue.c               |   24 ++++++++----------------
+ net/netlabel/netlabel_unlabeled.c      |    6 ++----
+ net/netrom/nr_loopback.c               |    3 +--
+ net/netrom/nr_route.c                  |    3 +--
+ net/packet/af_packet.c                 |   15 +++++----------
+ net/phonet/af_phonet.c                 |    3 +--
+ net/phonet/pn_dev.c                    |    6 ++----
+ net/phonet/socket.c                    |    3 +--
+ net/sched/act_mirred.c                 |    6 ++----
+ net/smc/smc_pnet.c                     |    3 +--
+ net/wireless/nl80211.c                 |   16 +++++-----------
+ net/wireless/scan.c                    |    3 +--
+ 32 files changed, 68 insertions(+), 140 deletions(-)
+
+--- a/net/batman-adv/bridge_loop_avoidance.c
++++ b/net/batman-adv/bridge_loop_avoidance.c
+@@ -2402,8 +2402,7 @@ out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+@@ -2640,8 +2639,7 @@ out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+--- a/net/batman-adv/distributed-arp-table.c
++++ b/net/batman-adv/distributed-arp-table.c
+@@ -1045,8 +1045,7 @@ out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+--- a/net/batman-adv/gateway_client.c
++++ b/net/batman-adv/gateway_client.c
+@@ -590,8 +590,7 @@ int batadv_gw_dump(struct sk_buff *msg,
+ out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+--- a/net/batman-adv/multicast.c
++++ b/net/batman-adv/multicast.c
+@@ -92,8 +92,7 @@ static struct net_device *batadv_mcast_g
+               upper = netdev_master_upper_dev_get_rcu(upper);
+       } while (upper && !(upper->priv_flags & IFF_EBRIDGE));
+-      if (upper)
+-              dev_hold(upper);
++      dev_hold(upper);
+       rcu_read_unlock();
+       return upper;
+@@ -541,8 +540,7 @@ batadv_mcast_mla_softif_get(struct net_d
+       }
+ out:
+-      if (bridge)
+-              dev_put(bridge);
++      dev_put(bridge);
+       return ret4 + ret6;
+ }
+@@ -2386,8 +2384,7 @@ batadv_mcast_netlink_get_primary(struct
+       }
+ out:
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       if (!ret && primary_if)
+               *primary_if = hard_iface;
+--- a/net/batman-adv/originator.c
++++ b/net/batman-adv/originator.c
+@@ -823,12 +823,10 @@ int batadv_hardif_neigh_dump(struct sk_b
+  out:
+       if (hardif)
+               batadv_hardif_put(hardif);
+-      if (hard_iface)
+-              dev_put(hard_iface);
++      dev_put(hard_iface);
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+@@ -1502,12 +1500,10 @@ int batadv_orig_dump(struct sk_buff *msg
+  out:
+       if (hardif)
+               batadv_hardif_put(hardif);
+-      if (hard_iface)
+-              dev_put(hard_iface);
++      dev_put(hard_iface);
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       return ret;
+ }
+--- a/net/batman-adv/translation-table.c
++++ b/net/batman-adv/translation-table.c
+@@ -815,8 +815,7 @@ check_roaming:
+ out:
+       if (in_hardif)
+               batadv_hardif_put(in_hardif);
+-      if (in_dev)
+-              dev_put(in_dev);
++      dev_put(in_dev);
+       if (tt_local)
+               batadv_tt_local_entry_put(tt_local);
+       if (tt_global)
+@@ -1331,8 +1330,7 @@ int batadv_tt_local_dump(struct sk_buff
+  out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       cb->args[0] = bucket;
+       cb->args[1] = idx;
+@@ -2252,8 +2250,7 @@ int batadv_tt_global_dump(struct sk_buff
+  out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+-      if (soft_iface)
+-              dev_put(soft_iface);
++      dev_put(soft_iface);
+       cb->args[0] = bucket;
+       cb->args[1] = idx;
+--- a/net/can/raw.c
++++ b/net/can/raw.c
+@@ -601,9 +601,7 @@ static int raw_setsockopt(struct socket
+               ro->count  = count;
+  out_fil:
+-              if (dev)
+-                      dev_put(dev);
+-
++              dev_put(dev);
+               release_sock(sk);
+               rtnl_unlock();
+@@ -647,9 +645,7 @@ static int raw_setsockopt(struct socket
+               ro->err_mask = err_mask;
+  out_err:
+-              if (dev)
+-                      dev_put(dev);
+-
++              dev_put(dev);
+               release_sock(sk);
+               rtnl_unlock();
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -906,8 +906,7 @@ struct net_device *dev_get_by_name(struc
+       rcu_read_lock();
+       dev = dev_get_by_name_rcu(net, name);
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       rcu_read_unlock();
+       return dev;
+ }
+@@ -980,8 +979,7 @@ struct net_device *dev_get_by_index(stru
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, ifindex);
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       rcu_read_unlock();
+       return dev;
+ }
+--- a/net/core/drop_monitor.c
++++ b/net/core/drop_monitor.c
+@@ -854,8 +854,7 @@ net_dm_hw_metadata_copy(const struct dev
+       }
+       hw_metadata->input_dev = metadata->input_dev;
+-      if (hw_metadata->input_dev)
+-              dev_hold(hw_metadata->input_dev);
++      dev_hold(hw_metadata->input_dev);
+       return hw_metadata;
+@@ -871,8 +870,7 @@ free_hw_metadata:
+ static void
+ net_dm_hw_metadata_free(const struct devlink_trap_metadata *hw_metadata)
+ {
+-      if (hw_metadata->input_dev)
+-              dev_put(hw_metadata->input_dev);
++      dev_put(hw_metadata->input_dev);
+       kfree(hw_metadata->fa_cookie);
+       kfree(hw_metadata->trap_name);
+       kfree(hw_metadata->trap_group_name);
+--- a/net/core/dst.c
++++ b/net/core/dst.c
+@@ -49,8 +49,7 @@ void dst_init(struct dst_entry *dst, str
+             unsigned short flags)
+ {
+       dst->dev = dev;
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       dst->ops = ops;
+       dst_init_metrics(dst, dst_default_metrics.metrics, true);
+       dst->expires = 0UL;
+@@ -111,8 +110,7 @@ struct dst_entry *dst_destroy(struct dst
+ #endif
+       if (dst->ops->destroy)
+               dst->ops->destroy(dst);
+-      if (dst->dev)
+-              dev_put(dst->dev);
++      dev_put(dst->dev);
+       lwtstate_put(dst->lwtstate);
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -743,12 +743,10 @@ struct pneigh_entry * pneigh_lookup(stru
+       write_pnet(&n->net, net);
+       memcpy(n->key, pkey, key_len);
+       n->dev = dev;
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       if (tbl->pconstructor && tbl->pconstructor(n)) {
+-              if (dev)
+-                      dev_put(dev);
++              dev_put(dev);
+               kfree(n);
+               n = NULL;
+               goto out;
+@@ -780,8 +778,7 @@ int pneigh_delete(struct neigh_table *tb
+                       write_unlock_bh(&tbl->lock);
+                       if (tbl->pdestructor)
+                               tbl->pdestructor(n);
+-                      if (n->dev)
+-                              dev_put(n->dev);
++                      dev_put(n->dev);
+                       kfree(n);
+                       return 0;
+               }
+@@ -814,8 +811,7 @@ static int pneigh_ifdown_and_unlock(stru
+               n->next = NULL;
+               if (tbl->pdestructor)
+                       tbl->pdestructor(n);
+-              if (n->dev)
+-                      dev_put(n->dev);
++              dev_put(n->dev);
+               kfree(n);
+       }
+       return -ENOENT;
+@@ -1677,8 +1673,7 @@ void neigh_parms_release(struct neigh_ta
+       list_del(&parms->list);
+       parms->dead = 1;
+       write_unlock_bh(&tbl->lock);
+-      if (parms->dev)
+-              dev_put(parms->dev);
++      dev_put(parms->dev);
+       call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
+ }
+ EXPORT_SYMBOL(neigh_parms_release);
+--- a/net/ethtool/netlink.c
++++ b/net/ethtool/netlink.c
+@@ -356,8 +356,7 @@ static int ethnl_default_doit(struct sk_
+               ops->cleanup_data(reply_data);
+       genlmsg_end(rskb, reply_payload);
+-      if (req_info->dev)
+-              dev_put(req_info->dev);
++      dev_put(req_info->dev);
+       kfree(reply_data);
+       kfree(req_info);
+       return genlmsg_reply(rskb, info);
+@@ -369,8 +368,7 @@ err_cleanup:
+       if (ops->cleanup_data)
+               ops->cleanup_data(reply_data);
+ err_dev:
+-      if (req_info->dev)
+-              dev_put(req_info->dev);
++      dev_put(req_info->dev);
+       kfree(reply_data);
+       kfree(req_info);
+       return ret;
+--- a/net/ieee802154/nl-phy.c
++++ b/net/ieee802154/nl-phy.c
+@@ -340,8 +340,7 @@ nla_put_failure:
+ out_dev:
+       wpan_phy_put(phy);
+ out:
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+       return rc;
+ }
+--- a/net/ieee802154/nl802154.c
++++ b/net/ieee802154/nl802154.c
+@@ -2230,8 +2230,7 @@ static void nl802154_post_doit(const str
+               if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
+                       struct wpan_dev *wpan_dev = info->user_ptr[1];
+-                      if (wpan_dev->netdev)
+-                              dev_put(wpan_dev->netdev);
++                      dev_put(wpan_dev->netdev);
+               } else {
+                       dev_put(info->user_ptr[1]);
+               }
+--- a/net/ieee802154/socket.c
++++ b/net/ieee802154/socket.c
+@@ -41,8 +41,7 @@ ieee802154_get_dev(struct net *net, cons
+               ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
+               rcu_read_lock();
+               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
+-              if (dev)
+-                      dev_hold(dev);
++              dev_hold(dev);
+               rcu_read_unlock();
+               break;
+       case IEEE802154_ADDR_SHORT:
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -210,9 +210,7 @@ static void rt_fibinfo_free_cpus(struct
+ void fib_nh_common_release(struct fib_nh_common *nhc)
+ {
+-      if (nhc->nhc_dev)
+-              dev_put(nhc->nhc_dev);
+-
++      dev_put(nhc->nhc_dev);
+       lwtstate_put(nhc->nhc_lwtstate);
+       rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
+       rt_fibinfo_free(&nhc->nhc_rth_input);
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -2782,8 +2782,7 @@ struct dst_entry *ipv4_blackhole_route(s
+               new->output = dst_discard_out;
+               new->dev = net->loopback_dev;
+-              if (new->dev)
+-                      dev_hold(new->dev);
++              dev_hold(new->dev);
+               rt->rt_is_input = ort->rt_is_input;
+               rt->rt_iif = ort->rt_iif;
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -693,8 +693,7 @@ static int inet6_netconf_get_devconf(str
+ errout:
+       if (in6_dev)
+               in6_dev_put(in6_dev);
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+       return err;
+ }
+@@ -5469,8 +5468,7 @@ static int inet6_rtm_getaddr(struct sk_b
+ errout_ifa:
+       in6_ifa_put(ifa);
+ errout:
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+       if (fillargs.netnsid >= 0)
+               put_net(tgt_net);
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -561,8 +561,7 @@ static int pim6_rcv(struct sk_buff *skb)
+       read_lock(&mrt_lock);
+       if (reg_vif_num >= 0)
+               reg_dev = mrt->vif_table[reg_vif_num].dev;
+-      if (reg_dev)
+-              dev_hold(reg_dev);
++      dev_hold(reg_dev);
+       read_unlock(&mrt_lock);
+       if (!reg_dev)
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -3521,8 +3521,7 @@ out:
+               fib_nh_common_release(&fib6_nh->nh_common);
+               fib6_nh->nh_common.nhc_pcpu_rth_output = NULL;
+               fib6_nh->fib_nh_lws = NULL;
+-              if (dev)
+-                      dev_put(dev);
++              dev_put(dev);
+       }
+       return err;
+--- a/net/netfilter/nf_queue.c
++++ b/net/netfilter/nf_queue.c
+@@ -60,18 +60,14 @@ static void nf_queue_entry_release_refs(
+       struct nf_hook_state *state = &entry->state;
+       /* Release those devices we held, or Alexey will kill me. */
+-      if (state->in)
+-              dev_put(state->in);
+-      if (state->out)
+-              dev_put(state->out);
++      dev_put(state->in);
++      dev_put(state->out);
+       if (state->sk)
+               nf_queue_sock_put(state->sk);
+ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+-      if (entry->physin)
+-              dev_put(entry->physin);
+-      if (entry->physout)
+-              dev_put(entry->physout);
++      dev_put(entry->physin);
++      dev_put(entry->physout);
+ #endif
+ }
+@@ -107,16 +103,12 @@ bool nf_queue_entry_get_refs(struct nf_q
+       if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
+               return false;
+-      if (state->in)
+-              dev_hold(state->in);
+-      if (state->out)
+-              dev_hold(state->out);
++      dev_hold(state->in);
++      dev_hold(state->out);
+ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+-      if (entry->physin)
+-              dev_hold(entry->physin);
+-      if (entry->physout)
+-              dev_hold(entry->physout);
++      dev_hold(entry->physin);
++      dev_hold(entry->physout);
+ #endif
+       return true;
+ }
+--- a/net/netlabel/netlabel_unlabeled.c
++++ b/net/netlabel/netlabel_unlabeled.c
+@@ -492,8 +492,7 @@ static int netlbl_unlhsh_remove_addr4(st
+               netlbl_af4list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr->s_addr, mask->s_addr);
+-              if (dev != NULL)
+-                      dev_put(dev);
++              dev_put(dev);
+               if (entry != NULL &&
+                   security_secid_to_secctx(entry->secid,
+                                            &secctx, &secctx_len) == 0) {
+@@ -553,8 +552,7 @@ static int netlbl_unlhsh_remove_addr6(st
+               netlbl_af6list_audit_addr(audit_buf, 1,
+                                         (dev != NULL ? dev->name : NULL),
+                                         addr, mask);
+-              if (dev != NULL)
+-                      dev_put(dev);
++              dev_put(dev);
+               if (entry != NULL &&
+                   security_secid_to_secctx(entry->secid,
+                                            &secctx, &secctx_len) == 0) {
+--- a/net/netrom/nr_loopback.c
++++ b/net/netrom/nr_loopback.c
+@@ -59,8 +59,7 @@ static void nr_loopback_timer(struct tim
+               if (dev == NULL || nr_rx_frame(skb, dev) == 0)
+                       kfree_skb(skb);
+-              if (dev != NULL)
+-                      dev_put(dev);
++              dev_put(dev);
+               if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running())
+                       mod_timer(&loopback_timer, jiffies + 10);
+--- a/net/netrom/nr_route.c
++++ b/net/netrom/nr_route.c
+@@ -573,8 +573,7 @@ struct net_device *nr_dev_first(void)
+                       if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
+                               first = dev;
+       }
+-      if (first)
+-              dev_hold(first);
++      dev_hold(first);
+       rcu_read_unlock();
+       return first;
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -249,8 +249,7 @@ static struct net_device *packet_cached_
+       rcu_read_lock();
+       dev = rcu_dereference(po->cached_dev);
+-      if (likely(dev))
+-              dev_hold(dev);
++      dev_hold(dev);
+       rcu_read_unlock();
+       return dev;
+@@ -3103,8 +3102,7 @@ static int packet_snd(struct socket *soc
+ out_free:
+       kfree_skb(skb);
+ out_unlock:
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+ out:
+       return err;
+ }
+@@ -3241,8 +3239,7 @@ static int packet_do_bind(struct sock *s
+               }
+       }
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       proto_curr = po->prot_hook.type;
+       dev_curr = po->prot_hook.dev;
+@@ -3279,8 +3276,7 @@ static int packet_do_bind(struct sock *s
+                       packet_cached_dev_assign(po, dev);
+               }
+       }
+-      if (dev_curr)
+-              dev_put(dev_curr);
++      dev_put(dev_curr);
+       if (proto == 0 || !need_rehook)
+               goto out_unlock;
+@@ -4216,8 +4212,7 @@ static int packet_notifier(struct notifi
+                               if (msg == NETDEV_UNREGISTER) {
+                                       packet_cached_dev_reset(po);
+                                       WRITE_ONCE(po->ifindex, -1);
+-                                      if (po->prot_hook.dev)
+-                                              dev_put(po->prot_hook.dev);
++                                      dev_put(po->prot_hook.dev);
+                                       po->prot_hook.dev = NULL;
+                               }
+                               spin_unlock(&po->bind_lock);
+--- a/net/phonet/af_phonet.c
++++ b/net/phonet/af_phonet.c
+@@ -275,8 +275,7 @@ int pn_skb_send(struct sock *sk, struct
+ drop:
+       kfree_skb(skb);
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+       return err;
+ }
+ EXPORT_SYMBOL(pn_skb_send);
+--- a/net/phonet/pn_dev.c
++++ b/net/phonet/pn_dev.c
+@@ -122,8 +122,7 @@ struct net_device *phonet_device_get(str
+                       break;
+               dev = NULL;
+       }
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       rcu_read_unlock();
+       return dev;
+ }
+@@ -411,8 +410,7 @@ struct net_device *phonet_route_output(s
+       daddr >>= 2;
+       rcu_read_lock();
+       dev = rcu_dereference(routes->table[daddr]);
+-      if (dev)
+-              dev_hold(dev);
++      dev_hold(dev);
+       rcu_read_unlock();
+       if (!dev)
+--- a/net/phonet/socket.c
++++ b/net/phonet/socket.c
+@@ -379,8 +379,7 @@ static int pn_socket_ioctl(struct socket
+                       saddr = PN_NO_ADDR;
+               release_sock(sk);
+-              if (dev)
+-                      dev_put(dev);
++              dev_put(dev);
+               if (saddr == PN_NO_ADDR)
+                       return -EHOSTUNREACH;
+--- a/net/sched/act_mirred.c
++++ b/net/sched/act_mirred.c
+@@ -79,8 +79,7 @@ static void tcf_mirred_release(struct tc
+       /* last reference to action, no need to lock */
+       dev = rcu_dereference_protected(m->tcfm_dev, 1);
+-      if (dev)
+-              dev_put(dev);
++      dev_put(dev);
+ }
+ static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
+@@ -181,8 +180,7 @@ static int tcf_mirred_init(struct net *n
+               mac_header_xmit = dev_is_mac_header_xmit(dev);
+               dev = rcu_replace_pointer(m->tcfm_dev, dev,
+                                         lockdep_is_held(&m->tcf_lock));
+-              if (dev)
+-                      dev_put(dev);
++              dev_put(dev);
+               m->tcfm_mac_header_xmit = mac_header_xmit;
+       }
+       goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
+--- a/net/smc/smc_pnet.c
++++ b/net/smc/smc_pnet.c
+@@ -395,8 +395,7 @@ static int smc_pnet_add_eth(struct smc_p
+       return 0;
+ out_put:
+-      if (ndev)
+-              dev_put(ndev);
++      dev_put(ndev);
+       return rc;
+ }
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -6356,8 +6356,7 @@ static int nl80211_set_station(struct sk
+       err = rdev_change_station(rdev, dev, mac_addr, &params);
+  out_put_vlan:
+-      if (params.vlan)
+-              dev_put(params.vlan);
++      dev_put(params.vlan);
+       return err;
+ }
+@@ -6592,8 +6591,7 @@ static int nl80211_new_station(struct sk
+       err = rdev_add_station(rdev, dev, mac_addr, &params);
+-      if (params.vlan)
+-              dev_put(params.vlan);
++      dev_put(params.vlan);
+       return err;
+ }
+@@ -8308,8 +8306,7 @@ static int nl80211_trigger_scan(struct s
+               goto out_free;
+       nl80211_send_scan_start(rdev, wdev);
+-      if (wdev->netdev)
+-              dev_hold(wdev->netdev);
++      dev_hold(wdev->netdev);
+       return 0;
+@@ -14661,9 +14658,7 @@ static int nl80211_pre_doit(const struct
+                       return -ENETDOWN;
+               }
+-              if (dev)
+-                      dev_hold(dev);
+-
++              dev_hold(dev);
+               info->user_ptr[0] = rdev;
+       }
+@@ -14677,8 +14672,7 @@ static void nl80211_post_doit(const stru
+               if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
+                       struct wireless_dev *wdev = info->user_ptr[1];
+-                      if (wdev->netdev)
+-                              dev_put(wdev->netdev);
++                      dev_put(wdev->netdev);
+               } else {
+                       dev_put(info->user_ptr[1]);
+               }
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -1057,8 +1057,7 @@ void ___cfg80211_scan_done(struct cfg802
+       }
+ #endif
+-      if (wdev->netdev)
+-              dev_put(wdev->netdev);
++      dev_put(wdev->netdev);
+       kfree(rdev->int_scan_req);
+       rdev->int_scan_req = NULL;
diff --git a/queue-5.10/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch b/queue-5.10/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch
new file mode 100644 (file)
index 0000000..a9b30ce
--- /dev/null
@@ -0,0 +1,94 @@
+From stable+bounces-256829-greg=kroah.com@vger.kernel.org Sat May 30 05:19:54 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:49:42 -0400
+Subject: netfilter: nf_queue: hold bridge skb->dev while queued
+To: stable@vger.kernel.org
+Cc: Haoze Xie <royenheart@gmail.com>, stable@kernel.org, Yuan Tan <yuantan098@gmail.com>, Yifan Wu <yifanwucs@gmail.com>, Juefei Pu <tomapufckgml@gmail.com>, Xin Liu <bird@lzu.edu.cn>, Ren Wei <n05ec@lzu.edu.cn>, Pablo Neira Ayuso <pablo@netfilter.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529234942.1939638-2-sashal@kernel.org>
+
+From: Haoze Xie <royenheart@gmail.com>
+
+[ Upstream commit e196115ec330a18de415bdb9f5071aa9f08e53ce ]
+
+br_pass_frame_up() rewrites skb->dev from the ingress port to the bridge
+master before queueing bridge LOCAL_IN packets. NFQUEUE only holds
+references on state.in/out and bridge physdevs, so a queued bridge
+packet can retain a freed bridge master in skb->dev until reinjection.
+
+When the verdict is reinjected later, br_netif_receive_skb() re-enters
+the receive path with skb->dev still pointing at the freed bridge master,
+triggering a use-after-free.
+
+Store skb->dev in the queue entry, hold a reference on it for the queue
+lifetime, and use the saved device when dropping queued packets during
+NETDEV_DOWN handling.
+
+Fixes: ac2863445686 ("netfilter: bridge: add nf_afinfo to enable queuing to userspace")
+Cc: stable@kernel.org
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Haoze Xie <royenheart@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_queue.h |    1 +
+ net/netfilter/nf_queue.c         |    4 +++-
+ net/netfilter/nfnetlink_queue.c  |    2 ++
+ 3 files changed, 6 insertions(+), 1 deletion(-)
+
+--- a/include/net/netfilter/nf_queue.h
++++ b/include/net/netfilter/nf_queue.h
+@@ -12,6 +12,7 @@
+ struct nf_queue_entry {
+       struct list_head        list;
+       struct sk_buff          *skb;
++      struct net_device       *skb_dev;
+       unsigned int            id;
+       unsigned int            hook_index;     /* index in hook_entries->hook[] */
+ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+--- a/net/netfilter/nf_queue.c
++++ b/net/netfilter/nf_queue.c
+@@ -60,6 +60,7 @@ static void nf_queue_entry_release_refs(
+       struct nf_hook_state *state = &entry->state;
+       /* Release those devices we held, or Alexey will kill me. */
++      dev_put(entry->skb_dev);
+       dev_put(state->in);
+       dev_put(state->out);
+       if (state->sk)
+@@ -103,6 +104,7 @@ bool nf_queue_entry_get_refs(struct nf_q
+       if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
+               return false;
++      dev_hold(entry->skb_dev);
+       dev_hold(state->in);
+       dev_hold(state->out);
+@@ -204,11 +206,11 @@ static int __nf_queue(struct sk_buff *sk
+       *entry = (struct nf_queue_entry) {
+               .skb    = skb,
++              .skb_dev = skb->dev,
+               .state  = *state,
+               .hook_index = index,
+               .size   = sizeof(*entry) + route_key_size,
+       };
+-
+       __nf_queue_entry_init_physdevs(entry);
+       if (!nf_queue_entry_get_refs(entry)) {
+--- a/net/netfilter/nfnetlink_queue.c
++++ b/net/netfilter/nfnetlink_queue.c
+@@ -911,6 +911,8 @@ dev_cmp(struct nf_queue_entry *entry, un
+       if (physinif == ifindex || physoutif == ifindex)
+               return 1;
+ #endif
++      if (entry->skb_dev && entry->skb_dev->ifindex == ifindex)
++              return 1;
+       if (entry->state.in)
+               if (entry->state.in->ifindex == ifindex)
+                       return 1;
diff --git a/queue-5.10/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch b/queue-5.10/netfilter-nft_fib-fix-stale-stack-leak-via-the-oifname-register.patch
new file mode 100644 (file)
index 0000000..2ee368b
--- /dev/null
@@ -0,0 +1,86 @@
+From stable+bounces-263424-greg=kroah.com@vger.kernel.org Mon Jun 15 23:33:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 14:02:45 -0400
+Subject: netfilter: nft_fib: fix stale stack leak via the OIFNAME register
+To: stable@vger.kernel.org
+Cc: Davide Ornaghi <d.ornaghi97@gmail.com>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260615180245.2316306-1-sashal@kernel.org>
+
+From: Davide Ornaghi <d.ornaghi97@gmail.com>
+
+[ 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 <fw@strlen.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Davide Ornaghi <d.ornaghi97@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -118,7 +118,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
+@@ -189,7 +189,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
+@@ -105,6 +105,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-5.10/octeontx2-af-add-validation-for-lmac-type.patch b/queue-5.10/octeontx2-af-add-validation-for-lmac-type.patch
new file mode 100644 (file)
index 0000000..2d595f2
--- /dev/null
@@ -0,0 +1,83 @@
+From stable+bounces-259316-greg=kroah.com@vger.kernel.org Sun May 31 05:54:08 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 20:23:59 -0400
+Subject: octeontx2-af: Add validation for lmac type
+To: stable@vger.kernel.org
+Cc: Hariprasad Kelam <hkelam@marvell.com>, Sunil Kovvuri Goutham <sgoutham@marvell.com>, Sai Krishna <saikrishnag@marvell.com>, Simon Horman <simon.horman@corigine.com>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260531002401.3659638-1-sashal@kernel.org>
+
+From: Hariprasad Kelam <hkelam@marvell.com>
+
+[ Upstream commit cb5edce271764524b88b1a6866b3e626686d9a33 ]
+
+Upon physical link change, firmware reports to the kernel about the
+change along with the details like speed, lmac_type_id, etc.
+Kernel derives lmac_type based on lmac_type_id received from firmware.
+
+In a few scenarios, firmware returns an invalid lmac_type_id, which
+is resulting in below kernel panic. This patch adds the missing
+validation of the lmac_type_id field.
+
+Internal error: Oops: 96000005 [#1] PREEMPT SMP
+[   35.321595] Modules linked in:
+[   35.328982] CPU: 0 PID: 31 Comm: kworker/0:1 Not tainted
+5.4.210-g2e3169d8e1bc-dirty #17
+[   35.337014] Hardware name: Marvell CN103XX board (DT)
+[   35.344297] Workqueue: events work_for_cpu_fn
+[   35.352730] pstate: 40400089 (nZcv daIf +PAN -UAO)
+[   35.360267] pc : strncpy+0x10/0x30
+[   35.366595] lr : cgx_link_change_handler+0x90/0x180
+
+Fixes: 61071a871ea6 ("octeontx2-af: Forward CGX link notifications to PFs")
+Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
+Signed-off-by: Sunil Kovvuri Goutham <sgoutham@marvell.com>
+Signed-off-by: Sai Krishna <saikrishnag@marvell.com>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: c0bf0a4f3f1f ("octeontx2-af: CGX: add bounds check to cgx_speed_mbps index")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/af/cgx.c  |   15 +++++++++++----
+ drivers/net/ethernet/marvell/octeontx2/af/mbox.h |    1 +
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+@@ -669,15 +669,22 @@ static inline void link_status_user_form
+                                          struct cgx_link_user_info *linfo,
+                                          struct cgx *cgx, u8 lmac_id)
+ {
+-      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)];
++      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);
+-      lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
+-      strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
++
++      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);
++              return;
++      }
++
++      strncpy(linfo->lmac_type, cgx_lmactype_string[linfo->lmac_type_id],
++              LMACTYPE_STR_LEN - 1);
+ }
+ /* Hardware event handlers */
+--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+@@ -369,6 +369,7 @@ struct cgx_link_user_info {
+       uint64_t full_duplex:1;
+       uint64_t lmac_type_id:4;
+       uint64_t speed:20; /* speed in Mbps */
++      uint64_t an:1;          /* AN supported or not */
+       uint64_t fec:2;  /* FEC type if enabled else 0 */
+ #define LMACTYPE_STR_LEN 16
+       char lmac_type[LMACTYPE_STR_LEN];
diff --git a/queue-5.10/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch b/queue-5.10/octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.patch
new file mode 100644 (file)
index 0000000..91fa0f3
--- /dev/null
@@ -0,0 +1,57 @@
+From stable+bounces-259318-greg=kroah.com@vger.kernel.org Sun May 31 05:54:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 20:24:01 -0400
+Subject: octeontx2-af: CGX: add bounds check to cgx_speed_mbps index
+To: stable@vger.kernel.org
+Cc: Sam Daly <sam@samdaly.ie>, Sunil Goutham <sgoutham@marvell.com>, Linu Cherian <lcherian@marvell.com>, Geetha sowjanya <gakula@marvell.com>, hariprasad <hkelam@marvell.com>, Subbaraya Sundeep <sbhatta@marvell.com>, Andrew Lunn <andrew+netdev@lunn.ch>, stable <stable@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260531002401.3659638-3-sashal@kernel.org>
+
+From: Sam Daly <sam@samdaly.ie>
+
+[ 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 <sgoutham@marvell.com>
+Cc: Linu Cherian <lcherian@marvell.com>
+Cc: Geetha sowjanya <gakula@marvell.com>
+Cc: hariprasad <hkelam@marvell.com>
+Cc: Subbaraya Sundeep <sbhatta@marvell.com>
+Cc: Andrew Lunn <andrew+netdev@lunn.ch>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Sam Daly <sam@samdaly.ie>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Link: https://patch.msgid.link/2026051352-refined-demise-e88d@gregkh
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -669,13 +669,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-5.10/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch b/queue-5.10/octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch
new file mode 100644 (file)
index 0000000..ca2fe2a
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-259317-greg=kroah.com@vger.kernel.org Sun May 31 05:54:08 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 20:24:00 -0400
+Subject: octeontx2-af: replace deprecated strncpy with strscpy
+To: stable@vger.kernel.org
+Cc: Justin Stitt <justinstitt@google.com>, Kees Cook <keescook@chromium.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260531002401.3659638-2-sashal@kernel.org>
+
+From: Justin Stitt <justinstitt@google.com>
+
+[ 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 <justinstitt@google.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+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 <kuba@kernel.org>
+Stable-dep-of: c0bf0a4f3f1f ("octeontx2-af: CGX: add bounds check to cgx_speed_mbps index")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/af/cgx.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+@@ -679,12 +679,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;
+       }
+-      strncpy(linfo->lmac_type, cgx_lmactype_string[linfo->lmac_type_id],
+-              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-5.10/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch b/queue-5.10/octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch
new file mode 100644 (file)
index 0000000..e052954
--- /dev/null
@@ -0,0 +1,62 @@
+From stable+bounces-259300-greg=kroah.com@vger.kernel.org Sun May 31 02:03:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 16:33:16 -0400
+Subject: octeontx2-pf: avoid double free of pool->stack on AQ init failure
+To: stable@vger.kernel.org
+Cc: Dawei Feng <dawei.feng@seu.edu.cn>, Zilin Guan <zilin@seu.edu.cn>, Simon Horman <horms@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530203316.3338022-1-sashal@kernel.org>
+
+From: Dawei Feng <dawei.feng@seu.edu.cn>
+
+[ 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 <zilin@seu.edu.cn>
+Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260515151826.1005397-1-dawei.feng@seu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1194,11 +1194,13 @@ static int otx2_pool_init(struct otx2_ni
+               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-5.10/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch b/queue-5.10/phy-tegra-xusb-disable-trk-clk-when-not-in-use.patch
new file mode 100644 (file)
index 0000000..7834607
--- /dev/null
@@ -0,0 +1,51 @@
+From sashal@kernel.org Mon Jun  1 16:38:12 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 07:08:08 -0400
+Subject: phy: tegra: xusb: Disable trk clk when not in use
+To: stable@vger.kernel.org
+Cc: Wayne Chang <waynec@nvidia.com>, Jon Hunter <jonathanh@nvidia.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601110809.450763-1-sashal@kernel.org>
+
+From: Wayne Chang <waynec@nvidia.com>
+
+[ 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 <waynec@nvidia.com>
+Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://lore.kernel.org/r/20230111110450.24617-5-jonathanh@nvidia.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: da110228b54f ("phy: tegra: xusb: Fix per-pad high-speed termination calibration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -225,6 +225,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);
+ }
+@@ -249,8 +253,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-5.10/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch b/queue-5.10/phy-tegra-xusb-fix-per-pad-high-speed-termination-calibration.patch
new file mode 100644 (file)
index 0000000..2f83db9
--- /dev/null
@@ -0,0 +1,144 @@
+From stable+bounces-259532-greg=kroah.com@vger.kernel.org Mon Jun  1 16:40:27 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 07:08:09 -0400
+Subject: phy: tegra: xusb: Fix per-pad high-speed termination calibration
+To: stable@vger.kernel.org
+Cc: Wayne Chang <waynec@nvidia.com>, Wei-Cheng Chen <weichengc@nvidia.com>, Jon Hunter <jonathanh@nvidia.com>, Vinod Koul <vkoul@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601110809.450763-2-sashal@kernel.org>
+
+From: Wayne Chang <waynec@nvidia.com>
+
+[ 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 <waynec@nvidia.com>
+Signed-off-by: Wei-Cheng Chen <weichengc@nvidia.com>
+Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
+Tested-by: Jon Hunter <jonathanh@nvidia.com>
+Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -127,7 +127,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;
+ };
+@@ -477,7 +477,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));
+@@ -895,17 +895,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) {
+               if (err != -EPROBE_DEFER)
+@@ -924,8 +930,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) {
+@@ -937,6 +943,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;
+ }
+@@ -1095,6 +1112,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
+@@ -415,6 +415,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-5.10/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch b/queue-5.10/pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
new file mode 100644 (file)
index 0000000..ee58634
--- /dev/null
@@ -0,0 +1,73 @@
+From stable+bounces-248924-greg=kroah.com@vger.kernel.org Sat May 16 03:20:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 17:35:39 -0400
+Subject: pmdomain: core: Fix detach procedure for virtual devices in genpd
+To: stable@vger.kernel.org
+Cc: Ulf Hansson <ulf.hansson@linaro.org>, Geert Uytterhoeven <geert@linux-m68k.org>, Geert Uytterhoeven <geert+renesas@glider.be>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515213539.3512446-1-sashal@kernel.org>
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ 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 <geert@linux-m68k.org>
+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 <geert+renesas@glider.be>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+[ dropped upstream context block referencing nonexistent `default_pstate` field ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2525,6 +2525,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;
+@@ -2534,6 +2535,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);
++
+       for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
+               ret = genpd_remove_device(pd, dev);
+               if (ret != -EAGAIN)
+@@ -2553,7 +2561,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-5.10/printk-add-print_hex_dump_devel.patch b/queue-5.10/printk-add-print_hex_dump_devel.patch
new file mode 100644 (file)
index 0000000..82c68c6
--- /dev/null
@@ -0,0 +1,49 @@
+From stable+bounces-245036-greg=kroah.com@vger.kernel.org Sun May 10 21:13:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 11:43:37 -0400
+Subject: printk: add print_hex_dump_devel()
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Herbert Xu <herbert@gondor.apana.org.au>, John Ogness <john.ogness@linutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260510154339.144690-1-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ 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 <herbert@gondor.apana.org.au>
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Reviewed-by: John Ogness <john.ogness@linutronix.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: 177730a273b1 ("crypto: caam - guard HMAC key hex dumps in hash_digest_key")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/printk.h |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/include/linux/printk.h
++++ b/include/linux/printk.h
+@@ -608,6 +608,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-5.10/qed-fix-double-free-in-qed_cxt_tables_alloc.patch b/queue-5.10/qed-fix-double-free-in-qed_cxt_tables_alloc.patch
new file mode 100644 (file)
index 0000000..ed40523
--- /dev/null
@@ -0,0 +1,58 @@
+From stable+bounces-256819-greg=kroah.com@vger.kernel.org Sat May 30 05:07:32 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:33:25 -0400
+Subject: qed: fix double free in qed_cxt_tables_alloc()
+To: stable@vger.kernel.org
+Cc: Dawei Feng <dawei.feng@seu.edu.cn>, Zilin Guan <zilin@seu.edu.cn>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233325.1901920-2-sashal@kernel.org>
+
+From: Dawei Feng <dawei.feng@seu.edu.cn>
+
+[ Upstream commit 2bccfb8476ca5f3548afbd623dc7a6980d4e77de ]
+
+If one of the later PF or VF CID bitmap allocations fails,
+qed_cid_map_alloc() jumps to cid_map_fail and frees the previously
+allocated CID bitmaps before returning an error. qed_cxt_tables_alloc()
+then calls qed_cxt_mngr_free(), which invokes qed_cid_map_free()
+again.
+
+Fix this by setting each CID bitmap pointer to NULL after bitmap_free()
+to avoid double free.
+
+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 reproduction was not attempted because exercising the failing
+allocation path requires device-specific setup.
+
+Fixes: fe56b9e6a8d9 ("qed: Add module with basic common support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
+Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
+Link: https://patch.msgid.link/20260520070323.2762379-1-dawei.feng@seu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_cxt.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+@@ -1038,11 +1038,13 @@ static void qed_cid_map_free(struct qed_
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+               bitmap_free(p_mngr->acquired[type].cid_map);
++              p_mngr->acquired[type].cid_map = NULL;
+               p_mngr->acquired[type].max_count = 0;
+               p_mngr->acquired[type].start_cid = 0;
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+                       bitmap_free(p_mngr->acquired_vf[type][vf].cid_map);
++                      p_mngr->acquired_vf[type][vf].cid_map = NULL;
+                       p_mngr->acquired_vf[type][vf].max_count = 0;
+                       p_mngr->acquired_vf[type][vf].start_cid = 0;
+               }
diff --git a/queue-5.10/qed-use-the-bitmap-api-to-simplify-some-functions.patch b/queue-5.10/qed-use-the-bitmap-api-to-simplify-some-functions.patch
new file mode 100644 (file)
index 0000000..8053d2a
--- /dev/null
@@ -0,0 +1,99 @@
+From stable+bounces-256818-greg=kroah.com@vger.kernel.org Sat May 30 05:07:21 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 May 2026 19:33:24 -0400
+Subject: qed: Use the bitmap API to simplify some functions
+To: stable@vger.kernel.org
+Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260529233325.1901920-1-sashal@kernel.org>
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 5e6c7ccd3ea4b25dd6b4b0363859913f315deacb ]
+
+'cid_map' is a bitmap. So use 'bitmap_zalloc()' to simplify code,
+improve the semantic and avoid some open-coded arithmetic in allocator
+arguments.
+
+Also change the corresponding 'kfree()' into 'bitmap_free()' to keep
+consistency.
+
+Also change some 'memset()' into 'bitmap_zero()' to keep consistency. This
+is also much less verbose.
+
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 2bccfb8476ca ("qed: fix double free in qed_cxt_tables_alloc()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_cxt.c |   24 +++++-------------------
+ 1 file changed, 5 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+@@ -1037,12 +1037,12 @@ static void qed_cid_map_free(struct qed_
+       u32 type, vf;
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+-              kfree(p_mngr->acquired[type].cid_map);
++              bitmap_free(p_mngr->acquired[type].cid_map);
+               p_mngr->acquired[type].max_count = 0;
+               p_mngr->acquired[type].start_cid = 0;
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+-                      kfree(p_mngr->acquired_vf[type][vf].cid_map);
++                      bitmap_free(p_mngr->acquired_vf[type][vf].cid_map);
+                       p_mngr->acquired_vf[type][vf].max_count = 0;
+                       p_mngr->acquired_vf[type][vf].start_cid = 0;
+               }
+@@ -1055,15 +1055,10 @@ qed_cid_map_alloc_single(struct qed_hwfn
+                        u32 cid_start,
+                        u32 cid_count, struct qed_cid_acquired_map *p_map)
+ {
+-      u32 size;
+-
+       if (!cid_count)
+               return 0;
+-      size = DIV_ROUND_UP(cid_count,
+-                          sizeof(unsigned long) * BITS_PER_BYTE) *
+-             sizeof(unsigned long);
+-      p_map->cid_map = kzalloc(size, GFP_KERNEL);
++      p_map->cid_map = bitmap_zalloc(cid_count, GFP_KERNEL);
+       if (!p_map->cid_map)
+               return -ENOMEM;
+@@ -1217,7 +1212,6 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+       struct qed_cid_acquired_map *p_map;
+       struct qed_conn_type_cfg *p_cfg;
+       int type;
+-      u32 len;
+       /* Reset acquired cids */
+       for (type = 0; type < MAX_CONN_TYPES; type++) {
+@@ -1226,11 +1220,7 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+               p_cfg = &p_mngr->conn_cfg[type];
+               if (p_cfg->cid_count) {
+                       p_map = &p_mngr->acquired[type];
+-                      len = DIV_ROUND_UP(p_map->max_count,
+-                                         sizeof(unsigned long) *
+-                                         BITS_PER_BYTE) *
+-                            sizeof(unsigned long);
+-                      memset(p_map->cid_map, 0, len);
++                      bitmap_zero(p_map->cid_map, p_map->max_count);
+               }
+               if (!p_cfg->cids_per_vf)
+@@ -1238,11 +1228,7 @@ void qed_cxt_mngr_setup(struct qed_hwfn
+               for (vf = 0; vf < MAX_NUM_VFS; vf++) {
+                       p_map = &p_mngr->acquired_vf[type][vf];
+-                      len = DIV_ROUND_UP(p_map->max_count,
+-                                         sizeof(unsigned long) *
+-                                         BITS_PER_BYTE) *
+-                            sizeof(unsigned long);
+-                      memset(p_map->cid_map, 0, len);
++                      bitmap_zero(p_map->cid_map, p_map->max_count);
+               }
+       }
+ }
diff --git a/queue-5.10/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch b/queue-5.10/rdma-move-dma-block-iterator-logic-into-dedicated-files.patch
new file mode 100644 (file)
index 0000000..a2b73ea
--- /dev/null
@@ -0,0 +1,451 @@
+From stable+bounces-263530-greg=kroah.com@vger.kernel.org Tue Jun 16 08:47:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 23:17:36 -0400
+Subject: RDMA: Move DMA block iterator logic into dedicated files
+To: stable@vger.kernel.org
+Cc: Leon Romanovsky <leonro@nvidia.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616031737.2781524-2-sashal@kernel.org>
+
+From: Leon Romanovsky <leonro@nvidia.com>
+
+[ 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 <leonro@nvidia.com>
+Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/core/Makefile             |    2 
+ drivers/infiniband/core/iter.c               |   43 ++++++++++++++
+ drivers/infiniband/core/verbs.c              |   37 ------------
+ 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/hns/hns_roce_alloc.c   |    2 
+ drivers/infiniband/hw/i40iw/i40iw_verbs.c    |    1 
+ drivers/infiniband/hw/mlx4/mr.c              |    1 
+ drivers/infiniband/hw/mlx5/mem.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                       |   24 --------
+ include/rdma/ib_verbs.h                      |   47 ---------------
+ include/rdma/iter.h                          |   80 +++++++++++++++++++++++++++
+ 17 files changed, 135 insertions(+), 117 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 <linux/export.h>
++#include <rdma/iter.h>
++
++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
+@@ -2896,40 +2896,3 @@ int rdma_init_netdev(struct ib_device *d
+                                            netdev, params.param);
+ }
+ 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 sg_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);
+-      sg_delta = BIT_ULL(biter->__pg_bit) - block_offset;
+-
+-      if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) {
+-              biter->__sg_advance += sg_delta;
+-      } else {
+-              biter->__sg_advance = 0;
+-              biter->__sg = sg_next(biter->__sg);
+-              biter->__sg_nents--;
+-      }
+-
+-      return true;
+-}
+-EXPORT_SYMBOL(__rdma_block_iter_next);
+--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
+@@ -46,7 +46,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/vmalloc.h>
+ #include <rdma/ib_verbs.h>
+-#include <rdma/ib_umem.h>
++#include <rdma/iter.h>
+ #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 <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <rdma/ib_umem.h>
+ #include <linux/atomic.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include "iw_cxgb4.h"
+--- a/drivers/infiniband/hw/efa/efa_verbs.c
++++ b/drivers/infiniband/hw/efa/efa_verbs.c
+@@ -7,9 +7,9 @@
+ #include <linux/log2.h>
+ #include <rdma/ib_addr.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/ib_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "efa.h"
+--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c
++++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
+@@ -34,7 +34,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/vmalloc.h>
+ #include "hns_roce_device.h"
+-#include <rdma/ib_umem.h>
++#include <rdma/iter.h>
+ int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj)
+ {
+--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
++++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+@@ -45,6 +45,7 @@
+ #include <rdma/iw_cm.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/ib_umem.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "i40iw.h"
+--- a/drivers/infiniband/hw/mlx4/mr.c
++++ b/drivers/infiniband/hw/mlx4/mr.c
+@@ -33,6 +33,7 @@
+ #include <linux/slab.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include "mlx4_ib.h"
+--- a/drivers/infiniband/hw/mlx5/mem.c
++++ b/drivers/infiniband/hw/mlx5/mem.c
+@@ -33,6 +33,7 @@
+ #include <linux/module.h>
+ #include <rdma/ib_umem.h>
+ #include <rdma/ib_umem_odp.h>
++#include <rdma/iter.h>
+ #include "mlx5_ib.h"
+ #include <linux/jiffies.h>
+--- a/drivers/infiniband/hw/mthca/mthca_provider.c
++++ b/drivers/infiniband/hw/mthca/mthca_provider.c
+@@ -35,8 +35,8 @@
+  */
+ #include <rdma/ib_smi.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_user_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include <linux/sched.h>
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+@@ -44,9 +44,9 @@
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/iw_cm.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_addr.h>
+ #include <rdma/ib_cache.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include "ocrdma.h"
+--- a/drivers/infiniband/hw/qedr/verbs.c
++++ b/drivers/infiniband/hw/qedr/verbs.c
+@@ -39,9 +39,9 @@
+ #include <rdma/ib_verbs.h>
+ #include <rdma/ib_user_verbs.h>
+ #include <rdma/iw_cm.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_addr.h>
+ #include <rdma/ib_cache.h>
++#include <rdma/iter.h>
+ #include <rdma/uverbs_ioctl.h>
+ #include <linux/qed/common_hsi.h>
+--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
+@@ -53,8 +53,8 @@
+ #include <linux/pci.h>
+ #include <linux/semaphore.h>
+ #include <linux/workqueue.h>
+-#include <rdma/ib_umem.h>
+ #include <rdma/ib_verbs.h>
++#include <rdma/iter.h>
+ #include <rdma/vmw_pvrdma-abi.h>
+ #include "pvrdma_ring.h"
+--- a/include/rdma/ib_umem.h
++++ b/include/rdma/ib_umem.h
+@@ -46,30 +46,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->sg_head.sgl, umem->nmap, pgsz);
+-}
+-
+-/**
+- * 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_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
+@@ -2756,21 +2756,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 */
+-      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) +              \
+@@ -2792,38 +2777,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,80 @@
++/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
++/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. */
++
++#ifndef _RDMA_ITER_H_
++#define _RDMA_ITER_H_
++
++#include <linux/scatterlist.h>
++#include <rdma/ib_umem.h>
++
++/**
++ * 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 */
++      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->sg_head.sgl, umem->nmap, pgsz);
++}
++
++/**
++ * 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_block_iter_next(biter);)
++
++#endif /* _RDMA_ITER_H_ */
diff --git a/queue-5.10/rdma-umem-fix-kernel-doc-warnings.patch b/queue-5.10/rdma-umem-fix-kernel-doc-warnings.patch
new file mode 100644 (file)
index 0000000..24e311c
--- /dev/null
@@ -0,0 +1,41 @@
+From stable+bounces-263528-greg=kroah.com@vger.kernel.org Tue Jun 16 08:47:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 23:17:35 -0400
+Subject: RDMA/umem: fix kernel-doc warnings
+To: stable@vger.kernel.org
+Cc: Randy Dunlap <rdunlap@infradead.org>, Leon Romanovsky <leon@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616031737.2781524-1-sashal@kernel.org>
+
+From: Randy Dunlap <rdunlap@infradead.org>
+
+[ 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 <rdunlap@infradead.org>
+Link: https://patch.msgid.link/20260224003120.3173892-1-rdunlap@infradead.org
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Stable-dep-of: 15fe76e23615 ("RDMA/umem: Fix truncation for block sizes >= 4G")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/rdma/ib_umem.h |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/rdma/ib_umem.h
++++ b/include/rdma/ib_umem.h
+@@ -57,6 +57,7 @@ static inline void __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
diff --git a/queue-5.10/rdma-umem-fix-truncation-for-block-sizes-4g.patch b/queue-5.10/rdma-umem-fix-truncation-for-block-sizes-4g.patch
new file mode 100644 (file)
index 0000000..4cdbb84
--- /dev/null
@@ -0,0 +1,44 @@
+From stable+bounces-263529-greg=kroah.com@vger.kernel.org Tue Jun 16 08:47:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jun 2026 23:17:37 -0400
+Subject: RDMA/umem: Fix truncation for block sizes >= 4G
+To: stable@vger.kernel.org
+Cc: Jason Gunthorpe <jgg@nvidia.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260616031737.2781524-3-sashal@kernel.org>
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ 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 <jgg@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/sched-use-u64-for-bandwidth-ratio-calculations.patch b/queue-5.10/sched-use-u64-for-bandwidth-ratio-calculations.patch
new file mode 100644 (file)
index 0000000..5ef2dde
--- /dev/null
@@ -0,0 +1,74 @@
+From stable+bounces-242630-greg=kroah.com@vger.kernel.org Sun May  3 06:10:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  2 May 2026 20:40:07 -0400
+Subject: sched: Use u64 for bandwidth ratio calculations
+To: stable@vger.kernel.org
+Cc: Joseph Salisbury <joseph.salisbury@oracle.com>, "Peter Zijlstra (Intel)" <peterz@infradead.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260503004007.933354-1-sashal@kernel.org>
+
+From: Joseph Salisbury <joseph.salisbury@oracle.com>
+
+[ Upstream commit c6e80201e057dfb7253385e60bf541121bf5dc33 ]
+
+to_ratio() computes BW_SHIFT-scaled bandwidth ratios from u64 period and
+runtime values, but it returns unsigned long.  tg_rt_schedulable() also
+stores the current group limit and the accumulated child sum in unsigned
+long.
+
+On 32-bit builds, large bandwidth ratios can be truncated and the RT
+group sum can wrap when enough siblings are present.  That can let an
+overcommitted RT hierarchy pass the schedulability check, and it also
+narrows the helper result for other callers.
+
+Return u64 from to_ratio() and use u64 for the RT group totals so
+bandwidth ratios are preserved and compared at full width on both 32-bit
+and 64-bit builds.
+
+Fixes: b40b2e8eb521 ("sched: rt: multi level group constraints")
+Assisted-by: Codex:GPT-5
+Signed-off-by: Joseph Salisbury <joseph.salisbury@oracle.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260403210014.2713404-1-joseph.salisbury@oracle.com
+[ dropped `extern` keyword from `to_ratio()` declaration ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sched/core.c  |    2 +-
+ kernel/sched/rt.c    |    2 +-
+ kernel/sched/sched.h |    2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -3328,7 +3328,7 @@ void sched_post_fork(struct task_struct
+       uclamp_post_fork(p);
+ }
+-unsigned long to_ratio(u64 period, u64 runtime)
++u64 to_ratio(u64 period, u64 runtime)
+ {
+       if (runtime == RUNTIME_INF)
+               return BW_UNIT;
+--- a/kernel/sched/rt.c
++++ b/kernel/sched/rt.c
+@@ -2527,7 +2527,7 @@ static int tg_rt_schedulable(struct task
+ {
+       struct rt_schedulable_data *d = data;
+       struct task_group *child;
+-      unsigned long total, sum = 0;
++      u64 total, sum = 0;
+       u64 period, runtime;
+       period = ktime_to_ns(tg->rt_bandwidth.rt_period);
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -1956,7 +1956,7 @@ extern void init_dl_inactive_task_timer(
+ #define RATIO_SHIFT           8
+ #define MAX_BW_BITS           (64 - BW_SHIFT)
+ #define MAX_BW                        ((1ULL << MAX_BW_BITS) - 1)
+-unsigned long to_ratio(u64 period, u64 runtime);
++u64 to_ratio(u64 period, u64 runtime);
+ extern void init_entity_runnable_average(struct sched_entity *se);
+ extern void post_init_entity_util_avg(struct task_struct *p);
diff --git a/queue-5.10/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch b/queue-5.10/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
new file mode 100644 (file)
index 0000000..34985d1
--- /dev/null
@@ -0,0 +1,203 @@
+From stable+bounces-260836-greg=kroah.com@vger.kernel.org Sat Jun  6 07:48:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:18:34 -0400
+Subject: scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, John Garry <john.g.garry@oracle.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606021834.2487480-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit bf33e01f88388c43e285492a63e539df6ffed64c ]
+
+iscsi_encode_text_output() concatenates "key=value\0" records into
+login->rsp_buf, an 8192-byte kzalloc(MAX_KEY_VALUE_PAIRS) buffer
+allocated in iscsit_alloc_login_setup_buffer(). The three sprintf() call
+sites in this function (lines 1398, 1411, 1424 in v7.1-rc2) never check
+the remaining buffer capacity:
+
+       *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+       *length += 1;
+       output_buf = textbuf + *length;
+
+The 8192-byte ceiling at iscsi_target_check_login_request() bounds the
+*input* Login PDU payload, but a single PDU can carry up to 2048 minimal
+four-byte "a=b\0" pairs, each unknown key expanding to a 16-byte
+"a=NotUnderstood\0" output record via iscsi_add_notunderstood_response().
+2048 * 16 = 32 KiB of output into an 8 KiB buffer, producing a ~24 KiB
+heap overrun in the kmalloc-8k slab.
+
+The fix introduces a static iscsi_encode_text_record() helper that uses
+snprintf() with a per-call bounds check against the remaining buffer,
+and threads a u32 textbuf_size parameter through
+iscsi_encode_text_output(). Both call sites in
+iscsi_target_handle_csg_zero() (PHASE_SECURITY) and
+iscsi_target_handle_csg_one() (PHASE_OPERATIONAL) pass
+MAX_KEY_VALUE_PAIRS. On overflow the encoder logs the condition, calls
+iscsi_release_extra_responses() to drop queued records, and returns -1;
+both caller sites now emit ISCSI_STATUS_CLS_INITIATOR_ERR /
+ISCSI_LOGIN_STATUS_INIT_ERR via iscsit_tx_login_rsp() before returning,
+so the initiator sees an explicit failed-login response rather than a
+silent connection drop. (Prior to this patch only the PHASE_OPERATIONAL
+caller did that; the PHASE_SECURITY caller is converted to the same
+shape.)
+
+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 <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target_nego.c       |    7 ++
+ drivers/target/iscsi/iscsi_target_parameters.c |   62 +++++++++++++++++++------
+ drivers/target/iscsi/iscsi_target_parameters.h |    2 
+ 3 files changed, 55 insertions(+), 16 deletions(-)
+
+--- a/drivers/target/iscsi/iscsi_target_nego.c
++++ b/drivers/target/iscsi/iscsi_target_nego.c
+@@ -878,10 +878,14 @@ static int iscsi_target_handle_csg_zero(
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+-      if (ret < 0)
++      if (ret < 0) {
++              iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
++                              ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
++      }
+       if (!iscsi_check_negotiated_keys(conn->param_list)) {
+               if (conn->tpg->tpg_attrib.authentication &&
+@@ -949,6 +953,7 @@ static int iscsi_target_handle_csg_one(s
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+       if (ret < 0) {
+--- a/drivers/target/iscsi/iscsi_target_parameters.c
++++ b/drivers/target/iscsi/iscsi_target_parameters.c
+@@ -1421,19 +1421,42 @@ free_buffer:
+       return -1;
+ }
++/*
++ * Append "key=value" plus a trailing NUL into @textbuf at *@length.
++ * Returns 0 on success and advances *@length, or -EMSGSIZE if the
++ * record (including the NUL) would not fit in the remaining buffer.
++ */
++static int iscsi_encode_text_record(char *textbuf, u32 *length,
++                                  u32 textbuf_size,
++                                  const char *key, const char *value)
++{
++      int n;
++      u32 avail;
++
++      if (*length >= textbuf_size)
++              return -EMSGSIZE;
++
++      avail = textbuf_size - *length;
++      n = snprintf(textbuf + *length, avail, "%s=%s", key, value);
++      if (n < 0 || (u32)n + 1 > avail)
++              return -EMSGSIZE;
++
++      *length += n + 1;
++      return 0;
++}
++
+ int iscsi_encode_text_output(
+       u8 phase,
+       u8 sender,
+       char *textbuf,
+       u32 *length,
++      u32 textbuf_size,
+       struct iscsi_param_list *param_list,
+       bool keys_workaround)
+ {
+-      char *output_buf = NULL;
+       struct iscsi_extra_response *er;
+       struct iscsi_param *param;
+-
+-      output_buf = textbuf + *length;
++      int ret;
+       if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
+               return -1;
+@@ -1445,10 +1468,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_RESPONSE_SENT(param) &&
+                   !IS_PSTATE_REPLY_OPTIONAL(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_RESPONSE_SENT(param);
+                       pr_debug("Sending key: %s=%s\n",
+                               param->name, param->value);
+@@ -1458,10 +1483,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_ACCEPTOR(param) &&
+                   !IS_PSTATE_PROPOSER(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_PROPOSER(param);
+                       iscsi_check_proposer_for_optional_reply(param,
+                                                               keys_workaround);
+@@ -1471,14 +1498,21 @@ int iscsi_encode_text_output(
+       }
+       list_for_each_entry(er, &param_list->extra_response_list, er_list) {
+-              *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+-              *length += 1;
+-              output_buf = textbuf + *length;
++              ret = iscsi_encode_text_record(textbuf, length, textbuf_size,
++                                             er->key, er->value);
++              if (ret < 0)
++                      goto err_overflow;
+               pr_debug("Sending key: %s=%s\n", er->key, er->value);
+       }
+       iscsi_release_extra_responses(param_list);
+       return 0;
++
++err_overflow:
++      pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n",
++             textbuf_size);
++      iscsi_release_extra_responses(param_list);
++      return -1;
+ }
+ int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)
+--- a/drivers/target/iscsi/iscsi_target_parameters.h
++++ b/drivers/target/iscsi/iscsi_target_parameters.h
+@@ -46,7 +46,7 @@ extern struct iscsi_param *iscsi_find_pa
+ extern int iscsi_extract_key_value(char *, char **, char **);
+ extern int iscsi_update_param_value(struct iscsi_param *, char *);
+ extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
+-extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
++extern int iscsi_encode_text_output(u8, u8, char *, u32 *, u32,
+                       struct iscsi_param_list *, bool);
+ extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
+ extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
diff --git a/queue-5.10/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-5.10/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
new file mode 100644 (file)
index 0000000..a821043
--- /dev/null
@@ -0,0 +1,124 @@
+From stable+bounces-260882-greg=kroah.com@vger.kernel.org Sat Jun  6 18:36:49 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 09:05:41 -0400
+Subject: scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, John Garry <john.g.garry@oracle.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606130541.2924890-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ 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 <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2294,8 +2294,9 @@ iscsit_handle_text_cmd(struct iscsi_conn
+               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"
+@@ -2315,6 +2316,7 @@ iscsit_handle_text_cmd(struct iscsi_conn
+                                       " 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-5.10/selftests-mptcp-drop-nanoseconds-width-specifier.patch b/queue-5.10/selftests-mptcp-drop-nanoseconds-width-specifier.patch
new file mode 100644 (file)
index 0000000..4526f82
--- /dev/null
@@ -0,0 +1,69 @@
+From stable+bounces-256922-greg=kroah.com@vger.kernel.org Sat May 30 21:10:44 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 11:40:36 -0400
+Subject: selftests: mptcp: drop nanoseconds width specifier
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530154036.2741872-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ 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) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-6-701e96419f2f@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -421,7 +421,7 @@ do_transfer()
+       wait_local_port_listen "${listener_ns}" "${port}"
+       local start
+-      start=$(date +%s%3N)
++      start=$(date +%s%N)
+       ip netns exec ${connector_ns} ./mptcp_connect -t $timeout -p $port -s ${cl_proto} $extra_args $connect_addr < "$cin" > "$cout" &
+       local cpid=$!
+@@ -431,7 +431,7 @@ do_transfer()
+       local rets=$?
+       local stop
+-      stop=$(date +%s%3N)
++      stop=$(date +%s%N)
+       if $capture; then
+               sleep 1
+@@ -440,7 +440,7 @@ do_transfer()
+       fi
+       local duration
+-      duration=$((stop-start))
++      duration=$(((stop-start) / 1000000))
+       duration=$(printf "(duration %05sms)" $duration)
+       if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
+               echo "$duration [ FAIL ] client exit code $retc, server $rets" 1>&2
diff --git a/queue-5.10/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch b/queue-5.10/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
new file mode 100644 (file)
index 0000000..6b2afe4
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-260876-greg=kroah.com@vger.kernel.org Sat Jun  6 18:03:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:32:04 -0400
+Subject: serial: altera_jtaguart: handle uart_add_one_port() failures
+To: stable@vger.kernel.org
+Cc: Myeonghun Pak <mhun512@gmail.com>, stable <stable@kernel.org>, Ijae Kim <ae878000@gmail.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606123204.2861133-2-sashal@kernel.org>
+
+From: Myeonghun Pak <mhun512@gmail.com>
+
+[ Upstream commit ea66be25f0e934f49d24cd0c5845d13cdba3520b ]
+
+altera_jtaguart_probe() maps the register window before registering the
+UART port, but it ignores failures from uart_add_one_port(). If port
+registration fails, probe still returns success and the mapping remains
+live until a later remove path that is not part of probe failure cleanup.
+
+Return the uart_add_one_port() error and unmap the register window on
+that failure path.
+
+This issue was identified during our ongoing static-analysis research while
+reviewing kernel code.
+
+Fixes: 5bcd601049c6 ("serial: Add driver for the Altera JTAG UART")
+Cc: stable <stable@kernel.org>
+Co-developed-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
+Link: https://patch.msgid.link/20260512065837.79528-1-mhun512@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/altera_jtaguart.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/altera_jtaguart.c
++++ b/drivers/tty/serial/altera_jtaguart.c
+@@ -423,6 +423,7 @@ static int altera_jtaguart_probe(struct
+       struct resource *res_mem;
+       int i = pdev->id;
+       int irq;
++      int ret;
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+@@ -462,7 +463,11 @@ static int altera_jtaguart_probe(struct
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
+-      uart_add_one_port(&altera_jtaguart_driver, port);
++      ret = uart_add_one_port(&altera_jtaguart_driver, port);
++      if (ret) {
++              iounmap(port->membase);
++              return ret;
++      }
+       return 0;
+ }
diff --git a/queue-5.10/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch b/queue-5.10/serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
new file mode 100644 (file)
index 0000000..d214826
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-260875-greg=kroah.com@vger.kernel.org Sat Jun  6 18:03:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:32:03 -0400
+Subject: serial: altera_jtaguart: Use platform_get_irq_optional() to get the interrupt
+To: stable@vger.kernel.org
+Cc: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606123204.2861133-1-sashal@kernel.org>
+
+From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+[ Upstream commit 60302276caff50f907bc3391a364691ab4a21b43 ]
+
+platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static
+allocation of IRQ resources in DT core code, this causes an issue
+when using hierarchical interrupt domains using "interrupts" property
+in the node as this bypasses the hierarchical setup and messes up the
+irq chaining.
+
+In preparation for removal of static setup of IRQ resource from DT core
+code use platform_get_irq_optional().
+
+Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20211224142917.6966-7-prabhakar.mahadev-lad.rj@bp.renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ea66be25f0e9 ("serial: altera_jtaguart: handle uart_add_one_port() failures")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/altera_jtaguart.c |   11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/serial/altera_jtaguart.c
++++ b/drivers/tty/serial/altera_jtaguart.c
+@@ -420,8 +420,9 @@ static int altera_jtaguart_probe(struct
+       struct altera_jtaguart_platform_uart *platp =
+                       dev_get_platdata(&pdev->dev);
+       struct uart_port *port;
+-      struct resource *res_irq, *res_mem;
++      struct resource *res_mem;
+       int i = pdev->id;
++      int irq;
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+@@ -440,9 +441,11 @@ static int altera_jtaguart_probe(struct
+       else
+               return -ENODEV;
+-      res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+-      if (res_irq)
+-              port->irq = res_irq->start;
++      irq = platform_get_irq_optional(pdev, 0);
++      if (irq < 0 && irq != -ENXIO)
++              return irq;
++      if (irq > 0)
++              port->irq = irq;
+       else if (platp)
+               port->irq = platp->irq;
+       else
diff --git a/queue-5.10/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch b/queue-5.10/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
new file mode 100644 (file)
index 0000000..02229e3
--- /dev/null
@@ -0,0 +1,42 @@
+From stable+bounces-260874-greg=kroah.com@vger.kernel.org Sat Jun  6 18:03:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:32:00 -0400
+Subject: serial: qcom-geni: fix UART_RX_PAR_EN bit position
+To: stable@vger.kernel.org
+Cc: Prasanna S <prasanna.s@oss.qualcomm.com>, stable <stable@kernel.org>, Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606123200.2861082-3-sashal@kernel.org>
+
+From: Prasanna S <prasanna.s@oss.qualcomm.com>
+
+[ 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 <stable@kernel.org>
+Signed-off-by: Prasanna S <prasanna.s@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -43,7 +43,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)
index 5ec666068ee4a7e9645279c5b32f12da94ccef29..076feaadec0bc82c1005f23f4769aa3724c71b5c 100644 (file)
@@ -215,3 +215,102 @@ io_uring-poll-fix-signed-comparison-in-io_poll_get_ownership.patch
 ipvs-skip-ipv6-extension-headers-for-csum-checks.patch
 batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch
 batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch
+f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch
+smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch
+smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch
+net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch
+drm-nouveau-fix-u32-overflow-in-pushbuf-reloc-bounds-check.patch
+arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch
+thermal-core-fix-thermal-zone-governor-cleanup-issues.patch
+wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch
+alsa-aoa-use-guard-for-mutex-locks.patch
+alsa-aoa-i2sbus-clear-stale-prepared-state.patch
+media-rc-ttusbir-respect-dma-coherency-rules.patch
+alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch
+erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch
+media-rc-igorplugusb-heed-coherency-rules.patch
+sched-use-u64-for-bandwidth-ratio-calculations.patch
+alsa-core-fix-potential-data-race-at-fasync-handling.patch
+net-qrtr-ns-limit-the-maximum-number-of-lookups.patch
+net-qrtr-ns-change-servers-radix-tree-to-xarray.patch
+net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch
+net-qrtr-ns-limit-the-total-number-of-nodes.patch
+net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch
+mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.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
+bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.patch
+can-ucan-fix-typos-in-comments.patch
+can-ucan-fix-devres-lifetime.patch
+ktest-fixing-indentation-to-match-expected-pattern.patch
+ktest-fix-the-month-in-the-name-of-the-failure-directory.patch
+ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch
+alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch
+printk-add-print_hex_dump_devel.patch
+crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch
+acpi-scan-use-acpi_dev_put-in-object-add-error-paths.patch
+tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch
+wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
+usb-dwc3-move-guid-programming-after-phy-initialization.patch
+spi-syncuacer-fix-controller-deregistration.patch
+spi-sun4i-fix-controller-deregistration.patch
+spi-ti-qspi-fix-controller-deregistration.patch
+spi-zynq-qspi-fix-controller-deregistration.patch
+spi-sun6i-fix-controller-deregistration.patch
+spi-tegra20-sflash-fix-controller-deregistration.patch
+spi-tegra114-fix-controller-deregistration.patch
+spi-uniphier-fix-controller-deregistration.patch
+mm-hugetlb_cma-round-up-per_node-before-logging-it.patch
+fbcon-avoid-oob-font-access-if-console-rotation-fails.patch
+spi-topcliff-pch-fix-controller-deregistration.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
+pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
+dm-btree-improve-btree-residency.patch
+dm-thin-fix-metadata-refcount-underflow.patch
+btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
+smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
+mptcp-pm-add_addr-rtx-fix-potential-data-race.patch
+f2fs-fix-incorrect-file-address-mapping-when-inline-inode-is-unwritten.patch
+spi-st-ssc4-fix-controller-deregistration.patch
+spi-lantiq-ssc-fix-controller-deregistration.patch
+bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch
+bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch
+qed-use-the-bitmap-api-to-simplify-some-functions.patch
+qed-fix-double-free-in-qed_cxt_tables_alloc.patch
+net-remove-redundant-if-statements.patch
+netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch
+bluetooth-consolidate-code-around-sk_alloc-into-a-helper-function.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
+ice-fix-vf-queue-configuration-with-low-mtu-values.patch
+use-less-confusing-names-for-iov_iter-direction-initializers.patch
+selftests-mptcp-drop-nanoseconds-width-specifier.patch
+mptcp-do-not-drop-partial-packets.patch
+octeontx2-pf-avoid-double-free-of-pool-stack-on-aq-init-failure.patch
+octeontx2-af-add-validation-for-lmac-type.patch
+octeontx2-af-replace-deprecated-strncpy-with-strscpy.patch
+octeontx2-af-cgx-add-bounds-check-to-cgx_speed_mbps-index.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
+scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.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
+serial-altera_jtaguart-use-platform_get_irq_optional-to-get-the-interrupt.patch
+serial-altera_jtaguart-handle-uart_add_one_port-failures.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-huge_memory-update-file-pmd-counter-before-folio_put.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-5.10/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch b/queue-5.10/smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch
new file mode 100644 (file)
index 0000000..398196f
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-241001-greg=kroah.com@vger.kernel.org Fri Apr 24 21:50:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 12:20:14 -0400
+Subject: smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424162014.2284352-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit a58c5af19ff0d6f44f6e9fe31e33a2c92223f77e ]
+
+smb2_ioctl_query_info() has two response-copy branches: PASSTHRU_FSCTL
+and the default QUERY_INFO path.  The QUERY_INFO branch clamps
+qi.input_buffer_length to the server-reported OutputBufferLength and then
+copies qi.input_buffer_length bytes from qi_rsp->Buffer to userspace, but
+it never verifies that the flexible-array payload actually fits within
+rsp_iov[1].iov_len.
+
+A malicious server can return OutputBufferLength larger than the actual
+QUERY_INFO response, causing copy_to_user() to walk past the response
+buffer and expose adjacent kernel heap to userspace.
+
+Guard the QUERY_INFO copy with a bounds check on the actual Buffer
+payload.  Use struct_size(qi_rsp, Buffer, qi.input_buffer_length)
+rather than an open-coded addition so the guard cannot overflow on
+32-bit builds.
+
+Fixes: f5778c398713 ("SMB3: Allow SMB3 FSCTL queries to be sent to server from tools")
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2ops.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -1720,6 +1720,12 @@ smb2_ioctl_query_info(const unsigned int
+               qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
+               if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length)
+                       qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength);
++              if (qi.input_buffer_length > 0 &&
++                  struct_size(qi_rsp, Buffer, qi.input_buffer_length) >
++                  rsp_iov[1].iov_len) {
++                      rc = -EFAULT;
++                      goto out;
++              }
+               if (copy_to_user(&pqi->input_buffer_length,
+                                &qi.input_buffer_length,
+                                sizeof(qi.input_buffer_length))) {
diff --git a/queue-5.10/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch b/queue-5.10/smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch
new file mode 100644 (file)
index 0000000..145a9d4
--- /dev/null
@@ -0,0 +1,46 @@
+From stable+bounces-240986-greg=kroah.com@vger.kernel.org Fri Apr 24 20:16:02 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:45:56 -0400
+Subject: smb: client: require a full NFS mode SID before reading mode bits
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424144556.2184965-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 2757ad3e4b6f9e0fed4c7739594e702abc5cab21 ]
+
+parse_dacl() treats an ACE SID matching sid_unix_NFS_mode as an NFS
+mode SID and reads sid.sub_auth[2] to recover the mode bits.
+
+That assumes the ACE carries three subauthorities, but compare_sids()
+only compares min(a, b) subauthorities.  A malicious server can return
+an ACE with num_subauth = 2 and sub_auth[] = {88, 3}, which still
+matches sid_unix_NFS_mode and then drives the sub_auth[2] read four
+bytes past the end of the ACE.
+
+Require num_subauth >= 3 before treating the ACE as an NFS mode SID.
+This keeps the fix local to the special-SID mode path without changing
+compare_sids() semantics for the rest of cifsacl.
+
+Fixes: e2f8fbfb8d09 ("cifs: get mode bits from special sid on stat")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cifsacl.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -757,6 +757,7 @@ static void parse_dacl(struct cifs_acl *
+                       dump_ace(ppace[i], end_of_acl);
+ #endif
+                       if (mode_from_special_sid &&
++                          ppace[i]->sid.num_subauth >= 3 &&
+                           (compare_sids(&(ppace[i]->sid),
+                                         &sid_unix_NFS_mode) == 0)) {
+                               /*
diff --git a/queue-5.10/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch b/queue-5.10/smb-client-use-fullsessionkey-for-aes-256-encryption-key-derivation.patch
new file mode 100644 (file)
index 0000000..829f301
--- /dev/null
@@ -0,0 +1,146 @@
+From stable+bounces-249163-greg=kroah.com@vger.kernel.org Mon May 18 06:54:12 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 May 2026 21:24:03 -0400
+Subject: smb: client: Use FullSessionKey for AES-256 encryption key derivation
+To: stable@vger.kernel.org
+Cc: Piyush Sachdeva <s.piyush1024@gmail.com>, Bharath SM <bharathsm@microsoft.com>, Piyush Sachdeva <psachdeva@microsoft.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260518012403.482990-1-sashal@kernel.org>
+
+From: Piyush Sachdeva <s.piyush1024@gmail.com>
+
+[ 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: <stable@vger.kernel.org>
+Reviewed-by: Bharath SM <bharathsm@microsoft.com>
+Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
+Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ adapted to old crypto_shash API ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2transport.c |   36 ++++++++++++++++++++++++++----------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+--- a/fs/cifs/smb2transport.c
++++ b/fs/cifs/smb2transport.c
+@@ -305,7 +305,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};
+@@ -326,7 +327,7 @@ static int generate_key(struct cifs_ses
+       }
+       rc = crypto_shash_setkey(server->secmech.hmacsha256,
+-              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;
+@@ -407,10 +408,9 @@ static int
+ generate_smb3signingkey(struct cifs_ses *ses,
+                       const struct derivation_triplet *ptriplet)
+ {
+-      int rc;
+-#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
++      unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE;
+       struct TCP_Server_Info *server = ses->server;
+-#endif
++      int rc;
+       /*
+        * All channels use the same encryption/decryption keys but
+@@ -426,30 +426,46 @@ generate_smb3signingkey(struct cifs_ses
+               rc = generate_key(ses, ptriplet->signing.label,
+                                 ptriplet->signing.context,
+                                 cifs_ses_binding_channel(ses)->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;
++
+               memcpy(ses->chans[0].signkey, ses->smb3signingkey,
+                      SMB3_SIGN_KEY_SIZE);
+               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;
+       }
+@@ -464,7 +480,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-5.10/spi-lantiq-ssc-fix-controller-deregistration.patch b/queue-5.10/spi-lantiq-ssc-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..1d7ec3f
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-250018-greg=kroah.com@vger.kernel.org Wed May 20 21:35:10 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 11:24:08 -0400
+Subject: spi: lantiq-ssc: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Hauke Mehrtens <hauke@hauke-m.de>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520152408.3943826-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <hauke@hauke-m.de>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260409120419.388546-17-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ adapted spi_controller/host naming to spi_master/master and preserved the int-returning remove() with trailing return 0 ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1003,7 +1003,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;
+@@ -1027,6 +1027,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);
+@@ -1037,6 +1041,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-5.10/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch b/queue-5.10/spi-qup-fix-error-pointer-deref-after-dma-setup-failure.patch
new file mode 100644 (file)
index 0000000..475d1c4
--- /dev/null
@@ -0,0 +1,47 @@
+From stable+bounces-259521-greg=kroah.com@vger.kernel.org Mon Jun  1 16:21:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 06:51:08 -0400
+Subject: spi: qup: fix error pointer deref after DMA setup failure
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601105108.378152-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <johan@kernel.org>
+Link: https://patch.msgid.link/20260512074334.914735-1-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-qup.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -969,8 +969,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-5.10/spi-qup-switch-to-use-modern-name.patch b/queue-5.10/spi-qup-switch-to-use-modern-name.patch
new file mode 100644 (file)
index 0000000..533e8cf
--- /dev/null
@@ -0,0 +1,459 @@
+From stable+bounces-259520-greg=kroah.com@vger.kernel.org Mon Jun  1 16:21:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon,  1 Jun 2026 06:51:07 -0400
+Subject: spi: qup: switch to use modern name
+To: stable@vger.kernel.org
+Cc: Yang Yingliang <yangyingliang@huawei.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260601105108.378152-1-sashal@kernel.org>
+
+From: Yang Yingliang <yangyingliang@huawei.com>
+
+[ Upstream commit 597442ff4f6226206b7cc28b86eb2be0ae9c6418 ]
+
+Change legacy name master to modern name host or controller.
+
+No functional changed.
+
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+Link: https://lore.kernel.org/r/20230818093154.1183529-10-yangyingliang@huawei.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: a7e8f3efd50a ("spi: qup: fix error pointer deref after DMA setup failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-qup.c |  164 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 82 insertions(+), 82 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;
+@@ -660,7 +660,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) {
+@@ -681,9 +681,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;
+@@ -694,7 +694,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;
+@@ -842,11 +842,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;
+@@ -880,21 +880,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;
+@@ -902,7 +902,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;
+@@ -915,30 +915,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;
+       }
+@@ -953,13 +953,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;
+@@ -968,9 +968,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;
+ }
+@@ -980,7 +980,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)
+@@ -994,7 +994,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;
+@@ -1030,32 +1030,32 @@ 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_master(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->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->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;
+@@ -1063,16 +1063,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);
+@@ -1150,7 +1150,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;
+@@ -1162,17 +1162,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 */
+@@ -1188,8 +1188,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;
+@@ -1214,8 +1214,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)) {
+@@ -1223,7 +1223,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;
+@@ -1238,8 +1238,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);
+@@ -1256,7 +1256,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;
+@@ -1271,8 +1271,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);
+@@ -1290,7 +1290,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-5.10/spi-st-ssc4-fix-controller-deregistration.patch b/queue-5.10/spi-st-ssc4-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..c53dfb0
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-250013-greg=kroah.com@vger.kernel.org Wed May 20 20:54:32 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 May 2026 11:18:24 -0400
+Subject: spi: st-ssc4: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Lee Jones <lee@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260520151824.3913740-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <lee@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-18-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ changed spi_controller/host API calls to spi_master/master equivalents ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -372,7 +372,7 @@ static int spi_st_probe(struct platform_
+       platform_set_drvdata(pdev, master);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register master\n");
+               goto rpm_disable;
+@@ -394,10 +394,16 @@ static int spi_st_remove(struct platform
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_st *spi_st = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_disable(&pdev->dev);
+       clk_disable_unprepare(spi_st->clk);
++      spi_master_put(master);
++
+       pinctrl_pm_select_sleep_state(&pdev->dev);
+       return 0;
diff --git a/queue-5.10/spi-sun4i-fix-controller-deregistration.patch b/queue-5.10/spi-sun4i-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..bb22eb3
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247017-greg=kroah.com@vger.kernel.org Thu May 14 00:10:21 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 14:34:01 -0400
+Subject: spi: sun4i: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Maxime Ripard <mripard@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513183401.3927454-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <mripard@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-19-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed `host`/`spi_controller` to `master`/`spi_master` and kept `int` return type with `return 0` in remove ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               goto err_pm_disable;
+@@ -521,8 +521,16 @@ err_free_master:
+ static int sun4i_spi_remove(struct platform_device *pdev)
+ {
++      struct spi_master *master = platform_get_drvdata(pdev);
++
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_force_suspend(&pdev->dev);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.10/spi-sun6i-fix-controller-deregistration.patch b/queue-5.10/spi-sun6i-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..e744e2c
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247111-greg=kroah.com@vger.kernel.org Thu May 14 10:28:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 00:58:46 -0400
+Subject: spi: sun6i: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Maxime Ripard <mripard@kernel.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514045846.24524-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <mripard@kernel.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-20-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller/host APIs to spi_master APIs, dropped non-existent DMA cleanup, and kept int return type ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-sun6i.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -512,7 +512,7 @@ static int sun6i_spi_probe(struct platfo
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&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;
+@@ -530,8 +530,16 @@ err_free_master:
+ static int sun6i_spi_remove(struct platform_device *pdev)
+ {
++      struct spi_master *master = platform_get_drvdata(pdev);
++
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_force_suspend(&pdev->dev);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.10/spi-syncuacer-fix-controller-deregistration.patch b/queue-5.10/spi-syncuacer-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..70668c2
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-247016-greg=kroah.com@vger.kernel.org Thu May 14 00:10:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 14:33:51 -0400
+Subject: spi: syncuacer: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Masahisa Kojima <masahisa.kojima@linaro.org>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513183351.3927329-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <masahisa.kojima@linaro.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-21-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller/host to spi_master/master and kept int return type with `return 0;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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_master(sspi->dev, master);
++      ret = spi_register_master(master);
+       if (ret)
+               goto disable_pm;
+@@ -740,10 +740,16 @@ static int synquacer_spi_remove(struct p
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       pm_runtime_disable(sspi->dev);
+       clk_disable_unprepare(sspi->clk);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.10/spi-tegra114-fix-controller-deregistration.patch b/queue-5.10/spi-tegra114-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..ca5512e
--- /dev/null
@@ -0,0 +1,59 @@
+From stable+bounces-247193-greg=kroah.com@vger.kernel.org Thu May 14 18:10:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 08:40:30 -0400
+Subject: spi: tegra114: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jingoo Han <jg1.han@samsung.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514124030.210588-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <jg1.han@samsung.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-22-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1422,7 +1422,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;
+@@ -1448,6 +1448,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)
+@@ -1460,6 +1464,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-5.10/spi-tegra20-sflash-fix-controller-deregistration.patch b/queue-5.10/spi-tegra20-sflash-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..895d6af
--- /dev/null
@@ -0,0 +1,58 @@
+From stable+bounces-247192-greg=kroah.com@vger.kernel.org Thu May 14 18:12:25 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 08:40:16 -0400
+Subject: spi: tegra20-sflash: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jingoo Han <jg1.han@samsung.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514124016.210394-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <jg1.han@samsung.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-23-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ 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 <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -508,7 +508,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;
+@@ -531,12 +531,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-5.10/spi-ti-qspi-fix-controller-deregistration.patch b/queue-5.10/spi-ti-qspi-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..177dd34
--- /dev/null
@@ -0,0 +1,68 @@
+From stable+bounces-247093-greg=kroah.com@vger.kernel.org Thu May 14 08:40:12 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 23:10:05 -0400
+Subject: spi: ti-qspi: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Sebastian Andrzej Siewior <bigeasy@linutronix.de>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514031006.4117436-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <bigeasy@linutronix.de>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-24-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_controller_*/host APIs to spi_master_*/master and kept remove() returning int ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-ti-qspi.c |   11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-ti-qspi.c
++++ b/drivers/spi/spi-ti-qspi.c
+@@ -895,7 +895,7 @@ no_dma:
+       qspi->mmap_enabled = false;
+       qspi->current_cs = -1;
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (!ret)
+               return 0;
+@@ -910,17 +910,18 @@ free_master:
+ static int 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;
++      spi_master_get(qspi->master);
++
++      spi_unregister_master(qspi->master);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       ti_qspi_dma_cleanup(qspi);
++      spi_master_put(qspi->master);
++
+       return 0;
+ }
diff --git a/queue-5.10/spi-topcliff-pch-fix-controller-deregistration.patch b/queue-5.10/spi-topcliff-pch-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..ade02b5
--- /dev/null
@@ -0,0 +1,48 @@
+From stable+bounces-247800-greg=kroah.com@vger.kernel.org Fri May 15 20:21:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 10:48:54 -0400
+Subject: spi: topcliff-pch: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Masayuki Ohtake <masa-korg@dsn.okisemi.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515144854.3250320-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 5d6f477d6fc0767c57c5e1e6f55a1662820eef87 ]
+
+Make sure to deregister the controller before disabling and releasing
+underlying resources like interrupts and DMA during driver unbind.
+
+Fixes: e8b17b5b3f30 ("spi/topcliff: Add topcliff platform controller hub (PCH) spi bus driver")
+Cc: stable@vger.kernel.org     # 2.6.37
+Cc: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260414134319.978196-8-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed data->host to data->master and kept return 0 ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-topcliff-pch.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-topcliff-pch.c
++++ b/drivers/spi/spi-topcliff-pch.c
+@@ -1449,11 +1449,16 @@ static int pch_spi_pd_remove(struct plat
+               free_irq(board_dat->pdev->irq, data);
+       }
++      spi_controller_get(data->master);
++
++      spi_unregister_controller(data->master);
++
+       if (use_dma)
+               pch_free_dma_buf(board_dat, data);
+       pci_iounmap(board_dat->pdev, data->io_remap_addr);
+-      spi_unregister_master(data->master);
++
++      spi_controller_put(data->master);
+       return 0;
+ }
diff --git a/queue-5.10/spi-uniphier-fix-controller-deregistration.patch b/queue-5.10/spi-uniphier-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..93c499d
--- /dev/null
@@ -0,0 +1,63 @@
+From stable+bounces-247202-greg=kroah.com@vger.kernel.org Thu May 14 18:37:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 09:06:38 -0400
+Subject: spi: uniphier: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Keiji Hayashibara <hayashibara.keiji@socionext.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514130638.228220-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <hayashibara.keiji@socionext.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-25-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ renamed spi_*_controller/host APIs to spi_*_master/master aliases and kept the pre-existing clk_disable_unprepare() after unregister ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -751,7 +751,7 @@ static int uniphier_spi_probe(struct pla
+       master->max_dma_len = min(dma_tx_burst, dma_rx_burst);
+-      ret = devm_spi_register_master(&pdev->dev, master);
++      ret = spi_register_master(master);
+       if (ret)
+               goto out_release_dma;
+@@ -780,6 +780,10 @@ static int uniphier_spi_remove(struct pl
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
++      spi_master_get(master);
++
++      spi_unregister_master(master);
++
+       if (master->dma_tx)
+               dma_release_channel(master->dma_tx);
+       if (master->dma_rx)
+@@ -787,6 +791,8 @@ static int uniphier_spi_remove(struct pl
+       clk_disable_unprepare(priv->clk);
++      spi_master_put(master);
++
+       return 0;
+ }
diff --git a/queue-5.10/spi-zynq-qspi-fix-controller-deregistration.patch b/queue-5.10/spi-zynq-qspi-fix-controller-deregistration.patch
new file mode 100644 (file)
index 0000000..84b2f12
--- /dev/null
@@ -0,0 +1,78 @@
+From stable+bounces-247098-greg=kroah.com@vger.kernel.org Thu May 14 09:44:27 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 May 2026 00:14:18 -0400
+Subject: spi: zynq-qspi: fix controller deregistration
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260514041418.4189826-1-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ 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 <naga.sureshkumar.relli@xilinx.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260410081757.503099-27-johan@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+[ kept int-returning remove() with manual clk_disable_unprepare() calls and routed probe error through existing clk_dis_all cascade instead of upstream's remove_ctlr label ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -652,7 +652,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);
+@@ -722,9 +722,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, "spi_register_master failed\n");
++              dev_err(&pdev->dev, "failed to register controller\n");
+               goto clk_dis_all;
+       }
+@@ -752,13 +752,20 @@ remove_master:
+  */
+ static int 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);
+       clk_disable_unprepare(xqspi->refclk);
+       clk_disable_unprepare(xqspi->pclk);
++      spi_controller_put(ctlr);
++
+       return 0;
+ }
diff --git a/queue-5.10/thermal-core-fix-thermal-zone-governor-cleanup-issues.patch b/queue-5.10/thermal-core-fix-thermal-zone-governor-cleanup-issues.patch
new file mode 100644 (file)
index 0000000..438c0b7
--- /dev/null
@@ -0,0 +1,69 @@
+From stable+bounces-242197-greg=kroah.com@vger.kernel.org Fri May  1 01:17:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 15:46:54 -0400
+Subject: thermal: core: Fix thermal zone governor cleanup issues
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430194654.1996047-1-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 41ff66baf81c6541f4f985dd7eac4494d03d9440 ]
+
+If thermal_zone_device_register_with_trips() fails after adding
+a thermal governor to the thermal zone being registered, the
+governor is not removed from it as appropriate which may lead to
+a memory leak.
+
+In turn, thermal_zone_device_unregister() calls thermal_set_governor()
+without acquiring the thermal zone lock beforehand which may race with
+a governor update via sysfs and may lead to a use-after-free in that
+case.
+
+Address these issues by adding two thermal_set_governor() calls, one to
+thermal_release() to remove the governor from the given thermal zone,
+and one to the thermal zone registration error path to cover failures
+preceding the thermal zone device registration.
+
+Fixes: e33df1d2f3a0 ("thermal: let governors have private data for each thermal zone")
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/5092923.31r3eYUQgx@rafael.j.wysocki
+[ adapted context for missing mutex_destroy/complete ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thermal/thermal_core.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -986,6 +986,7 @@ static void thermal_release(struct devic
+                    sizeof("thermal_zone") - 1)) {
+               tz = to_thermal_zone(dev);
+               thermal_zone_destroy_device_groups(tz);
++              thermal_set_governor(tz, NULL);
+               kfree(tz);
+       } else if (!strncmp(dev_name(dev), "cooling_device",
+                           sizeof("cooling_device") - 1)) {
+@@ -1447,8 +1448,10 @@ thermal_zone_device_register(const char
+       /* sys I/F */
+       /* Add nodes that are always present via .groups */
+       result = thermal_zone_create_device_groups(tz, mask);
+-      if (result)
++      if (result) {
++              thermal_set_governor(tz, NULL);
+               goto remove_id;
++      }
+       /* A new thermal zone needs to be updated anyway. */
+       atomic_set(&tz->need_update, 1);
+@@ -1571,8 +1574,6 @@ void thermal_zone_device_unregister(stru
+       cancel_delayed_work_sync(&tz->poll_queue);
+-      thermal_set_governor(tz, NULL);
+-
+       thermal_remove_hwmon_sysfs(tz);
+       ida_simple_remove(&thermal_tz_ida, tz->id);
+       ida_destroy(&tz->ida);
diff --git a/queue-5.10/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-5.10/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch
new file mode 100644 (file)
index 0000000..6d9065a
--- /dev/null
@@ -0,0 +1,112 @@
+From stable+bounces-260840-greg=kroah.com@vger.kernel.org Sat Jun  6 07:49:11 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:18:56 -0400
+Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Mika Westerberg <mika.westerberg@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606021856.2488432-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ 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 <michael.bommarito@gmail.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch b/queue-5.10/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch
new file mode 100644 (file)
index 0000000..bfc7210
--- /dev/null
@@ -0,0 +1,56 @@
+From stable+bounces-245167-greg=kroah.com@vger.kernel.org Mon May 11 15:09:52 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 11 May 2026 05:11:47 -0400
+Subject: tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func()
+To: stable@vger.kernel.org
+Cc: David Carlier <devnexen@gmail.com>, Masami Hiramatsu <mhiramat@kernel.org>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com>, "Steven Rostedt (Google)" <rostedt@goodmis.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260511091147.1436423-1-sashal@kernel.org>
+
+From: David Carlier <devnexen@gmail.com>
+
+[ 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 <mhiramat@kernel.org>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Link: https://patch.msgid.link/20260413190601.21993-1-devnexen@gmail.com
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+[ changed `tp->ext->unregfunc` to `tp->unregfunc` to match older struct layout ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/tracepoint.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/kernel/tracepoint.c
++++ b/kernel/tracepoint.c
+@@ -358,6 +358,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-5.10/tracing-probes-limit-size-of-event-probe-to-3k.patch b/queue-5.10/tracing-probes-limit-size-of-event-probe-to-3k.patch
new file mode 100644 (file)
index 0000000..53a093d
--- /dev/null
@@ -0,0 +1,68 @@
+From stable+bounces-247838-greg=kroah.com@vger.kernel.org Fri May 15 21:20:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 May 2026 11:36:12 -0400
+Subject: tracing/probes: Limit size of event probe to 3K
+To: stable@vger.kernel.org
+Cc: Steven Rostedt <rostedt@goodmis.org>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com>, "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260515153612.3302611-1-sashal@kernel.org>
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ 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 <mathieu.desnoyers@efficios.com>
+Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+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 <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/trace_probe.c |    5 +++++
+ kernel/trace/trace_probe.h |    4 +++-
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -610,6 +610,11 @@ static int traceprobe_parse_probe_arg_bo
+       parg->offset = *size;
+       *size += parg->type->size * (parg->count ?: 1);
++      if (*size > MAX_PROBE_EVENT_SIZE) {
++              trace_probe_log_err(offset, EVENT_TOO_BIG);
++              return -E2BIG;
++      }
++
+       if (parg->count) {
+               len = strlen(parg->type->fmttype) + 6;
+               parg->fmt = kmalloc(len, GFP_KERNEL);
+--- 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"
+@@ -439,7 +440,8 @@ extern int traceprobe_define_arg_fields(
+       C(FAIL_REG_PROBE,       "Failed to register probe event"),\
+       C(DIFF_PROBE_TYPE,      "Probe type is different from existing probe"),\
+       C(DIFF_ARG_TYPE,        "Argument type or name is different from existing probe"),\
+-      C(SAME_PROBE,           "There is already the exact same probe event"),
++      C(SAME_PROBE,           "There is already the exact same probe event"),\
++      C(EVENT_TOO_BIG,        "Event too big (too many fields?)"),
+ #undef C
+ #define C(a, b)               TP_ERR_##a
diff --git a/queue-5.10/tty-serial-qcom-geni-serial-align-define-values.patch b/queue-5.10/tty-serial-qcom-geni-serial-align-define-values.patch
new file mode 100644 (file)
index 0000000..43eab50
--- /dev/null
@@ -0,0 +1,115 @@
+From stable+bounces-260873-greg=kroah.com@vger.kernel.org Sat Jun  6 18:02:54 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:31:59 -0400
+Subject: tty: serial: qcom-geni-serial: align #define values
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606123200.2861082-2-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 6cde11dbf4b65170eeefba48df730c93d75e01a3 ]
+
+Keep the #define symbols aligned for better readability.
+
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20221229155030.418800-5-brgl@bgdev.pl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -35,57 +35,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-5.10/tty-serial-qcom-geni-serial-remove-unused-symbols.patch b/queue-5.10/tty-serial-qcom-geni-serial-remove-unused-symbols.patch
new file mode 100644 (file)
index 0000000..a57f2e6
--- /dev/null
@@ -0,0 +1,73 @@
+From stable+bounces-260872-greg=kroah.com@vger.kernel.org Sat Jun  6 18:02:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 08:31:58 -0400
+Subject: tty: serial: qcom-geni-serial: remove unused symbols
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606123200.2861082-1-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 68c6bd92c86cbc4937834c79963b27c77ee3bf51 ]
+
+Drop all unused symbols from the driver.
+
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20221229155030.418800-4-brgl@bgdev.pl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: ca2584d841b6 ("serial: qcom-geni: fix UART_RX_PAR_EN bit position")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -38,20 +38,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 */
+@@ -62,12 +53,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)
+@@ -76,11 +64,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-5.10/udf-fix-partition-descriptor-append-bookkeeping.patch b/queue-5.10/udf-fix-partition-descriptor-append-bookkeeping.patch
new file mode 100644 (file)
index 0000000..cbec57c
--- /dev/null
@@ -0,0 +1,61 @@
+From stable+bounces-244858-greg=kroah.com@vger.kernel.org Sat May  9 06:05:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  8 May 2026 20:35:37 -0400
+Subject: udf: fix partition descriptor append bookkeeping
+To: stable@vger.kernel.org
+Cc: Seohyeon Maeng <bioloidgp@gmail.com>, Jan Kara <jack@suse.cz>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509003537.2360522-1-sashal@kernel.org>
+
+From: Seohyeon Maeng <bioloidgp@gmail.com>
+
+[ 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 <bioloidgp@gmail.com>
+Link: https://patch.msgid.link/20260310081652.21220-1-bioloidgp@gmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+[ replaced kzalloc_objs() helper with equivalent kcalloc() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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-5.10/usb-dwc3-move-guid-programming-after-phy-initialization.patch b/queue-5.10/usb-dwc3-move-guid-programming-after-phy-initialization.patch
new file mode 100644 (file)
index 0000000..aee2f95
--- /dev/null
@@ -0,0 +1,63 @@
+From sashal@kernel.org Wed May 13 19:39:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 10:09:13 -0400
+Subject: usb: dwc3: Move GUID programming after PHY initialization
+To: stable@vger.kernel.org
+Cc: Selvarasu Ganesan <selvarasu.g@samsung.com>, stable <stable@kernel.org>, Pritam Manohar Sutar <pritam.sutar@samsung.com>, Thinh Nguyen <Thinh.Nguyen@synopsys.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513140913.3746791-1-sashal@kernel.org>
+
+From: Selvarasu Ganesan <selvarasu.g@samsung.com>
+
+[ 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 <stable@kernel.org>
+Reported-by: Pritam Manohar Sutar <pritam.sutar@samsung.com>
+Signed-off-by: Selvarasu Ganesan <selvarasu.g@samsung.com>
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ adapted dwc3_writel(dwc, ...) to dwc3_writel(dwc->regs, ...) ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -978,12 +978,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;
+@@ -1023,6 +1017,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-5.10/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-5.10/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
new file mode 100644 (file)
index 0000000..8592bf0
--- /dev/null
@@ -0,0 +1,69 @@
+From stable+bounces-260839-greg=kroah.com@vger.kernel.org Sat Jun  6 07:48:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri,  5 Jun 2026 22:18:44 -0400
+Subject: usb: typec: ucsi: Check if power role change actually happened before handling
+To: stable@vger.kernel.org
+Cc: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>, stable <stable@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606021844.2487798-1-sashal@kernel.org>
+
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+
+[ 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 <stable@kernel.org>
+Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change")
+Signed-off-by: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Reported-and-tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -656,7 +656,7 @@ static void ucsi_handle_connector_change
+       struct ucsi *ucsi = con->ucsi;
+       struct ucsi_connector_status pre_ack_status;
+       struct ucsi_connector_status post_ack_status;
+-      enum typec_role role;
++      enum typec_role role, prev_role;
+       u16 inferred_changes;
+       u16 changed_flags;
+       u64 command;
+@@ -692,6 +692,8 @@ static void ucsi_handle_connector_change
+        * short transitional changes.
+        */
++      prev_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
++
+       /* 1. First UCSI_GET_CONNECTOR_STATUS */
+       command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command(ucsi, command, &pre_ack_status,
+@@ -769,7 +771,8 @@ static void ucsi_handle_connector_change
+               ucsi_port_psy_changed(con);
+       }
+-      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);
+               /* Complete pending power role swap */
diff --git a/queue-5.10/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch b/queue-5.10/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch
new file mode 100644 (file)
index 0000000..457fdca
--- /dev/null
@@ -0,0 +1,43 @@
+From stable+bounces-260897-greg=kroah.com@vger.kernel.org Sat Jun  6 19:54:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat,  6 Jun 2026 10:24:04 -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 <myrrhperiwinkle@qtmlabs.xyz>, stable <stable@kernel.org>, Sergey Senozhatsky <senozhatsky@chromium.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260606142405.3108014-1-sashal@kernel.org>
+
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+
+[ 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 <stable@kernel.org>
+Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change")
+Signed-off-by: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Reported-and-tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-2-6f1239535187@qtmlabs.xyz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -775,6 +775,12 @@ static void ucsi_handle_connector_change
+           role != prev_role) {
+               typec_set_pwr_role(con->port, role);
++              /* 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))
+                       complete(&con->complete);
diff --git a/queue-5.10/use-less-confusing-names-for-iov_iter-direction-initializers.patch b/queue-5.10/use-less-confusing-names-for-iov_iter-direction-initializers.patch
new file mode 100644 (file)
index 0000000..035a55b
--- /dev/null
@@ -0,0 +1,1420 @@
+From stable+bounces-256902-greg=kroah.com@vger.kernel.org Sat May 30 19:50:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 May 2026 10:19:23 -0400
+Subject: use less confusing names for iov_iter direction initializers
+To: stable@vger.kernel.org
+Cc: Al Viro <viro@zeniv.linux.org.uk>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260530141926.2406669-1-sashal@kernel.org>
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[ Upstream commit de4eda9de2d957ef2d6a8365a01e26a435e958cb ]
+
+READ/WRITE proved to be actively confusing - the meanings are
+"data destination, as used with read(2)" and "data source, as
+used with write(2)", but people keep interpreting those as
+"we read data from it" and "we write data to it", i.e. exactly
+the wrong way.
+
+Call them ITER_DEST and ITER_SOURCE - at least that is harder
+to misinterpret...
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Stable-dep-of: a4f0b001782b ("vsock/virtio: reset connection on receiving queue overflow")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/cpu/microcode/intel.c    |    2 +-
+ crypto/testmgr.c                         |    4 ++--
+ drivers/block/drbd/drbd_main.c           |    2 +-
+ drivers/block/drbd/drbd_receiver.c       |    2 +-
+ drivers/block/loop.c                     |   14 +++++++-------
+ drivers/block/nbd.c                      |   10 +++++-----
+ drivers/char/random.c                    |    4 ++--
+ drivers/fsi/fsi-sbefifo.c                |    6 +++---
+ drivers/infiniband/ulp/rtrs/rtrs-clt.c   |    2 +-
+ drivers/isdn/mISDN/l1oip_core.c          |    2 +-
+ drivers/misc/vmw_vmci/vmci_queue_pair.c  |    6 +++---
+ drivers/net/ppp/ppp_generic.c            |    2 +-
+ drivers/nvme/host/tcp.c                  |    4 ++--
+ drivers/nvme/target/io-cmd-file.c        |    4 ++--
+ drivers/nvme/target/tcp.c                |    2 +-
+ drivers/scsi/sg.c                        |    2 +-
+ drivers/target/iscsi/iscsi_target_util.c |    4 ++--
+ drivers/target/target_core_file.c        |    2 +-
+ drivers/usb/usbip/usbip_common.c         |    2 +-
+ drivers/vhost/net.c                      |    6 +++---
+ drivers/vhost/scsi.c                     |   10 +++++-----
+ drivers/vhost/vhost.c                    |    6 +++---
+ drivers/vhost/vringh.c                   |    4 ++--
+ drivers/vhost/vsock.c                    |    4 ++--
+ drivers/xen/pvcalls-back.c               |    8 ++++----
+ fs/9p/vfs_addr.c                         |    4 ++--
+ fs/9p/vfs_dir.c                          |    2 +-
+ fs/9p/xattr.c                            |    4 ++--
+ fs/afs/cmservice.c                       |    2 +-
+ fs/afs/internal.h                        |    4 ++--
+ fs/afs/rxrpc.c                           |   12 ++++++------
+ fs/aio.c                                 |    4 ++--
+ fs/ceph/file.c                           |    4 ++--
+ fs/cifs/connect.c                        |    6 +++---
+ fs/cifs/file.c                           |    4 ++--
+ fs/cifs/smb2ops.c                        |    4 ++--
+ fs/cifs/transport.c                      |    6 +++---
+ fs/nfsd/vfs.c                            |    4 ++--
+ fs/ocfs2/cluster/tcp.c                   |    2 +-
+ fs/orangefs/inode.c                      |    6 +++---
+ fs/read_write.c                          |   12 ++++++------
+ fs/seq_file.c                            |    2 +-
+ fs/splice.c                              |   10 +++++-----
+ include/linux/uio.h                      |    3 +++
+ mm/madvise.c                             |    2 +-
+ mm/page_io.c                             |    2 +-
+ mm/process_vm_access.c                   |    2 +-
+ net/9p/client.c                          |    2 +-
+ net/bluetooth/6lowpan.c                  |    2 +-
+ net/bluetooth/a2mp.c                     |    2 +-
+ net/bluetooth/smp.c                      |    2 +-
+ net/ipv4/tcp.c                           |    2 +-
+ net/netfilter/ipvs/ip_vs_sync.c          |    2 +-
+ net/smc/smc_clc.c                        |    6 +++---
+ net/socket.c                             |   12 ++++++------
+ net/sunrpc/socklib.c                     |    6 +++---
+ net/sunrpc/svcsock.c                     |    4 ++--
+ net/sunrpc/xprtsock.c                    |    6 +++---
+ net/tipc/topsrv.c                        |    2 +-
+ net/tls/tls_device.c                     |    4 ++--
+ net/xfrm/espintcp.c                      |    2 +-
+ security/keys/keyctl.c                   |    4 ++--
+ 62 files changed, 138 insertions(+), 135 deletions(-)
+
+--- a/arch/x86/kernel/cpu/microcode/intel.c
++++ b/arch/x86/kernel/cpu/microcode/intel.c
+@@ -940,7 +940,7 @@ static enum ucode_state request_microcod
+       kvec.iov_base = (void *)firmware->data;
+       kvec.iov_len = firmware->size;
+-      iov_iter_kvec(&iter, WRITE, &kvec, 1, firmware->size);
++      iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size);
+       ret = generic_load_microcode(cpu, &iter);
+       release_firmware(firmware);
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -747,7 +747,7 @@ static int build_cipher_test_sglists(str
+       struct iov_iter input;
+       int err;
+-      iov_iter_kvec(&input, WRITE, inputs, nr_inputs, src_total_len);
++      iov_iter_kvec(&input, ITER_SOURCE, inputs, nr_inputs, src_total_len);
+       err = build_test_sglist(&tsgls->src, cfg->src_divs, alignmask,
+                               cfg->inplace ?
+                                       max(dst_total_len, src_total_len) :
+@@ -1130,7 +1130,7 @@ static int build_hash_sglist(struct test
+       kv.iov_base = (void *)vec->plaintext;
+       kv.iov_len = vec->psize;
+-      iov_iter_kvec(&input, WRITE, &kv, 1, vec->psize);
++      iov_iter_kvec(&input, ITER_SOURCE, &kv, 1, vec->psize);
+       return build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
+                                &input, divs);
+ }
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -1857,7 +1857,7 @@ int drbd_send(struct drbd_connection *co
+       /* THINK  if (signal_pending) return ... ? */
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size);
+       if (sock == connection->data.socket) {
+               rcu_read_lock();
+--- a/drivers/block/drbd/drbd_receiver.c
++++ b/drivers/block/drbd/drbd_receiver.c
+@@ -505,7 +505,7 @@ static int drbd_recv_short(struct socket
+       struct msghdr msg = {
+               .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
+       };
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
+       return sock_recvmsg(sock, &msg, msg.msg_flags);
+ }
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -265,7 +265,7 @@ static int lo_write_bvec(struct file *fi
+       struct iov_iter i;
+       ssize_t bw;
+-      iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
++      iov_iter_bvec(&i, ITER_SOURCE, bvec, 1, bvec->bv_len);
+       file_start_write(file);
+       bw = vfs_iter_write(file, &i, ppos, 0);
+@@ -343,7 +343,7 @@ static int lo_read_simple(struct loop_de
+       ssize_t len;
+       rq_for_each_segment(bvec, rq, iter) {
+-              iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
++              iov_iter_bvec(&i, ITER_DEST, &bvec, 1, bvec.bv_len);
+               len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
+               if (len < 0)
+                       return len;
+@@ -384,7 +384,7 @@ static int lo_read_transfer(struct loop_
+               b.bv_offset = 0;
+               b.bv_len = bvec.bv_len;
+-              iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
++              iov_iter_bvec(&i, ITER_DEST, &b, 1, b.bv_len);
+               len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
+               if (len < 0) {
+                       ret = len;
+@@ -508,7 +508,7 @@ static void lo_rw_aio_complete(struct ki
+ }
+ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
+-                   loff_t pos, bool rw)
++                   loff_t pos, int rw)
+ {
+       struct iov_iter iter;
+       struct req_iterator rq_iter;
+@@ -566,7 +566,7 @@ static int lo_rw_aio(struct loop_device
+       if (cmd->css)
+               kthread_associate_blkcg(cmd->css);
+-      if (rw == WRITE)
++      if (rw == ITER_SOURCE)
+               ret = call_write_iter(file, &cmd->iocb, &iter);
+       else
+               ret = call_read_iter(file, &cmd->iocb, &iter);
+@@ -611,14 +611,14 @@ static int do_req_filebacked(struct loop
+               if (lo->transfer)
+                       return lo_write_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+-                      return lo_rw_aio(lo, cmd, pos, WRITE);
++                      return lo_rw_aio(lo, cmd, pos, ITER_SOURCE);
+               else
+                       return lo_write_simple(lo, rq, pos);
+       case REQ_OP_READ:
+               if (lo->transfer)
+                       return lo_read_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+-                      return lo_rw_aio(lo, cmd, pos, READ);
++                      return lo_rw_aio(lo, cmd, pos, ITER_DEST);
+               else
+                       return lo_read_simple(lo, rq, pos);
+       default:
+--- a/drivers/block/nbd.c
++++ b/drivers/block/nbd.c
+@@ -543,7 +543,7 @@ static int nbd_send_cmd(struct nbd_devic
+       u32 nbd_cmd_flags = 0;
+       int sent = nsock->sent, skip = 0;
+-      iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
++      iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
+       type = req_to_nbd_cmd_type(req);
+       if (type == U32_MAX)
+@@ -629,7 +629,7 @@ send_pages:
+                       dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
+                               req, bvec.bv_len);
+-                      iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
++                      iov_iter_bvec(&from, ITER_SOURCE, &bvec, 1, bvec.bv_len);
+                       if (skip) {
+                               if (skip >= iov_iter_count(&from)) {
+                                       skip -= iov_iter_count(&from);
+@@ -681,7 +681,7 @@ static int nbd_read_reply(struct nbd_dev
+       int result;
+       reply->magic = 0;
+-      iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply));
++      iov_iter_kvec(&to, ITER_DEST, &iov, 1, sizeof(*reply));
+       result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
+       if (result < 0) {
+               if (!nbd_disconnected(nbd->config))
+@@ -758,7 +758,7 @@ static struct nbd_cmd *nbd_handle_reply(
+               struct iov_iter to;
+               rq_for_each_segment(bvec, req, iter) {
+-                      iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
++                      iov_iter_bvec(&to, ITER_DEST, &bvec, 1, bvec.bv_len);
+                       result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
+                       if (result < 0) {
+                               dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
+@@ -1206,7 +1206,7 @@ static void send_disconnects(struct nbd_
+       for (i = 0; i < config->num_connections; i++) {
+               struct nbd_sock *nsock = config->socks[i];
+-              iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
++              iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request));
+               mutex_lock(&nsock->tx_lock);
+               ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
+               if (ret < 0)
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -1237,7 +1237,7 @@ SYSCALL_DEFINE3(getrandom, char __user *
+                       return ret;
+       }
+-      ret = import_single_range(READ, ubuf, len, &iov, &iter);
++      ret = import_single_range(ITER_DEST, ubuf, len, &iov, &iter);
+       if (unlikely(ret))
+               return ret;
+       return get_random_bytes_user(&iter);
+@@ -1348,7 +1348,7 @@ static long random_ioctl(struct file *f,
+                       return -EINVAL;
+               if (get_user(len, p++))
+                       return -EFAULT;
+-              ret = import_single_range(WRITE, p, len, &iov, &iter);
++              ret = import_single_range(ITER_SOURCE, p, len, &iov, &iter);
+               if (unlikely(ret))
+                       return ret;
+               ret = write_pool_user(&iter);
+--- a/drivers/fsi/fsi-sbefifo.c
++++ b/drivers/fsi/fsi-sbefifo.c
+@@ -640,7 +640,7 @@ static void sbefifo_collect_async_ffdc(s
+       }
+         ffdc_iov.iov_base = ffdc;
+       ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
+-        iov_iter_kvec(&ffdc_iter, READ, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
++        iov_iter_kvec(&ffdc_iter, ITER_DEST, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
+       cmd[0] = cpu_to_be32(2);
+       cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
+       rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
+@@ -737,7 +737,7 @@ int sbefifo_submit(struct device *dev, c
+       rbytes = (*resp_len) * sizeof(__be32);
+       resp_iov.iov_base = response;
+       resp_iov.iov_len = rbytes;
+-        iov_iter_kvec(&resp_iter, READ, &resp_iov, 1, rbytes);
++        iov_iter_kvec(&resp_iter, ITER_DEST, &resp_iov, 1, rbytes);
+       /* Perform the command */
+       mutex_lock(&sbefifo->lock);
+@@ -817,7 +817,7 @@ static ssize_t sbefifo_user_read(struct
+       /* Prepare iov iterator */
+       resp_iov.iov_base = buf;
+       resp_iov.iov_len = len;
+-      iov_iter_init(&resp_iter, READ, &resp_iov, 1, len);
++      iov_iter_init(&resp_iter, ITER_DEST, &resp_iov, 1, len);
+       /* Perform the command */
+       mutex_lock(&sbefifo->lock);
+--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
++++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+@@ -902,7 +902,7 @@ static void rtrs_clt_init_req(struct rtr
+       req->need_inv_comp = false;
+       req->inv_errno = 0;
+-      iov_iter_kvec(&iter, WRITE, vec, 1, usr_len);
++      iov_iter_kvec(&iter, ITER_SOURCE, vec, 1, usr_len);
+       len = _copy_from_iter(req->iu->buf, usr_len, &iter);
+       WARN_ON(len != usr_len);
+--- a/drivers/isdn/mISDN/l1oip_core.c
++++ b/drivers/isdn/mISDN/l1oip_core.c
+@@ -706,7 +706,7 @@ l1oip_socket_thread(void *data)
+               printk(KERN_DEBUG "%s: socket created and open\n",
+                      __func__);
+       while (!signal_pending(current)) {
+-              iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, recvbuf_size);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, recvbuf_size);
+               recvlen = sock_recvmsg(socket, &msg, 0);
+               if (recvlen > 0) {
+                       l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
+--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
++++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
+@@ -3028,7 +3028,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_q
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&from, WRITE, &v, 1, buf_size);
++      iov_iter_kvec(&from, ITER_SOURCE, &v, 1, buf_size);
+       qp_lock(qpair);
+@@ -3072,7 +3072,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_q
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&to, READ, &v, 1, buf_size);
++      iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
+       qp_lock(qpair);
+@@ -3117,7 +3117,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *
+       if (!qpair || !buf)
+               return VMCI_ERROR_INVALID_ARGS;
+-      iov_iter_kvec(&to, READ, &v, 1, buf_size);
++      iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
+       qp_lock(qpair);
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -490,7 +490,7 @@ static ssize_t ppp_read(struct file *fil
+       ret = -EFAULT;
+       iov.iov_base = buf;
+       iov.iov_len = count;
+-      iov_iter_init(&to, READ, &iov, 1, count);
++      iov_iter_init(&to, ITER_DEST, &iov, 1, count);
+       if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
+               goto outf;
+       ret = skb->len;
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -296,7 +296,7 @@ static inline void nvme_tcp_advance_req(
+       if (!iov_iter_count(&req->iter) &&
+           req->data_sent < req->data_len) {
+               req->curr_bio = req->curr_bio->bi_next;
+-              nvme_tcp_init_iter(req, WRITE);
++              nvme_tcp_init_iter(req, ITER_SOURCE);
+       }
+ }
+@@ -766,7 +766,7 @@ static int nvme_tcp_recv_data(struct nvm
+                               nvme_tcp_init_recv_ctx(queue);
+                               return -EIO;
+                       }
+-                      nvme_tcp_init_iter(req, READ);
++                      nvme_tcp_init_iter(req, ITER_DEST);
+               }
+               /* we can read only from what is left in this bio */
+--- a/drivers/nvme/target/io-cmd-file.c
++++ b/drivers/nvme/target/io-cmd-file.c
+@@ -111,10 +111,10 @@ static ssize_t nvmet_file_submit_bvec(st
+               if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
+                       ki_flags |= IOCB_DSYNC;
+               call_iter = req->ns->file->f_op->write_iter;
+-              rw = WRITE;
++              rw = ITER_SOURCE;
+       } else {
+               call_iter = req->ns->file->f_op->read_iter;
+-              rw = READ;
++              rw = ITER_DEST;
+       }
+       iov_iter_bvec(&iter, rw, req->f.bvec, nr_segs, count);
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -339,7 +339,7 @@ static void nvmet_tcp_build_pdu_iovec(st
+               sg_offset = 0;
+       }
+-      iov_iter_bvec(&cmd->recv_msg.msg_iter, READ, cmd->iov,
++      iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov,
+                     nr_pages, cmd->pdu_len);
+ }
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1753,7 +1753,7 @@ sg_start_req(Sg_request *srp, unsigned c
+       Sg_scatter_hold *rsv_schp = &sfp->reserve;
+       struct request_queue *q = sfp->parentdp->device->request_queue;
+       struct rq_map_data *md, map_data;
+-      int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
++      int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? ITER_SOURCE : ITER_DEST;
+       unsigned char *long_cmdp = NULL;
+       SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
+--- a/drivers/target/iscsi/iscsi_target_util.c
++++ b/drivers/target/iscsi/iscsi_target_util.c
+@@ -1247,7 +1247,7 @@ int rx_data(
+               return -1;
+       memset(&msg, 0, sizeof(struct msghdr));
+-      iov_iter_kvec(&msg.msg_iter, READ, iov, iov_count, data);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, iov, iov_count, data);
+       while (msg_data_left(&msg)) {
+               rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
+@@ -1283,7 +1283,7 @@ int tx_data(
+       memset(&msg, 0, sizeof(struct msghdr));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, iov_count, data);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, iov_count, data);
+       while (msg_data_left(&msg)) {
+               int tx_loop = sock_sendmsg(conn->sock, &msg);
+--- a/drivers/target/target_core_file.c
++++ b/drivers/target/target_core_file.c
+@@ -480,7 +480,7 @@ fd_execute_write_same(struct se_cmd *cmd
+               len += se_dev->dev_attrib.block_size;
+       }
+-      iov_iter_bvec(&iter, WRITE, bvec, nolb, len);
++      iov_iter_bvec(&iter, ITER_SOURCE, bvec, nolb, len);
+       ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
+       kfree(bvec);
+--- a/drivers/usb/usbip/usbip_common.c
++++ b/drivers/usb/usbip/usbip_common.c
+@@ -309,7 +309,7 @@ int usbip_recv(struct socket *sock, void
+       if (!sock || !buf || !size)
+               return -EINVAL;
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, size);
+       usbip_dbg_xmit("enter\n");
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -614,7 +614,7 @@ static size_t init_iov_iter(struct vhost
+       /* Skip header. TODO: support TSO. */
+       size_t len = iov_length(vq->iov, out);
+-      iov_iter_init(iter, WRITE, vq->iov, out, len);
++      iov_iter_init(iter, ITER_SOURCE, vq->iov, out, len);
+       iov_iter_advance(iter, hdr_size);
+       return iov_iter_count(iter);
+@@ -1188,14 +1188,14 @@ static void handle_rx(struct vhost_net *
+                       msg.msg_control = vhost_net_buf_consume(&nvq->rxq);
+               /* On overrun, truncate and discard */
+               if (unlikely(headcount > UIO_MAXIOV)) {
+-                      iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
++                      iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, 1, 1);
+                       err = sock->ops->recvmsg(sock, &msg,
+                                                1, MSG_DONTWAIT | MSG_TRUNC);
+                       pr_debug("Discarded rx packet: len %zd\n", sock_len);
+                       continue;
+               }
+               /* We don't need to be notified again. */
+-              iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
++              iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, in, vhost_len);
+               fixup = msg.msg_iter;
+               if (unlikely((vhost_hlen))) {
+                       /* We will supply the header ourselves
+--- a/drivers/vhost/scsi.c
++++ b/drivers/vhost/scsi.c
+@@ -574,7 +574,7 @@ static void vhost_scsi_complete_cmd_work
+               memcpy(v_rsp.sense, cmd->tvc_sense_buf,
+                      se_cmd->scsi_sense_length);
+-              iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
++              iov_iter_init(&iov_iter, ITER_DEST, &cmd->tvc_resp_iov,
+                             cmd->tvc_in_iovs, sizeof(v_rsp));
+               ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
+               if (likely(ret == sizeof(v_rsp))) {
+@@ -883,7 +883,7 @@ vhost_scsi_get_desc(struct vhost_scsi *v
+        * point at the start of the outgoing WRITE payload, if
+        * DMA_TO_DEVICE is set.
+        */
+-      iov_iter_init(&vc->out_iter, WRITE, vq->iov, vc->out, vc->out_size);
++      iov_iter_init(&vc->out_iter, ITER_SOURCE, vq->iov, vc->out, vc->out_size);
+       ret = 0;
+ done:
+@@ -1036,7 +1036,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *
+                       data_direction = DMA_FROM_DEVICE;
+                       exp_data_len = vc.in_size - vc.rsp_size;
+-                      iov_iter_init(&in_iter, READ, &vq->iov[vc.out], vc.in,
++                      iov_iter_init(&in_iter, ITER_DEST, &vq->iov[vc.out], vc.in,
+                                     vc.rsp_size + exp_data_len);
+                       iov_iter_advance(&in_iter, vc.rsp_size);
+                       data_iter = in_iter;
+@@ -1173,7 +1173,7 @@ vhost_scsi_send_tmf_resp(struct vhost_sc
+       memset(&rsp, 0, sizeof(rsp));
+       rsp.response = tmf_resp_code;
+-      iov_iter_init(&iov_iter, READ, resp_iov, in_iovs, sizeof(rsp));
++      iov_iter_init(&iov_iter, ITER_DEST, resp_iov, in_iovs, sizeof(rsp));
+       ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
+       if (likely(ret == sizeof(rsp)))
+@@ -1268,7 +1268,7 @@ vhost_scsi_send_an_resp(struct vhost_scs
+       memset(&rsp, 0, sizeof(rsp));   /* event_actual = 0 */
+       rsp.response = VIRTIO_SCSI_S_OK;
+-      iov_iter_init(&iov_iter, READ, &vq->iov[vc->out], vc->in, sizeof(rsp));
++      iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[vc->out], vc->in, sizeof(rsp));
+       ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter);
+       if (likely(ret == sizeof(rsp)))
+--- a/drivers/vhost/vhost.c
++++ b/drivers/vhost/vhost.c
+@@ -841,7 +841,7 @@ static int vhost_copy_to_user(struct vho
+                                    VHOST_ACCESS_WO);
+               if (ret < 0)
+                       goto out;
+-              iov_iter_init(&t, WRITE, vq->iotlb_iov, ret, size);
++              iov_iter_init(&t, ITER_SOURCE, vq->iotlb_iov, ret, size);
+               ret = copy_to_iter(from, size, &t);
+               if (ret == size)
+                       ret = 0;
+@@ -880,7 +880,7 @@ static int vhost_copy_from_user(struct v
+                              (unsigned long long) size);
+                       goto out;
+               }
+-              iov_iter_init(&f, READ, vq->iotlb_iov, ret, size);
++              iov_iter_init(&f, ITER_DEST, vq->iotlb_iov, ret, size);
+               ret = copy_from_iter(to, size, &f);
+               if (ret == size)
+                       ret = 0;
+@@ -2132,7 +2132,7 @@ static int get_indirect(struct vhost_vir
+                       vq_err(vq, "Translation failure %d in indirect.\n", ret);
+               return ret;
+       }
+-      iov_iter_init(&from, READ, vq->indirect, ret, len);
++      iov_iter_init(&from, ITER_DEST, vq->indirect, ret, len);
+       count = len / sizeof desc;
+       /* Buffers are chained via a 16 bit next field, so
+        * we can have at most 2^16 of these. */
+--- a/drivers/vhost/vringh.c
++++ b/drivers/vhost/vringh.c
+@@ -1122,7 +1122,7 @@ static inline int copy_from_iotlb(const
+       if (ret < 0)
+               return ret;
+-      iov_iter_bvec(&iter, READ, iov, ret, len);
++      iov_iter_bvec(&iter, ITER_DEST, iov, ret, len);
+       ret = copy_from_iter(dst, len, &iter);
+@@ -1141,7 +1141,7 @@ static inline int copy_to_iotlb(const st
+       if (ret < 0)
+               return ret;
+-      iov_iter_bvec(&iter, WRITE, iov, ret, len);
++      iov_iter_bvec(&iter, ITER_SOURCE, iov, ret, len);
+       return copy_to_iter(src, len, &iter);
+ }
+--- a/drivers/vhost/vsock.c
++++ b/drivers/vhost/vsock.c
+@@ -155,7 +155,7 @@ vhost_transport_do_send_pkt(struct vhost
+                       break;
+               }
+-              iov_iter_init(&iov_iter, READ, &vq->iov[out], in, iov_len);
++              iov_iter_init(&iov_iter, ITER_DEST, &vq->iov[out], in, iov_len);
+               payload_len = pkt->len - pkt->off;
+               /* If the packet is greater than the space available in the
+@@ -337,7 +337,7 @@ vhost_vsock_alloc_pkt(struct vhost_virtq
+               return NULL;
+       len = iov_length(vq->iov, out);
+-      iov_iter_init(&iov_iter, WRITE, vq->iov, out, len);
++      iov_iter_init(&iov_iter, ITER_SOURCE, vq->iov, out, len);
+       nbytes = copy_from_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter);
+       if (nbytes != sizeof(pkt->hdr)) {
+--- a/drivers/xen/pvcalls-back.c
++++ b/drivers/xen/pvcalls-back.c
+@@ -129,13 +129,13 @@ static bool pvcalls_conn_back_read(void
+       if (masked_prod < masked_cons) {
+               vec[0].iov_base = data->in + masked_prod;
+               vec[0].iov_len = wanted;
+-              iov_iter_kvec(&msg.msg_iter, READ, vec, 1, wanted);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 1, wanted);
+       } else {
+               vec[0].iov_base = data->in + masked_prod;
+               vec[0].iov_len = array_size - masked_prod;
+               vec[1].iov_base = data->in;
+               vec[1].iov_len = wanted - vec[0].iov_len;
+-              iov_iter_kvec(&msg.msg_iter, READ, vec, 2, wanted);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, vec, 2, wanted);
+       }
+       atomic_set(&map->read, 0);
+@@ -188,13 +188,13 @@ static bool pvcalls_conn_back_write(stru
+       if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
+               vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
+               vec[0].iov_len = size;
+-              iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, size);
++              iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 1, size);
+       } else {
+               vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
+               vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
+               vec[1].iov_base = data->out;
+               vec[1].iov_len = size - vec[0].iov_len;
+-              iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, size);
++              iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 2, size);
+       }
+       atomic_set(&map->write, 0);
+--- a/fs/9p/vfs_addr.c
++++ b/fs/9p/vfs_addr.c
+@@ -51,7 +51,7 @@ static int v9fs_fid_readpage(void *data,
+       if (retval == 0)
+               return retval;
+-      iov_iter_bvec(&to, READ, &bvec, 1, PAGE_SIZE);
++      iov_iter_bvec(&to, ITER_DEST, &bvec, 1, PAGE_SIZE);
+       retval = p9_client_read(fid, page_offset(page), &to, &err);
+       if (err) {
+@@ -162,7 +162,7 @@ static int v9fs_vfs_writepage_locked(str
+       bvec.bv_page = page;
+       bvec.bv_offset = 0;
+       bvec.bv_len = len;
+-      iov_iter_bvec(&from, WRITE, &bvec, 1, len);
++      iov_iter_bvec(&from, ITER_SOURCE, &bvec, 1, len);
+       /* We should have writeback_fid always set */
+       BUG_ON(!v9inode->writeback_fid);
+--- a/fs/9p/vfs_dir.c
++++ b/fs/9p/vfs_dir.c
+@@ -108,7 +108,7 @@ static int v9fs_dir_readdir(struct file
+               if (rdir->tail == rdir->head) {
+                       struct iov_iter to;
+                       int n;
+-                      iov_iter_kvec(&to, READ, &kvec, 1, buflen);
++                      iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buflen);
+                       n = p9_client_read(file->private_data, ctx->pos, &to,
+                                          &err);
+                       if (err)
+--- a/fs/9p/xattr.c
++++ b/fs/9p/xattr.c
+@@ -32,7 +32,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid
+       struct iov_iter to;
+       int err;
+-      iov_iter_kvec(&to, READ, &kvec, 1, buffer_size);
++      iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buffer_size);
+       attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
+       if (IS_ERR(attr_fid)) {
+@@ -107,7 +107,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fi
+       struct iov_iter from;
+       int retval, err;
+-      iov_iter_kvec(&from, WRITE, &kvec, 1, value_len);
++      iov_iter_kvec(&from, ITER_SOURCE, &kvec, 1, value_len);
+       p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
+                name, value_len, flags);
+--- a/fs/afs/cmservice.c
++++ b/fs/afs/cmservice.c
+@@ -298,7 +298,7 @@ static int afs_deliver_cb_callback(struc
+               if (call->count2 != call->count && call->count2 != 0)
+                       return afs_protocol_error(call, afs_eproto_cb_count);
+               call->iter = &call->def_iter;
+-              iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4);
++              iov_iter_discard(&call->def_iter, ITER_DEST, call->count2 * 3 * 4);
+               call->unmarshall++;
+               fallthrough;
+--- a/fs/afs/internal.h
++++ b/fs/afs/internal.h
+@@ -1273,7 +1273,7 @@ static inline void afs_extract_begin(str
+ {
+       call->kvec[0].iov_base = buf;
+       call->kvec[0].iov_len = size;
+-      iov_iter_kvec(&call->def_iter, READ, call->kvec, 1, size);
++      iov_iter_kvec(&call->def_iter, ITER_DEST, call->kvec, 1, size);
+ }
+ static inline void afs_extract_to_tmp(struct afs_call *call)
+@@ -1288,7 +1288,7 @@ static inline void afs_extract_to_tmp64(
+ static inline void afs_extract_discard(struct afs_call *call, size_t size)
+ {
+-      iov_iter_discard(&call->def_iter, READ, size);
++      iov_iter_discard(&call->def_iter, ITER_DEST, size);
+ }
+ static inline void afs_extract_to_buf(struct afs_call *call, size_t size)
+--- a/fs/afs/rxrpc.c
++++ b/fs/afs/rxrpc.c
+@@ -302,7 +302,7 @@ static void afs_load_bvec(struct afs_cal
+               offset = 0;
+       }
+-      iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes);
++      iov_iter_bvec(&msg->msg_iter, ITER_SOURCE, bv, nr, bytes);
+ }
+ /*
+@@ -437,7 +437,7 @@ void afs_make_call(struct afs_addr_curso
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0);
+@@ -467,7 +467,7 @@ error_do_abort:
+               rxrpc_kernel_abort_call(call->net->socket, rxcall,
+                                       RX_USER_ABORT, ret, "KSD");
+       } else {
+-              iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
+               rxrpc_kernel_recv_data(call->net->socket, rxcall,
+                                      &msg.msg_iter, false,
+                                      &call->abort_code, &call->service_id);
+@@ -517,7 +517,7 @@ static void afs_deliver_to_call(struct a
+              state == AFS_CALL_SV_AWAIT_ACK
+              ) {
+               if (state == AFS_CALL_SV_AWAIT_ACK) {
+-                      iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0);
++                      iov_iter_kvec(&call->def_iter, ITER_DEST, NULL, 0, 0);
+                       ret = rxrpc_kernel_recv_data(call->net->socket,
+                                                    call->rxcall, &call->def_iter,
+                                                    false, &remote_abort,
+@@ -854,7 +854,7 @@ void afs_send_empty_reply(struct afs_cal
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, NULL, 0, 0);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = 0;
+@@ -894,7 +894,7 @@ void afs_send_simple_reply(struct afs_ca
+       iov[0].iov_len          = len;
+       msg.msg_name            = NULL;
+       msg.msg_namelen         = 0;
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, len);
+       msg.msg_control         = NULL;
+       msg.msg_controllen      = 0;
+       msg.msg_flags           = 0;
+--- a/fs/aio.c
++++ b/fs/aio.c
+@@ -1547,7 +1547,7 @@ static int aio_read(struct kiocb *req, c
+       if (unlikely(!file->f_op->read_iter))
+               return -EINVAL;
+-      ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
++      ret = aio_setup_rw(ITER_DEST, iocb, &iovec, vectored, compat, &iter);
+       if (ret < 0)
+               return ret;
+       ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
+@@ -1575,7 +1575,7 @@ static int aio_write(struct kiocb *req,
+       if (unlikely(!file->f_op->write_iter))
+               return -EINVAL;
+-      ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
++      ret = aio_setup_rw(ITER_SOURCE, iocb, &iovec, vectored, compat, &iter);
+       if (ret < 0)
+               return ret;
+       ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
+--- a/fs/ceph/file.c
++++ b/fs/ceph/file.c
+@@ -1115,7 +1115,7 @@ static void ceph_aio_complete_req(struct
+                               aio_req->total_len = rc + zlen;
+                       }
+-                      iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs,
++                      iov_iter_bvec(&i, ITER_DEST, osd_data->bvec_pos.bvecs,
+                                     osd_data->num_bvecs,
+                                     osd_data->bvec_pos.iter.bi_size);
+                       iov_iter_advance(&i, rc);
+@@ -1342,7 +1342,7 @@ ceph_direct_read_write(struct kiocb *ioc
+                               int zlen = min_t(size_t, len - ret,
+                                                size - pos - ret);
+-                              iov_iter_bvec(&i, READ, bvecs, num_pages, len);
++                              iov_iter_bvec(&i, ITER_DEST, bvecs, num_pages, len);
+                               iov_iter_advance(&i, ret);
+                               iov_iter_zero(zlen, &i);
+                               ret += zlen;
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -747,7 +747,7 @@ cifs_read_from_socket(struct TCP_Server_
+ {
+       struct msghdr smb_msg = {};
+       struct kvec iov = {.iov_base = buf, .iov_len = to_read};
+-      iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
++      iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+@@ -762,7 +762,7 @@ cifs_discard_from_socket(struct TCP_Serv
+        *  and cifs_readv_from_socket sets msg_control and msg_controllen
+        *  so little to initialize in struct msghdr
+        */
+-      iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
++      iov_iter_discard(&smb_msg.msg_iter, ITER_DEST, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+@@ -774,7 +774,7 @@ cifs_read_page_from_socket(struct TCP_Se
+       struct msghdr smb_msg = {};
+       struct bio_vec bv = {
+               .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
+-      iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
++      iov_iter_bvec(&smb_msg.msg_iter, ITER_DEST, &bv, 1, to_read);
+       return cifs_readv_from_socket(server, &smb_msg);
+ }
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -3180,7 +3180,7 @@ static ssize_t __cifs_writev(
+               ctx->iter = *from;
+               ctx->len = len;
+       } else {
+-              rc = setup_aio_ctx_iter(ctx, from, WRITE);
++              rc = setup_aio_ctx_iter(ctx, from, ITER_SOURCE);
+               if (rc) {
+                       kref_put(&ctx->refcount, cifs_aio_ctx_release);
+                       return rc;
+@@ -3920,7 +3920,7 @@ static ssize_t __cifs_readv(
+               ctx->iter = *to;
+               ctx->len = len;
+       } else {
+-              rc = setup_aio_ctx_iter(ctx, to, READ);
++              rc = setup_aio_ctx_iter(ctx, to, ITER_DEST);
+               if (rc) {
+                       kref_put(&ctx->refcount, cifs_aio_ctx_release);
+                       return rc;
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -4720,13 +4720,13 @@ handle_read_data(struct TCP_Server_Info
+                       return 0;
+               }
+-              iov_iter_bvec(&iter, WRITE, bvec, npages, data_len);
++              iov_iter_bvec(&iter, ITER_SOURCE, bvec, npages, data_len);
+       } else if (buf_len >= data_offset + data_len) {
+               /* read response payload is in buf */
+               WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
+               iov.iov_base = buf + data_offset;
+               iov.iov_len = data_len;
+-              iov_iter_kvec(&iter, WRITE, &iov, 1, data_len);
++              iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, data_len);
+       } else {
+               /* read response payload cannot be in both buf and pages */
+               WARN_ONCE(1, "buf can not contain only a part of read data");
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -362,7 +362,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       .iov_base = &rfc1002_marker,
+                       .iov_len  = 4
+               };
+-              iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4);
++              iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
+               rc = smb_send_kvec(server, &smb_msg, &sent);
+               if (rc < 0)
+                       goto unmask;
+@@ -383,7 +383,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       size += iov[i].iov_len;
+               }
+-              iov_iter_kvec(&smb_msg.msg_iter, WRITE, iov, n_vec, size);
++              iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size);
+               rc = smb_send_kvec(server, &smb_msg, &sent);
+               if (rc < 0)
+@@ -399,7 +399,7 @@ __smb_send_rqst(struct TCP_Server_Info *
+                       rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
+                                            &bvec.bv_offset);
+-                      iov_iter_bvec(&smb_msg.msg_iter, WRITE,
++                      iov_iter_bvec(&smb_msg.msg_iter, ITER_SOURCE,
+                                     &bvec, 1, bvec.bv_len);
+                       rc = smb_send_kvec(server, &smb_msg, &sent);
+                       if (rc < 0)
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1043,7 +1043,7 @@ __be32 nfsd_readv(struct svc_rqst *rqstp
+       ssize_t host_err;
+       trace_nfsd_read_vector(rqstp, fhp, offset, *count);
+-      iov_iter_kvec(&iter, READ, vec, vlen, *count);
++      iov_iter_kvec(&iter, ITER_DEST, vec, vlen, *count);
+       host_err = vfs_iter_read(file, &iter, &ppos, 0);
+       return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
+ }
+@@ -1133,7 +1133,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
+       if (stable && !use_wgather)
+               flags |= RWF_SYNC;
+-      iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
++      iov_iter_kvec(&iter, ITER_SOURCE, vec, vlen, *cnt);
+       since = READ_ONCE(file->f_wb_err);
+       if (verf)
+               nfsd_copy_write_verifier(verf, nn);
+--- a/fs/ocfs2/cluster/tcp.c
++++ b/fs/ocfs2/cluster/tcp.c
+@@ -902,7 +902,7 @@ static int o2net_recv_tcp_msg(struct soc
+ {
+       struct kvec vec = { .iov_len = len, .iov_base = data, };
+       struct msghdr msg = { .msg_flags = MSG_DONTWAIT, };
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, len);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, len);
+       return sock_recvmsg(sock, &msg, MSG_DONTWAIT);
+ }
+--- a/fs/orangefs/inode.c
++++ b/fs/orangefs/inode.c
+@@ -52,7 +52,7 @@ static int orangefs_writepage_locked(str
+       bv.bv_len = wlen;
+       bv.bv_offset = off % PAGE_SIZE;
+       WARN_ON(wlen == 0);
+-      iov_iter_bvec(&iter, WRITE, &bv, 1, wlen);
++      iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, wlen);
+       ret = wait_for_direct_io(ORANGEFS_IO_WRITE, inode, &off, &iter, wlen,
+           len, wr, NULL, NULL);
+@@ -110,7 +110,7 @@ static int orangefs_writepages_work(stru
+               else
+                       ow->bv[i].bv_offset = 0;
+       }
+-      iov_iter_bvec(&iter, WRITE, ow->bv, ow->npages, ow->len);
++      iov_iter_bvec(&iter, ITER_SOURCE, ow->bv, ow->npages, ow->len);
+       WARN_ON(ow->off >= len);
+       if (ow->off + ow->len > len)
+@@ -275,7 +275,7 @@ static int orangefs_readpage(struct file
+       bv.bv_page = page;
+       bv.bv_len = PAGE_SIZE;
+       bv.bv_offset = 0;
+-      iov_iter_bvec(&iter, READ, &bv, 1, PAGE_SIZE);
++      iov_iter_bvec(&iter, ITER_DEST, &bv, 1, PAGE_SIZE);
+       ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &off, &iter,
+           read_size, inode->i_size, NULL, &buffer_index, file);
+--- a/fs/read_write.c
++++ b/fs/read_write.c
+@@ -410,7 +410,7 @@ static ssize_t new_sync_read(struct file
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = (ppos ? *ppos : 0);
+-      iov_iter_init(&iter, READ, &iov, 1, len);
++      iov_iter_init(&iter, ITER_DEST, &iov, 1, len);
+       ret = call_read_iter(filp, &kiocb, &iter);
+       BUG_ON(ret == -EIOCBQUEUED);
+@@ -450,7 +450,7 @@ ssize_t __kernel_read(struct file *file,
+       init_sync_kiocb(&kiocb, file);
+       kiocb.ki_pos = pos ? *pos : 0;
+-      iov_iter_kvec(&iter, READ, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len);
+       ret = file->f_op->read_iter(&kiocb, &iter);
+       if (ret > 0) {
+               if (pos)
+@@ -513,7 +513,7 @@ static ssize_t new_sync_write(struct fil
+       init_sync_kiocb(&kiocb, filp);
+       kiocb.ki_pos = (ppos ? *ppos : 0);
+-      iov_iter_init(&iter, WRITE, &iov, 1, len);
++      iov_iter_init(&iter, ITER_SOURCE, &iov, 1, len);
+       ret = call_write_iter(filp, &kiocb, &iter);
+       BUG_ON(ret == -EIOCBQUEUED);
+@@ -546,7 +546,7 @@ ssize_t __kernel_write(struct file *file
+       init_sync_kiocb(&kiocb, file);
+       kiocb.ki_pos = pos ? *pos : 0;
+-      iov_iter_kvec(&iter, WRITE, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len);
+       ret = file->f_op->write_iter(&kiocb, &iter);
+       if (ret > 0) {
+               if (pos)
+@@ -916,7 +916,7 @@ static ssize_t vfs_readv(struct file *fi
+       struct iov_iter iter;
+       ssize_t ret;
+-      ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret >= 0) {
+               ret = do_iter_read(file, &iter, pos, flags);
+               kfree(iov);
+@@ -933,7 +933,7 @@ static ssize_t vfs_writev(struct file *f
+       struct iov_iter iter;
+       ssize_t ret;
+-      ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_SOURCE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret >= 0) {
+               file_start_write(file);
+               ret = do_iter_write(file, &iter, pos, flags);
+--- a/fs/seq_file.c
++++ b/fs/seq_file.c
+@@ -156,7 +156,7 @@ ssize_t seq_read(struct file *file, char
+       ssize_t ret;
+       init_sync_kiocb(&kiocb, file);
+-      iov_iter_init(&iter, READ, &iov, 1, size);
++      iov_iter_init(&iter, ITER_DEST, &iov, 1, size);
+       kiocb.ki_pos = *ppos;
+       ret = seq_read_iter(&kiocb, &iter);
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -304,7 +304,7 @@ ssize_t generic_file_splice_read(struct
+       unsigned int i_head;
+       int ret;
+-      iov_iter_pipe(&to, READ, pipe, len);
++      iov_iter_pipe(&to, ITER_DEST, pipe, len);
+       i_head = to.head;
+       init_sync_kiocb(&kiocb, in);
+       kiocb.ki_pos = *ppos;
+@@ -685,7 +685,7 @@ iter_file_splice_write(struct pipe_inode
+                       n++;
+               }
+-              iov_iter_bvec(&from, WRITE, array, n, sd.total_len - left);
++              iov_iter_bvec(&from, ITER_SOURCE, array, n, sd.total_len - left);
+               ret = vfs_iter_write(out, &from, &sd.pos, 0);
+               if (ret <= 0)
+                       break;
+@@ -1263,9 +1263,9 @@ static int vmsplice_type(struct fd f, in
+       if (!f.file)
+               return -EBADF;
+       if (f.file->f_mode & FMODE_WRITE) {
+-              *type = WRITE;
++              *type = ITER_SOURCE;
+       } else if (f.file->f_mode & FMODE_READ) {
+-              *type = READ;
++              *type = ITER_DEST;
+       } else {
+               fdput(f);
+               return -EBADF;
+@@ -1314,7 +1314,7 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const
+       if (!iov_iter_count(&iter))
+               error = 0;
+-      else if (iov_iter_rw(&iter) == WRITE)
++      else if (type == ITER_SOURCE)
+               error = vmsplice_to_pipe(f.file, &iter, flags);
+       else
+               error = vmsplice_to_user(f.file, &iter, flags);
+--- a/include/linux/uio.h
++++ b/include/linux/uio.h
+@@ -26,6 +26,9 @@ enum iter_type {
+       ITER_DISCARD = 64,
+ };
++#define ITER_SOURCE   1       // == WRITE
++#define ITER_DEST     0       // == READ
++
+ struct iov_iter_state {
+       size_t iov_offset;
+       size_t count;
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -1184,7 +1184,7 @@ SYSCALL_DEFINE5(process_madvise, int, pi
+               goto out;
+       }
+-      ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
++      ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
+       if (ret < 0)
+               goto out;
+--- a/mm/page_io.c
++++ b/mm/page_io.c
+@@ -269,7 +269,7 @@ int __swap_writepage(struct page *page,
+               };
+               struct iov_iter from;
+-              iov_iter_bvec(&from, WRITE, &bv, 1, PAGE_SIZE);
++              iov_iter_bvec(&from, ITER_SOURCE, &bv, 1, PAGE_SIZE);
+               init_sync_kiocb(&kiocb, swap_file);
+               kiocb.ki_pos = page_file_offset(page);
+--- a/mm/process_vm_access.c
++++ b/mm/process_vm_access.c
+@@ -264,7 +264,7 @@ static ssize_t process_vm_rw(pid_t pid,
+       struct iovec *iov_r = iovstack_r;
+       struct iov_iter iter;
+       ssize_t rc;
+-      int dir = vm_write ? WRITE : READ;
++      int dir = vm_write ? ITER_SOURCE : ITER_DEST;
+       if (flags != 0)
+               return -EINVAL;
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -2095,7 +2095,7 @@ int p9_client_readdir(struct p9_fid *fid
+       struct kvec kv = {.iov_base = data, .iov_len = count};
+       struct iov_iter to;
+-      iov_iter_kvec(&to, READ, &kv, 1, count);
++      iov_iter_kvec(&to, ITER_DEST, &kv, 1, count);
+       p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+                               fid->fid, (unsigned long long) offset, count);
+--- a/net/bluetooth/6lowpan.c
++++ b/net/bluetooth/6lowpan.c
+@@ -478,7 +478,7 @@ static int send_pkt(struct l2cap_chan *c
+       iv.iov_len = skb->len;
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, skb->len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, skb->len);
+       err = l2cap_chan_send(chan, &msg, skb->len);
+       if (err > 0) {
+--- a/net/bluetooth/a2mp.c
++++ b/net/bluetooth/a2mp.c
+@@ -56,7 +56,7 @@ static void a2mp_send(struct amp_mgr *mg
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, total_len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, total_len);
+       l2cap_chan_send(chan, &msg, total_len);
+--- a/net/bluetooth/smp.c
++++ b/net/bluetooth/smp.c
+@@ -606,7 +606,7 @@ static void smp_send_cmd(struct l2cap_co
+       memset(&msg, 0, sizeof(msg));
+-      iov_iter_kvec(&msg.msg_iter, WRITE, iv, 2, 1 + len);
++      iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iv, 2, 1 + len);
+       l2cap_chan_send(chan, &msg, 1 + len);
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -1812,7 +1812,7 @@ static int tcp_copy_straggler_data(struc
+       if (copy_address != zc->copybuf_address)
+               return -EINVAL;
+-      err = import_single_range(READ, (void __user *)copy_address,
++      err = import_single_range(ITER_DEST, (void __user *)copy_address,
+                                 copylen, &iov, &msg.msg_iter);
+       if (err)
+               return err;
+--- a/net/netfilter/ipvs/ip_vs_sync.c
++++ b/net/netfilter/ipvs/ip_vs_sync.c
+@@ -1617,7 +1617,7 @@ ip_vs_receive(struct socket *sock, char
+       EnterFunction(7);
+       /* Receive a packet */
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, buflen);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, buflen);
+       len = sock_recvmsg(sock, &msg, MSG_DONTWAIT);
+       if (len < 0)
+               return len;
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -361,7 +361,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+        */
+       krflags = MSG_PEEK | MSG_WAITALL;
+       clc_sk->sk_rcvtimeo = timeout;
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1,
+                       sizeof(struct smc_clc_msg_hdr));
+       len = sock_recvmsg(smc->clcsock, &msg, krflags);
+       if (signal_pending(current)) {
+@@ -408,7 +408,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+       } else {
+               recvlen = datlen;
+       }
+-      iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
+       krflags = MSG_WAITALL;
+       len = sock_recvmsg(smc->clcsock, &msg, krflags);
+       if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
+@@ -425,7 +425,7 @@ int smc_clc_wait_msg(struct smc_sock *sm
+               /* receive remaining proposal message */
+               recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
+                                               SMC_CLC_RECV_BUF_LEN : datlen;
+-              iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &vec, 1, recvlen);
+               len = sock_recvmsg(smc->clcsock, &msg, krflags);
+               if (len < recvlen) {
+                       smc->sk.sk_err = EPROTO;
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -706,7 +706,7 @@ EXPORT_SYMBOL(sock_sendmsg);
+ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
+                  struct kvec *vec, size_t num, size_t size)
+ {
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
+       return sock_sendmsg(sock, msg);
+ }
+ EXPORT_SYMBOL(kernel_sendmsg);
+@@ -732,7 +732,7 @@ int kernel_sendmsg_locked(struct sock *s
+       if (!sock->ops->sendmsg_locked)
+               return sock_no_sendmsg_locked(sk, msg, size);
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, num, size);
+       return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
+ }
+@@ -944,7 +944,7 @@ int kernel_recvmsg(struct socket *sock,
+                  struct kvec *vec, size_t num, size_t size, int flags)
+ {
+       msg->msg_control_is_user = false;
+-      iov_iter_kvec(&msg->msg_iter, READ, vec, num, size);
++      iov_iter_kvec(&msg->msg_iter, ITER_DEST, vec, num, size);
+       return sock_recvmsg(sock, msg, flags);
+ }
+ EXPORT_SYMBOL(kernel_recvmsg);
+@@ -1982,7 +1982,7 @@ int __sys_sendto(int fd, void __user *bu
+       struct iovec iov;
+       int fput_needed;
+-      err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter);
++      err = import_single_range(ITER_SOURCE, buff, len, &iov, &msg.msg_iter);
+       if (unlikely(err))
+               return err;
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
+@@ -2043,7 +2043,7 @@ int __sys_recvfrom(int fd, void __user *
+       int err, err2;
+       int fput_needed;
+-      err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter);
++      err = import_single_range(ITER_DEST, ubuf, size, &iov, &msg.msg_iter);
+       if (unlikely(err))
+               return err;
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
+@@ -2314,7 +2314,7 @@ static int copy_msghdr_from_user(struct
+       if (err)
+               return err;
+-      err = import_iovec(save_addr ? READ : WRITE,
++      err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE,
+                           msg.msg_iov, msg.msg_iovlen,
+                           UIO_FASTIOV, iov, &kmsg->msg_iter);
+       return err < 0 ? err : 0;
+--- a/net/sunrpc/socklib.c
++++ b/net/sunrpc/socklib.c
+@@ -213,7 +213,7 @@ static inline int xprt_sendmsg(struct so
+ static int xprt_send_kvec(struct socket *sock, struct msghdr *msg,
+                         struct kvec *vec, size_t seek)
+ {
+-      iov_iter_kvec(&msg->msg_iter, WRITE, vec, 1, vec->iov_len);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, 1, vec->iov_len);
+       return xprt_sendmsg(sock, msg, seek);
+ }
+@@ -226,7 +226,7 @@ static int xprt_send_pagedata(struct soc
+       if (err < 0)
+               return err;
+-      iov_iter_bvec(&msg->msg_iter, WRITE, xdr->bvec, xdr_buf_pagecount(xdr),
++      iov_iter_bvec(&msg->msg_iter, ITER_SOURCE, xdr->bvec, xdr_buf_pagecount(xdr),
+                     xdr->page_len + xdr->page_base);
+       return xprt_sendmsg(sock, msg, base + xdr->page_base);
+ }
+@@ -249,7 +249,7 @@ static int xprt_send_rm_and_kvec(struct
+       };
+       size_t len = iov[0].iov_len + iov[1].iov_len;
+-      iov_iter_kvec(&msg->msg_iter, WRITE, iov, 2, len);
++      iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, iov, 2, len);
+       return xprt_sendmsg(sock, msg, base);
+ }
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -271,7 +271,7 @@ static ssize_t svc_tcp_read_msg(struct s
+       rqstp->rq_respages = &rqstp->rq_pages[i];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
+-      iov_iter_bvec(&msg.msg_iter, READ, bvec, i, buflen);
++      iov_iter_bvec(&msg.msg_iter, ITER_DEST, bvec, i, buflen);
+       if (seek) {
+               iov_iter_advance(&msg.msg_iter, seek);
+               buflen -= seek;
+@@ -880,7 +880,7 @@ static ssize_t svc_tcp_read_marker(struc
+               want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
+               iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
+               iov.iov_len  = want;
+-              iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, want);
++              iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);
+               len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
+               if (len < 0)
+                       return len;
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -358,7 +358,7 @@ static ssize_t
+ xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags,
+               struct kvec *kvec, size_t count, size_t seek)
+ {
+-      iov_iter_kvec(&msg->msg_iter, READ, kvec, 1, count);
++      iov_iter_kvec(&msg->msg_iter, ITER_DEST, kvec, 1, count);
+       return xs_sock_recvmsg(sock, msg, flags, seek);
+ }
+@@ -367,7 +367,7 @@ xs_read_bvec(struct socket *sock, struct
+               struct bio_vec *bvec, unsigned long nr, size_t count,
+               size_t seek)
+ {
+-      iov_iter_bvec(&msg->msg_iter, READ, bvec, nr, count);
++      iov_iter_bvec(&msg->msg_iter, ITER_DEST, bvec, nr, count);
+       return xs_sock_recvmsg(sock, msg, flags, seek);
+ }
+@@ -375,7 +375,7 @@ static ssize_t
+ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
+               size_t count)
+ {
+-      iov_iter_discard(&msg->msg_iter, READ, count);
++      iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
+       return sock_recvmsg(sock, msg, flags);
+ }
+--- a/net/tipc/topsrv.c
++++ b/net/tipc/topsrv.c
+@@ -396,7 +396,7 @@ static int tipc_conn_rcv_from_sock(struc
+       iov.iov_base = &s;
+       iov.iov_len = sizeof(s);
+       msg.msg_name = NULL;
+-      iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, iov.iov_len);
++      iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, iov.iov_len);
+       ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
+       if (ret == -EWOULDBLOCK)
+               return -EWOULDBLOCK;
+--- a/net/tls/tls_device.c
++++ b/net/tls/tls_device.c
+@@ -585,7 +585,7 @@ int tls_device_sendpage(struct sock *sk,
+       kaddr = kmap(page);
+       iov.iov_base = kaddr + offset;
+       iov.iov_len = size;
+-      iov_iter_kvec(&msg_iter, WRITE, &iov, 1, size);
++      iov_iter_kvec(&msg_iter, ITER_SOURCE, &iov, 1, size);
+       rc = tls_push_data(sk, &msg_iter, size,
+                          flags, TLS_RECORD_TYPE_DATA);
+       kunmap(page);
+@@ -660,7 +660,7 @@ static int tls_device_push_pending_recor
+ {
+       struct iov_iter msg_iter;
+-      iov_iter_kvec(&msg_iter, WRITE, NULL, 0, 0);
++      iov_iter_kvec(&msg_iter, ITER_SOURCE, NULL, 0, 0);
+       return tls_push_data(sk, &msg_iter, 0, flags, TLS_RECORD_TYPE_DATA);
+ }
+--- a/net/xfrm/espintcp.c
++++ b/net/xfrm/espintcp.c
+@@ -360,7 +360,7 @@ static int espintcp_sendmsg(struct sock
+       *((__be16 *)buf) = cpu_to_be16(msglen);
+       pfx_iov.iov_base = buf;
+       pfx_iov.iov_len = sizeof(buf);
+-      iov_iter_kvec(&pfx_iter, WRITE, &pfx_iov, 1, pfx_iov.iov_len);
++      iov_iter_kvec(&pfx_iter, ITER_SOURCE, &pfx_iov, 1, pfx_iov.iov_len);
+       err = sk_msg_memcopy_from_iter(sk, &pfx_iter, &emsg->skmsg,
+                                      pfx_iov.iov_len);
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -1256,7 +1256,7 @@ long keyctl_instantiate_key(key_serial_t
+               struct iov_iter from;
+               int ret;
+-              ret = import_single_range(WRITE, (void __user *)_payload, plen,
++              ret = import_single_range(ITER_SOURCE, (void __user *)_payload, plen,
+                                         &iov, &from);
+               if (unlikely(ret))
+                       return ret;
+@@ -1288,7 +1288,7 @@ long keyctl_instantiate_key_iov(key_seri
+       if (!_payload_iov)
+               ioc = 0;
+-      ret = import_iovec(WRITE, _payload_iov, ioc,
++      ret = import_iovec(ITER_SOURCE, _payload_iov, ioc,
+                                   ARRAY_SIZE(iovstack), &iov, &from);
+       if (ret < 0)
+               return ret;
diff --git a/queue-5.10/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch b/queue-5.10/wifi-brcmfmac-fix-potential-use-after-free-issue-when-stopping-watchdog-task.patch
new file mode 100644 (file)
index 0000000..1dcc8fa
--- /dev/null
@@ -0,0 +1,55 @@
+From stable+bounces-246865-greg=kroah.com@vger.kernel.org Wed May 13 19:27:28 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 May 2026 09:33:00 -0400
+Subject: wifi: brcmfmac: Fix potential use-after-free issue when stopping watchdog task
+To: stable@vger.kernel.org
+Cc: Marek Szyprowski <m.szyprowski@samsung.com>, Arend van Spriel <arend.vanspriel@broadcom.com>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260513133300.3732727-1-sashal@kernel.org>
+
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+
+[ 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 <m.szyprowski@samsung.com>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Link: https://patch.msgid.link/20260416093339.2066829-1-m.szyprowski@samsung.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+[ replaced kthread_stop_put() with open-coded kthread_stop() + put_task_struct() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -2464,8 +2464,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;
+       }
+@@ -4536,8 +4538,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-5.10/wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch b/queue-5.10/wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch
new file mode 100644 (file)
index 0000000..dfb0d02
--- /dev/null
@@ -0,0 +1,49 @@
+From stable+bounces-242198-greg=kroah.com@vger.kernel.org Fri May  1 01:17:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 15:46:57 -0400
+Subject: wifi: mwifiex: fix use-after-free in mwifiex_adapter_cleanup()
+To: stable@vger.kernel.org
+Cc: Daniel Hodges <git@danielhodges.dev>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430194657.1996779-1-sashal@kernel.org>
+
+From: Daniel Hodges <git@danielhodges.dev>
+
+[ Upstream commit ae5e95d4157481693be2317e3ffcd84e36010cbb ]
+
+The mwifiex_adapter_cleanup() function uses timer_delete()
+(non-synchronous) for the wakeup_timer before the adapter structure is
+freed. This is incorrect because timer_delete() does not wait for any
+running timer callback to complete.
+
+If the wakeup_timer callback (wakeup_timer_fn) is executing when
+mwifiex_adapter_cleanup() is called, the callback will continue to
+access adapter fields (adapter->hw_status, adapter->if_ops.card_reset,
+etc.) which may be freed by mwifiex_free_adapter() called later in the
+mwifiex_remove_card() path.
+
+Use timer_delete_sync() instead to ensure any running timer callback has
+completed before returning.
+
+Fixes: 4636187da60b ("mwifiex: add wakeup timer based recovery mechanism")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Hodges <git@danielhodges.dev>
+Link: https://patch.msgid.link/20260206194401.2346-1-git@danielhodges.dev
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+[ changed `timer_delete_sync(&adapter->wakeup_timer)` to `del_timer_sync(&adapter->wakeup_timer)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/marvell/mwifiex/init.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/marvell/mwifiex/init.c
++++ b/drivers/net/wireless/marvell/mwifiex/init.c
+@@ -399,7 +399,7 @@ static void mwifiex_invalidate_lists(str
+ static void
+ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
+ {
+-      del_timer(&adapter->wakeup_timer);
++      del_timer_sync(&adapter->wakeup_timer);
+       del_timer_sync(&adapter->devdump_timer);
+       mwifiex_cancel_all_pending_cmd(adapter);
+       wake_up_interruptible(&adapter->cmd_wait_q.wait);