From: Greg Kroah-Hartman Date: Wed, 20 May 2026 14:54:21 +0000 (+0200) Subject: 7.0-stable patches X-Git-Tag: v6.6.141~50 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=0c7f1c339f460a41396df65697092efcd370e40c;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: accel-rocket-fix-prep_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch alsa-hda-realtek-add-mute-led-quirk-for-hp-pavilion-laptop-16-ag0xxx.patch alsa-hda-realtek-add-quirk-for-samsung-galaxy-book5-360-headphone.patch alsa-usb-audio-bound-midi-2.0-endpoint-descriptor-scans.patch alsa-usb-audio-bound-midi-endpoint-descriptor-scans.patch alsa-usb-audio-qcom-check-offload-mapping-failures.patch btrfs-only-release-the-dirty-pages-io-tree-after-successful-writes.patch ceph-fix-a-buffer-leak-in-__ceph_setxattr.patch ceph-fix-bug_on-in-__ceph_build_xattrs_blob-due-to-stale-blob-size.patch ceph-put-folios-not-suitable-for-writeback.patch drm-amd-display-wrap-dcn32-phantom-plane-allocation-in-dc_run_with_preemption_enabled.patch drm-bridge-imx8qxp-pxl2dpi-avoid-err_ptr-with-device_node-cleanup.patch drm-i915-dp-fix-vsc-dynamic-range-signaling-for-rgb-formats.patch drm-i915-skip-__i915_request_skip-for-already-signaled-requests.patch drm-loongson-use-managed-kms-polling.patch drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch drm-replace-old-pointer-to-new-idr.patch drm-ttm-convert-eagain-from-dmem_cgroup_try_charge-to-enospc.patch drm-ttm-fix-ttm_bo_shrink-infinite-lru-walk-on-backup-failure.patch drm-ttm-fix-ttm_bo_swapout-infinite-lru-walk-on-swapout-failure.patch drm-xe-dma-buf-fix-uaf-with-retry-loop.patch drm-xe-dma-buf-handle-empty-bo-and-uaf-races.patch io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch iommu-amd-bounds-check-devid-in-__rlookup_amd_iommu.patch iommu-fix-ats-invalidation-timeouts-during-__iommu_remove_group_pasid.patch iommu-fix-nested-pci_dev_reset_iommu_prepare-done.patch iommu-fix-null-group-domain-dereference-in-pci_dev_reset_iommu_done.patch iommu-fix-pasid-attach-in-pci_dev_reset_iommu_prepare-done.patch iommu-fix-warn_on-in-__iommu_group_set_domain_nofail-due-to-reset.patch iommu-replace-per-group-resetting_domain-with-per-gdev-blocked-flag.patch iommu-vt-d-avoid-null-pointer-dereference-or-refcount-corruption.patch iommu-vt-d-disable-dmar-for-intel-q35-igfx.patch iommu-vt-d-fix-oops-due-to-out-of-scope-access.patch irqchip-gic-v5-allocate-its-parent-lpis-as-a-range.patch irqchip-gic-v5-move-lpi-allocation-into-the-lpi-domain.patch irqchip-gic-v5-support-range-allocation-for-lpis.patch irqchip-meson-gpio-use-the-correct-register-in-meson_s4_gpio_irq_set_type.patch irqchip-riscv-imsic-clear-interrupt-move-state-during-cpu-offlining.patch libceph-fix-potential-null-ptr-deref-in-decode_choose_args.patch libceph-fix-potential-out-of-bounds-access-in-__ceph_x_decrypt.patch libceph-fix-potential-out-of-bounds-access-in-crush_decode.patch libceph-fix-potential-out-of-bounds-access-in-osdmap_decode.patch libceph-handle-rbtree-insertion-error-in-decode_choose_args.patch netfs-fix-error-handling-in-netfs_extract_user_iter.patch nfsd-fix-file-change-detection-in-cb_getattr.patch nfsd-fix-get_dir_delegation-when-vfs-leases-are-disabled.patch nfsd-update-mtime-ctime-on-clone-in-presense-of-delegated-attributes.patch nfsd-update-mtime-ctime-on-copy-in-presence-of-delegated-attributes.patch nvme-apple-reset-q-sq_tail-during-queue-init.patch platform-x86-intel-move-debugfs-register-before-creating-devices.patch platform-x86-lenovo-wmi-helpers-fix-memory-leak-in-lwmi_dev_evaluate_int.patch platform-x86-lenovo-wmi-helpers-move-gamezone-enums-to-wmi-helpers.patch platform-x86-lenovo-wmi-other-add-attribute-id-helper-functions.patch platform-x86-lenovo-wmi-other-balance-component-bind-and-unbind.patch platform-x86-lenovo-wmi-other-balance-ida-id-allocation-and-free.patch platform-x86-lenovo-wmi-other-fix-tunable_attr_01-struct-members.patch platform-x86-lenovo-wmi-other-limit-adding-attributes-to-supported-devices.patch platform-x86-lenovo-wmi-other-zero-initialize-wmi-arguments.patch powerpc-warp-fix-error-handling-in-pika_dtm_thread.patch riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch smb-client-fix-possible-infinite-loop-and-oob-read-in-symlink_data.patch virt-sev-guest-do-not-use-host-controlled-page-order-in-cleanup-path.patch x86-kexec-push-kjump-return-address-even-for-non-kjump-kexec.patch xfs-fix-memory-leak-on-error-in-xfs_alloc_zone_info.patch --- diff --git a/queue-7.0/accel-rocket-fix-prep_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch b/queue-7.0/accel-rocket-fix-prep_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch new file mode 100644 index 0000000000..728225e2c1 --- /dev/null +++ b/queue-7.0/accel-rocket-fix-prep_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch @@ -0,0 +1,38 @@ +From 74570e12b4705ea11dcdfbfbd0a0b0fdaeff3059 Mon Sep 17 00:00:00 2001 +From: Gyeyoung Baek +Date: Sun, 19 Apr 2026 16:17:15 +0900 +Subject: accel/rocket: Fix prep_bo ioctl leaking positive return from dma_resv_wait_timeout() + +From: Gyeyoung Baek + +commit 74570e12b4705ea11dcdfbfbd0a0b0fdaeff3059 upstream. + +dma_resv_wait_timeout() returns a positive 'remaining jiffies' value +on success, 0 on timeout, and -errno on failure. + +rocket_ioctl_prep_bo() returns this 'long' result from an int-typed +ioctl handler, so positive values reach userspace as bogus errors. +Explicitly set ret to 0 on the success path. + +Fixes: 525ad89dd904 ("accel/rocket: Add IOCTLs for synchronizing memory accesses") +Cc: stable@vger.kernel.org +Signed-off-by: Gyeyoung Baek +Reviewed-by: Tomeu Vizoso +Link: https://patch.msgid.link/c0ebf83b345721701b22d8f5bc41c52c0ecf5e16.1776581974.git.gye976@gmail.com +Signed-off-by: Steven Price +Signed-off-by: Greg Kroah-Hartman +--- + drivers/accel/rocket/rocket_gem.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/accel/rocket/rocket_gem.c ++++ b/drivers/accel/rocket/rocket_gem.c +@@ -145,6 +145,8 @@ int rocket_ioctl_prep_bo(struct drm_devi + ret = dma_resv_wait_timeout(gem_obj->resv, DMA_RESV_USAGE_WRITE, true, timeout); + if (!ret) + ret = timeout ? -ETIMEDOUT : -EBUSY; ++ else if (ret > 0) ++ ret = 0; + + shmem_obj = &to_rocket_bo(gem_obj)->base; + diff --git a/queue-7.0/alsa-hda-realtek-add-mute-led-quirk-for-hp-pavilion-laptop-16-ag0xxx.patch b/queue-7.0/alsa-hda-realtek-add-mute-led-quirk-for-hp-pavilion-laptop-16-ag0xxx.patch new file mode 100644 index 0000000000..30ed651a2f --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-mute-led-quirk-for-hp-pavilion-laptop-16-ag0xxx.patch @@ -0,0 +1,38 @@ +From 7d1051ad68df3d584b5f24bfa1fb19f3a24db278 Mon Sep 17 00:00:00 2001 +From: Adrien Burnett +Date: Thu, 14 May 2026 18:59:05 +0200 +Subject: ALSA: hda/realtek: Add mute LED quirk for HP Pavilion Laptop 16-ag0xxx + +From: Adrien Burnett + +commit 7d1051ad68df3d584b5f24bfa1fb19f3a24db278 upstream. + +Add a SND_PCI_QUIRK entry for the HP Pavilion Laptop 16-ag0xxx +(subsystem 0x103c:0x8cbc, Realtek ALC245). The +ALC245_FIXUP_HP_X360_MUTE_LEDS fixup is already used by the +neighbouring HP Pavilion Aero Laptop 13-bg0xxx (0x103c:0x8cbd); +it chains the master-mute COEF handler with the GPIO mic-mute +LED handler, which is what this machine needs. + +Tested on the affected hardware: both the mute and mic-mute key +LEDs respond correctly to the keyboard hotkeys after this change. + +Cc: +Signed-off-by: Adrien Burnett +Link: https://patch.msgid.link/20260514165905.21175-1-an.arctic.pigeon@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7146,6 +7146,7 @@ static const struct hda_quirk alc269_fix + SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), ++ SND_PCI_QUIRK(0x103c, 0x8cbc, "HP Pavilion Laptop 16-ag0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), + SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-samsung-galaxy-book5-360-headphone.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-samsung-galaxy-book5-360-headphone.patch new file mode 100644 index 0000000000..e7b7032d2f --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-samsung-galaxy-book5-360-headphone.patch @@ -0,0 +1,35 @@ +From fd87b510f5f543125ecf51e7c706a9f4bc3352be Mon Sep 17 00:00:00 2001 +From: Markus Kramer +Date: Thu, 14 May 2026 00:28:18 +0200 +Subject: ALSA: hda/realtek: Add quirk for Samsung Galaxy Book5 360 headphone + +From: Markus Kramer + +commit fd87b510f5f543125ecf51e7c706a9f4bc3352be upstream. + +The Samsung Galaxy Book5 360 (NP750QHA, PCI subsystem ID 0x144d:0xc902) +has severe audio distortion on the 3.5mm headphone jack. Applying +ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET corrects the output path +configuration, consistent with fixes already applied to other Samsung +Galaxy Book models using the same ALC256 codec. + +Cc: stable@vger.kernel.org +Link: https://github.com/thesofproject/linux/issues/5648 +Signed-off-by: Markus Kramer +Link: https://patch.msgid.link/20260513222818.14351-1-linux@markus-kramer.de +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7448,6 +7448,7 @@ static const struct hda_quirk alc269_fix + SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), + SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), + SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), ++ SND_PCI_QUIRK(0x144d, 0xc902, "Samsung Galaxy Book5 360 (NP750QHA)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), + SND_PCI_QUIRK(0x144d, 0xc1cb, "Samsung Galaxy Book3 Pro 360 (NP965QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), + SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), diff --git a/queue-7.0/alsa-usb-audio-bound-midi-2.0-endpoint-descriptor-scans.patch b/queue-7.0/alsa-usb-audio-bound-midi-2.0-endpoint-descriptor-scans.patch new file mode 100644 index 0000000000..08aa6d1270 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-bound-midi-2.0-endpoint-descriptor-scans.patch @@ -0,0 +1,58 @@ +From 918be519c7876329e1b6e2ea1c59f0b75e792dca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Thu, 7 May 2026 00:40:52 -0300 +Subject: ALSA: usb-audio: Bound MIDI 2.0 endpoint descriptor scans +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit 918be519c7876329e1b6e2ea1c59f0b75e792dca upstream. + +The USB MIDI 2.0 endpoint parser has the same descriptor walking +pattern as the legacy MIDI parser. It validates bLength against +bNumGrpTrmBlock before reading baAssoGrpTrmBlkID[], but not against the +remaining bytes in the endpoint-extra scan. + +A malformed device can therefore make later baAssoGrpTrmBlkID[] reads +consume bytes past the walked descriptor. + +Reject zero-length and overlong descriptors while walking endpoint +extras. + +Fixes: ff49d1df79ae ("ALSA: usb-audio: USB MIDI 2.0 UMP support") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260507-usb-midi-endpoint-scan-bounds-v1-2-329d7348160e@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/midi2.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/sound/usb/midi2.c ++++ b/sound/usb/midi2.c +@@ -496,15 +496,17 @@ static void *find_usb_ms_endpoint_descri + while (extralen > 3) { + struct usb_ms_endpoint_descriptor *ms_ep = + (struct usb_ms_endpoint_descriptor *)extra; ++ int length = ms_ep->bLength; + +- if (ms_ep->bLength > 3 && ++ if (!length || length > extralen) ++ break; ++ ++ if (length > 3 && + ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT && + ms_ep->bDescriptorSubtype == subtype) + return ms_ep; +- if (!extra[0]) +- break; +- extralen -= extra[0]; +- extra += extra[0]; ++ extralen -= length; ++ extra += length; + } + return NULL; + } diff --git a/queue-7.0/alsa-usb-audio-bound-midi-endpoint-descriptor-scans.patch b/queue-7.0/alsa-usb-audio-bound-midi-endpoint-descriptor-scans.patch new file mode 100644 index 0000000000..6ca3ff7fbd --- /dev/null +++ b/queue-7.0/alsa-usb-audio-bound-midi-endpoint-descriptor-scans.patch @@ -0,0 +1,58 @@ +From d6854daa67be623860f4e1873fd3d3c275aba4ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Thu, 7 May 2026 00:40:51 -0300 +Subject: ALSA: usb-audio: Bound MIDI endpoint descriptor scans +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit d6854daa67be623860f4e1873fd3d3c275aba4ed upstream. + +snd_usbmidi_get_ms_info() validates the internal MIDIStreaming endpoint +descriptor size before using baAssocJackID[], but the descriptor walker can +still return a class-specific endpoint descriptor whose bLength exceeds the +remaining bytes in the endpoint-extra scan. + +That leaves later flexible-array reads bounded by bLength, but not by the +remaining bytes in the endpoint-extra scan. + +Stop walking when bLength is zero or +extends past the remaining endpoint-extra scan. + +Fixes: 5c6cd7021a05 ("ALSA: usb-audio: Fix case when USB MIDI interface has more than one extra endpoint descriptor") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260507-usb-midi-endpoint-scan-bounds-v1-1-329d7348160e@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/midi.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -1947,15 +1947,17 @@ static struct usb_ms_endpoint_descriptor + while (extralen > 3) { + struct usb_ms_endpoint_descriptor *ms_ep = + (struct usb_ms_endpoint_descriptor *)extra; ++ int length = ms_ep->bLength; + +- if (ms_ep->bLength > 3 && ++ if (!length || length > extralen) ++ break; ++ ++ if (length > 3 && + ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT && + ms_ep->bDescriptorSubtype == UAC_MS_GENERAL) + return ms_ep; +- if (!extra[0]) +- break; +- extralen -= extra[0]; +- extra += extra[0]; ++ extralen -= length; ++ extra += length; + } + return NULL; + } diff --git a/queue-7.0/alsa-usb-audio-qcom-check-offload-mapping-failures.patch b/queue-7.0/alsa-usb-audio-qcom-check-offload-mapping-failures.patch new file mode 100644 index 0000000000..0af691690c --- /dev/null +++ b/queue-7.0/alsa-usb-audio-qcom-check-offload-mapping-failures.patch @@ -0,0 +1,108 @@ +From 814b2c9b30e56074e11fc0a6e5419b3fee0639bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Mon, 11 May 2026 01:36:37 -0300 +Subject: ALSA: usb-audio: qcom: Check offload mapping failures +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit 814b2c9b30e56074e11fc0a6e5419b3fee0639bc upstream. + +uaudio_transfer_buffer_setup() calls dma_get_sgtable() and then passes +the sg_table to uaudio_iommu_map_xfer_buf() without checking whether sg +table construction succeeded. If dma_get_sgtable() fails, the sg_table +contents are not valid. + +uaudio_iommu_map_pa() also ignores iommu_map() failures for the event and +transfer rings and still returns the allocated IOVA to the QMI response. +That can expose an unmapped IOVA to the audio DSP. For transfer rings, +the failed mapping also leaves the IOVA allocator state marked in use. + +Check both operations. Free the coherent transfer buffer when sg table +construction fails, free the sg table when transfer-buffer IOMMU mapping +fails, and release the transfer-ring IOVA if iommu_map() fails. Also +return the existing event-ring IOVA when the event ring is already mapped, +matching the pre-split helper behavior. + +Fixes: 326bbc348298 ("ALSA: usb-audio: qcom: Introduce QC USB SND offloading support") +Fixes: 44499ecb4f28 ("ALSA: usb: qcom: Fix false-positive address space check") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260511-alsa-usb-qcom-offload-map-errors-v1-1-6502695e58bc@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/qcom/qc_audio_offload.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +--- a/sound/usb/qcom/qc_audio_offload.c ++++ b/sound/usb/qcom/qc_audio_offload.c +@@ -565,6 +565,7 @@ static unsigned long uaudio_iommu_map_pa + unsigned long iova = 0; + bool map = true; + int prot = uaudio_iommu_map_prot(dma_coherent); ++ int ret; + + switch (mtype) { + case MEM_EVENT_RING: +@@ -582,10 +583,24 @@ static unsigned long uaudio_iommu_map_pa + dev_err(uaudio_qdev->data->dev, "unknown mem type %d\n", mtype); + } + +- if (!iova || !map) ++ if (!iova) + return 0; + +- iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, GFP_KERNEL); ++ if (!map) ++ return iova; ++ ++ ret = iommu_map(uaudio_qdev->data->domain, iova, pa, size, prot, ++ GFP_KERNEL); ++ if (ret) { ++ dev_err(uaudio_qdev->data->dev, ++ "failed to map %zu bytes at iova 0x%08lx: %d\n", ++ size, iova, ret); ++ if (mtype == MEM_XFER_RING) ++ uaudio_put_iova(iova, size, ++ &uaudio_qdev->xfer_ring_list, ++ &uaudio_qdev->xfer_ring_iova_size); ++ return 0; ++ } + + return iova; + } +@@ -1054,15 +1069,17 @@ static int uaudio_transfer_buffer_setup( + if (!xfer_buf) + return -ENOMEM; + +- dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, +- xfer_buf_dma, len); ++ ret = dma_get_sgtable(subs->dev->bus->sysdev, &xfer_buf_sgt, xfer_buf, ++ xfer_buf_dma, len); ++ if (ret) ++ goto free_xfer_buf; + + /* map the physical buffer into sysdev as well */ + xfer_buf_dma_sysdev = uaudio_iommu_map_xfer_buf(dma_coherent, + len, &xfer_buf_sgt); + if (!xfer_buf_dma_sysdev) { + ret = -ENOMEM; +- goto unmap_sync; ++ goto free_sgt; + } + + mem_info->dma = xfer_buf_dma; +@@ -1073,7 +1090,9 @@ static int uaudio_transfer_buffer_setup( + + return 0; + +-unmap_sync: ++free_sgt: ++ sg_free_table(&xfer_buf_sgt); ++free_xfer_buf: + usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_dma); + + return ret; diff --git a/queue-7.0/btrfs-only-release-the-dirty-pages-io-tree-after-successful-writes.patch b/queue-7.0/btrfs-only-release-the-dirty-pages-io-tree-after-successful-writes.patch new file mode 100644 index 0000000000..ceccb18b66 --- /dev/null +++ b/queue-7.0/btrfs-only-release-the-dirty-pages-io-tree-after-successful-writes.patch @@ -0,0 +1,152 @@ +From 4066c55e109475a06d18a1f127c939d551211956 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Thu, 30 Apr 2026 10:37:22 +0930 +Subject: btrfs: only release the dirty pages io tree after successful writes + +From: Qu Wenruo + +commit 4066c55e109475a06d18a1f127c939d551211956 upstream. + +[WARNING] +With extra warning on dirty extent buffers at umount (aka, the next +patch in the series), test case generic/388 can trigger the following +warning about dirty extent buffers at unmount time: + + BTRFS critical (device dm-2 state E): emergency shutdown + BTRFS error (device dm-2 state E): error while writing out transaction: -30 + BTRFS warning (device dm-2 state E): Skipping commit of aborted transaction. + BTRFS error (device dm-2 state EA): Transaction 9 aborted (error -30) + BTRFS: error (device dm-2 state EA) in cleanup_transaction:2068: errno=-30 Readonly filesystem + BTRFS info (device dm-2 state EA): forced readonly + BTRFS info (device dm-2 state EA): last unmount of filesystem 4fbf2e15-f941-49a0-bc7c-716315d2777c + ------------[ cut here ]------------ + WARNING: disk-io.c:3311 at invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs], CPU#8: umount/914368 + CPU: 8 UID: 0 PID: 914368 Comm: umount Tainted: G OE 7.1.0-rc1-custom+ #372 PREEMPT(full) 2de38db8d1deae71fde295430a0ff3ab98ccf596 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022 + RIP: 0010:invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs] + Call Trace: + + close_ctree+0x52e/0x574 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] + generic_shutdown_super+0x89/0x1a0 + kill_anon_super+0x16/0x40 + btrfs_kill_super+0x16/0x20 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd] + deactivate_locked_super+0x2d/0xb0 + cleanup_mnt+0xdc/0x140 + task_work_run+0x5a/0xa0 + exit_to_user_mode_loop+0x123/0x4b0 + do_syscall_64+0x243/0x7c0 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + + ---[ end trace 0000000000000000 ]--- + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30539776 owner 9 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30621696 owner 257 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30638080 owner 258 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30654464 owner 7 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30703616 owner 2 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30720000 owner 10 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30736384 owner 4 gen 9 refs 2 flags 0x7 + BTRFS warning (device dm-2 state EA): unable to release extent buffer 30752768 owner 11 gen 9 refs 2 flags 0x7 + +I'm using a stripped down version, which seems to trigger the warning +more reliably: + + _fsstress_pid="" + workload() + { + dmesg -C + mkfs.btrfs -f -K $dev > /dev/null + echo 1 > /sys/kernel/debug/clear_warn_once + mount $dev $mnt + $fsstress -w -n 1024 -p 4 -d $mnt & + _fsstress_pid=$! + sleep 0 + $godown $mnt + pkill --echo -PIPE fsstress > /dev/null + wait $_fsstress_pid + unset _fsstress_pid + umount $mnt + + if dmesg | grep -q "WARNING"; then + fail + fi + } + + for (( i = 0; i < $runtime; i++ )); do + echo "=== $i/$runtime ===" + workload + done + +[CAUSE] +Inside btrfs_write_and_wait_transaction(), we first try to write all +dirty ebs, then wait for them to finish. + +After that we call btrfs_extent_io_tree_release() to free all +extent states from dirty_pages io tree. + +However if we hit an error from btrfs_write_marked_extent(), then we +still call btrfs_extent_io_tree_release() to clear that dirty_pages io +tree, which may contain dirty records that we haven't yet submitted. + +Furthermore, the later transaction cleanup path will utilize that +dirty_pages io tree to properly cleanup those dirty ebs, but since it's +already empty, no dirty ebs are properly cleaned up, thus will later +trigger the warnings inside invalidate_btree_folios(). + +[FIX] +Normally such dirty ebs won't cause problems, as when the iput() is +called on the btree inode, the dirty ebs will be forcibly written back, +and since the fs is already in an error status, such writeback will not +reach disk and finish immediately. + +But it's still better to get rid of such dirty ebs, if we ended up with +dirty ebs but the fs is not in an error status, then such writeback at +iput() time will be too late, as all workers are already stopped but +writeback will utilize workers, which will lead to NULL pointer +dereferences. + +Instead of unconditionally calling btrfs_extent_io_tree_release(), only +call it if btrfs_write_and_wait_transaction() finished successfully, so +that @dirty_pages extent io tree is kept untouched for transaction +cleanup. + +CC: stable@vger.kernel.org # 6.1+ +Reviewed-by: Filipe Manana +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/disk-io.c | 1 + + fs/btrfs/transaction.c | 9 ++++----- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4709,6 +4709,7 @@ static void btrfs_destroy_marked_extents + free_extent_buffer_stale(eb); + } + } ++ btrfs_extent_io_tree_release(dirty_pages); + } + + static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -1275,14 +1275,13 @@ static int btrfs_write_and_wait_transact + blk_finish_plug(&plug); + ret2 = btrfs_wait_extents(fs_info, dirty_pages); + +- btrfs_extent_io_tree_release(&trans->transaction->dirty_pages); +- + if (ret) + return ret; +- else if (ret2) ++ if (ret2) + return ret2; +- else +- return 0; ++ ++ btrfs_extent_io_tree_release(&trans->transaction->dirty_pages); ++ return 0; + } + + /* diff --git a/queue-7.0/ceph-fix-a-buffer-leak-in-__ceph_setxattr.patch b/queue-7.0/ceph-fix-a-buffer-leak-in-__ceph_setxattr.patch new file mode 100644 index 0000000000..f8c1ae9e9d --- /dev/null +++ b/queue-7.0/ceph-fix-a-buffer-leak-in-__ceph_setxattr.patch @@ -0,0 +1,34 @@ +From 5d3cc36b4e77a27ce7b686b7c59c7072bcb3fa8e Mon Sep 17 00:00:00 2001 +From: Viacheslav Dubeyko +Date: Thu, 9 Apr 2026 12:26:02 -0700 +Subject: ceph: fix a buffer leak in __ceph_setxattr() + +From: Viacheslav Dubeyko + +commit 5d3cc36b4e77a27ce7b686b7c59c7072bcb3fa8e upstream. + +The old_blob in __ceph_setxattr() can store +ci->i_xattrs.prealloc_blob value during the retry. +However, it is never called the ceph_buffer_put() +for the old_blob object. This patch fixes the issue of +the buffer leak. + +Cc: stable@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Reviewed-by: Alex Markuze +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/xattr.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ceph/xattr.c ++++ b/fs/ceph/xattr.c +@@ -1294,6 +1294,7 @@ retry: + + do_sync: + spin_unlock(&ci->i_ceph_lock); ++ ceph_buffer_put(old_blob); + do_sync_unlocked: + if (lock_snap_rwsem) + up_read(&mdsc->snap_rwsem); diff --git a/queue-7.0/ceph-fix-bug_on-in-__ceph_build_xattrs_blob-due-to-stale-blob-size.patch b/queue-7.0/ceph-fix-bug_on-in-__ceph_build_xattrs_blob-due-to-stale-blob-size.patch new file mode 100644 index 0000000000..7af007c247 --- /dev/null +++ b/queue-7.0/ceph-fix-bug_on-in-__ceph_build_xattrs_blob-due-to-stale-blob-size.patch @@ -0,0 +1,125 @@ +From 0c22d9511cbde746622f8e4c11aaa63fe76d45f9 Mon Sep 17 00:00:00 2001 +From: Viacheslav Dubeyko +Date: Thu, 9 Apr 2026 12:43:40 -0700 +Subject: ceph: fix BUG_ON in __ceph_build_xattrs_blob() due to stale blob size + +From: Viacheslav Dubeyko + +commit 0c22d9511cbde746622f8e4c11aaa63fe76d45f9 upstream. + +The generic/642 test-case can reproduce the kernel crash: + +[40243.605254] ------------[ cut here ]------------ +[40243.605956] kernel BUG at fs/ceph/xattr.c:918! +[40243.607142] Oops: invalid opcode: 0000 [#1] SMP PTI +[40243.608067] CPU: 7 UID: 0 PID: 498762 Comm: kworker/7:1 Not tainted 7.0.0-rc7+ #3 PREEMPT(full) +[40243.609700] Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[40243.611820] Workqueue: ceph-msgr ceph_con_workfn +[40243.612715] RIP: 0010:__ceph_build_xattrs_blob+0x1b8/0x1e0 +[40243.613731] Code: 0f 84 82 fe ff ff e9 cf 8e 56 ff 48 8d 65 e8 31 c0 5b 41 5c 41 5d 5d 31 d2 31 c9 31 f6 31 ff 45 31 c0 45 31 c9 c3 cc cc cc cc <0f> 0b 4c 8b 62 08 41 8b 85 24 07 00 00 49 83 c4 04 41 89 44 24 fc +[40243.616888] RSP: 0018:ffffcc80c4d4b688 EFLAGS: 00010287 +[40243.617773] RAX: 0000000000010026 RBX: 0000000000000001 RCX: 0000000000000000 +[40243.618928] RDX: ffff8a773798dee0 RSI: 0000000000000000 RDI: 0000000000000000 +[40243.620158] RBP: ffffcc80c4d4b6a0 R08: 0000000000000000 R09: 0000000000000000 +[40243.621573] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a75f3b58000 +[40243.622907] R13: ffff8a75f3b58000 R14: 0000000000000080 R15: 000000000000bffd +[40243.624054] FS: 0000000000000000(0000) GS:ffff8a787d1b4000(0000) knlGS:0000000000000000 +[40243.625331] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[40243.626269] CR2: 000072f390b623c0 CR3: 000000011c02a003 CR4: 0000000000372ef0 +[40243.627408] Call Trace: +[40243.627839] +[40243.628188] __prep_cap+0x3fd/0x4a0 +[40243.628789] ? do_raw_spin_unlock+0x4e/0xe0 +[40243.629474] ceph_check_caps+0x46a/0xc80 +[40243.630094] ? __lock_acquire+0x4a2/0x2650 +[40243.630773] ? find_held_lock+0x31/0x90 +[40243.631347] ? handle_cap_grant+0x79f/0x1060 +[40243.632068] ? lock_release+0xd9/0x300 +[40243.632696] ? __mutex_unlock_slowpath+0x3e/0x340 +[40243.633429] ? lock_release+0xd9/0x300 +[40243.634052] handle_cap_grant+0xcf6/0x1060 +[40243.634745] ceph_handle_caps+0x122b/0x2110 +[40243.635415] mds_dispatch+0x5bd/0x2160 +[40243.636034] ? ceph_con_process_message+0x65/0x190 +[40243.636828] ? lock_release+0xd9/0x300 +[40243.637431] ceph_con_process_message+0x7a/0x190 +[40243.638184] ? kfree+0x311/0x4f0 +[40243.638749] ? kfree+0x311/0x4f0 +[40243.639268] process_message+0x16/0x1a0 +[40243.639915] ? sg_free_table+0x39/0x90 +[40243.640572] ceph_con_v2_try_read+0xf58/0x2120 +[40243.641255] ? lock_acquire+0xc8/0x300 +[40243.641863] ceph_con_workfn+0x151/0x820 +[40243.642493] process_one_work+0x22f/0x630 +[40243.643093] ? process_one_work+0x254/0x630 +[40243.643770] worker_thread+0x1e2/0x400 +[40243.644332] ? __pfx_worker_thread+0x10/0x10 +[40243.645020] kthread+0x109/0x140 +[40243.645560] ? __pfx_kthread+0x10/0x10 +[40243.646125] ret_from_fork+0x3f8/0x480 +[40243.646752] ? __pfx_kthread+0x10/0x10 +[40243.647316] ? __pfx_kthread+0x10/0x10 +[40243.647919] ret_from_fork_asm+0x1a/0x30 +[40243.648556] +[40243.648902] Modules linked in: overlay hctr2 libpolyval chacha libchacha adiantum libnh libpoly1305 essiv intel_rapl_msr intel_rapl_common intel_uncore_frequency_common skx_edac_common nfit kvm_intel kvm irqbypass joydev ghash_clmulni_intel aesni_intel rapl input_leds mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 pata_acpi bochs qemu_fw_cfg i2c_smbus sch_fq_codel rbd dm_crypt msr parport_pc ppdev lp parport efi_pstore +[40243.654766] ---[ end trace 0000000000000000 ]--- + +Commit d93231a6bc8a ("ceph: prevent a client from exceeding the MDS +maximum xattr size") moved the required_blob_size computation to before +the __build_xattrs() call, introducing a race. + +__build_xattrs() releases and reacquires i_ceph_lock during execution. +In that window, handle_cap_grant() may update i_xattrs.blob with a +newer MDS-provided blob and bump i_xattrs.version. When +__build_xattrs() detects that index_version < version, it destroys and +rebuilds the entire xattr rb-tree from the new blob, potentially +increasing count, names_size, and vals_size. + +The prealloc_blob size check that follows still uses the stale +required_blob_size computed before the rebuild, so it passes even when +prealloc_blob is too small for the now-larger tree. After __set_xattr() +adds one more xattr on top, __ceph_build_xattrs_blob() is called from +the cap flush path and hits: + + BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len); + +Fix this by recomputing required_blob_size after __build_xattrs() +returns, using the current tree state. Also re-validate against +m_max_xattr_size to fall back to the sync path if the rebuilt tree now +exceeds the MDS limit. + +Cc: stable@vger.kernel.org +Fixes: d93231a6bc8a ("ceph: prevent a client from exceeding the MDS maximum xattr size") +Signed-off-by: Viacheslav Dubeyko +Reviewed-by: Alex Markuze +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/xattr.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/fs/ceph/xattr.c ++++ b/fs/ceph/xattr.c +@@ -1254,6 +1254,22 @@ retry: + ceph_vinop(inode), name, ceph_cap_string(issued)); + __build_xattrs(inode); + ++ /* ++ * __build_xattrs() may have released and reacquired i_ceph_lock, ++ * during which handle_cap_grant() could have replaced i_xattrs.blob ++ * with a newer MDS-provided blob and bumped i_xattrs.version. If that ++ * caused __build_xattrs() to rebuild the rb-tree from the new blob, ++ * count/names_size/vals_size may now be larger than when ++ * required_blob_size was computed above. Recompute it here so the ++ * prealloc_blob size check below reflects the current tree state. ++ */ ++ required_blob_size = __get_required_blob_size(ci, name_len, val_len); ++ if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) { ++ doutc(cl, "sync (size too large): %d > %llu\n", ++ required_blob_size, mdsc->mdsmap->m_max_xattr_size); ++ goto do_sync; ++ } ++ + if (!ci->i_xattrs.prealloc_blob || + required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { + struct ceph_buffer *blob; diff --git a/queue-7.0/ceph-put-folios-not-suitable-for-writeback.patch b/queue-7.0/ceph-put-folios-not-suitable-for-writeback.patch new file mode 100644 index 0000000000..a4582cb953 --- /dev/null +++ b/queue-7.0/ceph-put-folios-not-suitable-for-writeback.patch @@ -0,0 +1,42 @@ +From 544576f0f05c4a759806acddfaaeb686f14fb4b0 Mon Sep 17 00:00:00 2001 +From: Hristo Venev +Date: Mon, 4 May 2026 18:54:45 +0300 +Subject: ceph: put folios not suitable for writeback + +From: Hristo Venev + +commit 544576f0f05c4a759806acddfaaeb686f14fb4b0 upstream. + +The batch holds references to the folios (see `filemap_get_folios`, +`folio_batch_release`), so we need to `folio_put` the folios we remove. + +Tested on v6.18. + +Cc: stable@vger.kernel.org +Link: https://tracker.ceph.com/issues/74156 +Signed-off-by: Hristo Venev +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/addr.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -1322,6 +1322,7 @@ void ceph_process_folio_batch(struct add + ceph_wbc, folio); + if (rc == -ENODATA) { + folio_unlock(folio); ++ folio_put(folio); + ceph_wbc->fbatch.folios[i] = NULL; + continue; + } else if (rc == -E2BIG) { +@@ -1332,6 +1333,7 @@ void ceph_process_folio_batch(struct add + if (!folio_clear_dirty_for_io(folio)) { + doutc(cl, "%p !folio_clear_dirty_for_io\n", folio); + folio_unlock(folio); ++ folio_put(folio); + ceph_wbc->fbatch.folios[i] = NULL; + continue; + } diff --git a/queue-7.0/drm-amd-display-wrap-dcn32-phantom-plane-allocation-in-dc_run_with_preemption_enabled.patch b/queue-7.0/drm-amd-display-wrap-dcn32-phantom-plane-allocation-in-dc_run_with_preemption_enabled.patch new file mode 100644 index 0000000000..5e086e6940 --- /dev/null +++ b/queue-7.0/drm-amd-display-wrap-dcn32-phantom-plane-allocation-in-dc_run_with_preemption_enabled.patch @@ -0,0 +1,65 @@ +From 183182235f6d53bac62c6c39014738a54a68dfa6 Mon Sep 17 00:00:00 2001 +From: Mikhail Gavrilov +Date: Tue, 5 May 2026 09:05:37 +0800 +Subject: drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED + +From: Mikhail Gavrilov + +commit 183182235f6d53bac62c6c39014738a54a68dfa6 upstream. + +[Why] +dcn32_validate_bandwidth() wraps dcn32_internal_validate_bw() with +DC_FP_START()/DC_FP_END(). In x86 non-RT, DC_FP_START takes fpregs_lock(), +which disables local softirqs. + +The DML1 path through dcn32_enable_phantom_plane() calls kvzalloc() to +allocate ~335 KiB for dc_plane_state. This triggers the vmalloc path, +which calls BUG_ON(in_interrupt()) because it's invoked within the +FPU-enabled (softirq disabled) region, leading to a kernel crash. + +[How] +Wrap the dc_state_create_phantom_plane() call with the +DC_RUN_WITH_PREEMPTION_ENABLED() macro to allow preemption during +this memory allocation. + +Fixes: 235c67634230 ("drm/amd/display: add DCN32/321 specific files for Display Core") +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4470 +Reviewed-by: Aurabindo Pillai +Signed-off-by: Mikhail Gavrilov +Signed-off-by: James Lin +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +(cherry picked from commit 885ccbef7b94a8b38f69c4211c679021aa27ad11) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +@@ -92,9 +92,14 @@ + #include "dml/dcn32/dcn32_fpu.h" + + #include "dc_state_priv.h" ++#include "dc_fpu.h" + + #include "dml2_0/dml2_wrapper.h" + ++#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED) ++#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code ++#endif ++ + #define DC_LOGGER_INIT(logger) + + enum dcn32_clk_src_array_id { +@@ -1684,7 +1689,8 @@ static void dcn32_enable_phantom_plane(s + if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) + phantom_plane = prev_phantom_plane; + else +- phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state); ++ DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane = ++ dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state)); + + if (!phantom_plane) + continue; diff --git a/queue-7.0/drm-bridge-imx8qxp-pxl2dpi-avoid-err_ptr-with-device_node-cleanup.patch b/queue-7.0/drm-bridge-imx8qxp-pxl2dpi-avoid-err_ptr-with-device_node-cleanup.patch new file mode 100644 index 0000000000..f9f91ae35b --- /dev/null +++ b/queue-7.0/drm-bridge-imx8qxp-pxl2dpi-avoid-err_ptr-with-device_node-cleanup.patch @@ -0,0 +1,120 @@ +From 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Thu, 7 May 2026 18:06:03 +0800 +Subject: drm/bridge: imx8qxp-pxl2dpi: avoid ERR_PTR with device_node cleanup + +From: Guangshuo Li + +commit 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb upstream. + +imx8qxp_pxl2dpi_get_available_ep_from_port() returns ERR_PTR() +on errors. imx8qxp_pxl2dpi_find_next_bridge() stores its return +value in a __free(device_node) variable before checking IS_ERR(). +When the function returns on the error path, the cleanup action calls +of_node_put() on the ERR_PTR() value. + +Do not let a device_node cleanup variable hold error pointers. Change +imx8qxp_pxl2dpi_get_available_ep_from_port() to return an int and pass +the endpoint node through an output argument. Initialize the output +argument to NULL so callers hold either NULL on error paths or a valid +device_node pointer on successful path. + +Fixes: ceea3f7806a10 ("drm/bridge: imx8qxp-pxl2dpi: simplify put of device_node pointers") +Cc: stable@vger.kernel.org +Reviewed-by: Liu Ying +Signed-off-by: Guangshuo Li +Link: https://patch.msgid.link/20260507100604.667731-1-lgs201920130244@gmail.com +Signed-off-by: Liu Ying +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 40 +++++++++++++++------------ + 1 file changed, 23 insertions(+), 17 deletions(-) + +--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c ++++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c +@@ -222,52 +222,58 @@ static const struct drm_bridge_funcs imx + imx8qxp_pxl2dpi_bridge_atomic_get_output_bus_fmts, + }; + +-static struct device_node * ++static int + imx8qxp_pxl2dpi_get_available_ep_from_port(struct imx8qxp_pxl2dpi *p2d, +- u32 port_id) ++ u32 port_id, ++ struct device_node **ep) + { +- struct device_node *port, *ep; ++ struct device_node *port; ++ int ret = 0; + int ep_cnt; + ++ *ep = NULL; ++ + port = of_graph_get_port_by_id(p2d->dev->of_node, port_id); + if (!port) { + DRM_DEV_ERROR(p2d->dev, "failed to get port@%u\n", port_id); +- return ERR_PTR(-ENODEV); ++ return -ENODEV; + } + + ep_cnt = of_get_available_child_count(port); + if (ep_cnt == 0) { + DRM_DEV_ERROR(p2d->dev, "no available endpoints of port@%u\n", + port_id); +- ep = ERR_PTR(-ENODEV); ++ ret = -ENODEV; + goto out; + } else if (ep_cnt > 1) { + DRM_DEV_ERROR(p2d->dev, + "invalid available endpoints of port@%u\n", + port_id); +- ep = ERR_PTR(-EINVAL); ++ ret = -EINVAL; + goto out; + } + +- ep = of_get_next_available_child(port, NULL); +- if (!ep) { ++ *ep = of_get_next_available_child(port, NULL); ++ if (!*ep) { + DRM_DEV_ERROR(p2d->dev, + "failed to get available endpoint of port@%u\n", + port_id); +- ep = ERR_PTR(-ENODEV); ++ ret = -ENODEV; + goto out; + } + out: + of_node_put(port); +- return ep; ++ return ret; + } + + static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d) + { +- struct device_node *ep __free(device_node) = +- imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1); +- if (IS_ERR(ep)) +- return PTR_ERR(ep); ++ struct device_node *ep __free(device_node) = NULL; ++ int ret; ++ ++ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1, &ep); ++ if (ret) ++ return ret; + + struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { +@@ -291,9 +297,9 @@ static int imx8qxp_pxl2dpi_set_pixel_lin + struct of_endpoint endpoint; + int ret; + +- ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0); +- if (IS_ERR(ep)) +- return PTR_ERR(ep); ++ ret = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 0, &ep); ++ if (ret) ++ return ret; + + ret = of_graph_parse_endpoint(ep, &endpoint); + if (ret) { diff --git a/queue-7.0/drm-i915-dp-fix-vsc-dynamic-range-signaling-for-rgb-formats.patch b/queue-7.0/drm-i915-dp-fix-vsc-dynamic-range-signaling-for-rgb-formats.patch new file mode 100644 index 0000000000..9d1d501ef8 --- /dev/null +++ b/queue-7.0/drm-i915-dp-fix-vsc-dynamic-range-signaling-for-rgb-formats.patch @@ -0,0 +1,55 @@ +From 1ae15b6c7965d137eef21f2cc7d367b29cb88369 Mon Sep 17 00:00:00 2001 +From: Chaitanya Kumar Borah +Date: Tue, 5 May 2026 14:39:20 +0530 +Subject: drm/i915/dp: Fix VSC dynamic range signaling for RGB formats + +From: Chaitanya Kumar Borah + +commit 1ae15b6c7965d137eef21f2cc7d367b29cb88369 upstream. + +For RGB, set dynamic_range to CTA or VESA based on +crtc_state->limited_color_range so sinks apply correct +quantization. YCbCr remains limited (CTA) range. +(DP v1.4, Table 5-1) + +v2: +- Added Reported-by and Tested-by tags + +v3: +- Add back YCbCr comment(Suraj) + +Cc: stable@vger.kernel.org #v5.8+ +Reported-by: DeepChirp +Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/15874 +Tested-by: DeepChirp +Fixes: 9799c4c3b76e ("drm/i915/dp: Add compute routine for DP VSC SDP") +Assisted-by: GitHub-Copilot:GPT-5.4 +Signed-off-by: Chaitanya Kumar Borah +Reviewed-by: Suraj Kandpal +Signed-off-by: Suraj Kandpal +Link: https://patch.msgid.link/20260505090920.2479112-1-chaitanya.kumar.borah@intel.com +(cherry picked from commit 38e10ddae6f8d42a2e8437fcd25a1cac51106c64) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_dp.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -2981,8 +2981,13 @@ static void intel_dp_compute_vsc_colorim + drm_WARN_ON(display->drm, + vsc->bpc == 6 && vsc->pixelformat != DP_PIXELFORMAT_RGB); + +- /* all YCbCr are always limited range */ +- vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA; ++ /* All YCbCr formats are always limited range. */ ++ if (vsc->pixelformat == DP_PIXELFORMAT_RGB) ++ vsc->dynamic_range = crtc_state->limited_color_range ? ++ DP_DYNAMIC_RANGE_CTA : DP_DYNAMIC_RANGE_VESA; ++ else ++ vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA; ++ + vsc->content_type = DP_CONTENT_TYPE_NOT_DEFINED; + } + diff --git a/queue-7.0/drm-i915-skip-__i915_request_skip-for-already-signaled-requests.patch b/queue-7.0/drm-i915-skip-__i915_request_skip-for-already-signaled-requests.patch new file mode 100644 index 0000000000..a44605ce65 --- /dev/null +++ b/queue-7.0/drm-i915-skip-__i915_request_skip-for-already-signaled-requests.patch @@ -0,0 +1,61 @@ +From 4cfe4c0efbdcde742a47813180cc69b132d7598e Mon Sep 17 00:00:00 2001 +From: Sebastian Brzezinka +Date: Thu, 16 Apr 2026 13:31:18 +0200 +Subject: drm/i915: skip __i915_request_skip() for already signaled requests + +From: Sebastian Brzezinka + +commit 4cfe4c0efbdcde742a47813180cc69b132d7598e upstream. + +After a GPU reset the HWSP is zeroed, so previously completed +requests appear incomplete. If such a request is picked up during +reset_rewind() and marked guilty, i915_request_set_error_once() +returns early (fence already signaled), leaving fence.error without +a fatal error code. The subsequent __i915_request_skip() then hits: +``` +GEM_BUG_ON(!fatal_error(rq->fence.error)) +``` + +Fixes a kernel BUG observed on Sandy Bridge (Gen6) during +heartbeat-triggered engine resets. +``` +kernel BUG at drivers/gpu/drm/i915/i915_request.c:556! +RIP: __i915_request_skip+0x15e/0x1d0 [i915] +... +__i915_request_reset+0x212/0xa70 [i915] +reset_rewind+0xe4/0x280 [i915] +intel_gt_reset+0x30d/0x5b0 [i915] +heartbeat+0x516/0x530 [i915] +``` + +Guard __i915_request_skip() with i915_request_signaled(), if the +fence is already signaled, the ring content is committed and there +is nothing left to skip. + +Fixes: 36e191f0644b ("drm/i915: Apply i915_request_skip() on submission") +Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/13729 +Signed-off-by: Sebastian Brzezinka +Cc: stable@vger.kernel.org # v5.7+ +Reviewed-by: Krzysztof Karas +Reviewed-by: Andi Shyti +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/fe76921d35b6ae85aa651822726d0d9815aa5362.1776339012.git.sebastian.brzezinka@intel.com +(cherry picked from commit 5ba54393dcd7adf75a9f39f5a933b1538349cad5) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/gt/intel_reset.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/gt/intel_reset.c ++++ b/drivers/gpu/drm/i915/gt/intel_reset.c +@@ -132,7 +132,8 @@ void __i915_request_reset(struct i915_re + rcu_read_lock(); /* protect the GEM context */ + if (guilty) { + i915_request_set_error_once(rq, -EIO); +- __i915_request_skip(rq); ++ if (!i915_request_signaled(rq)) ++ __i915_request_skip(rq); + banned = mark_guilty(rq); + } else { + i915_request_set_error_once(rq, -EAGAIN); diff --git a/queue-7.0/drm-loongson-use-managed-kms-polling.patch b/queue-7.0/drm-loongson-use-managed-kms-polling.patch new file mode 100644 index 0000000000..bd4d38d46e --- /dev/null +++ b/queue-7.0/drm-loongson-use-managed-kms-polling.patch @@ -0,0 +1,46 @@ +From 0a9c56dd387605d17dabeedd9fdd2c4c1d0bab7b Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Wed, 13 May 2026 15:57:00 +0900 +Subject: drm/loongson: Use managed KMS polling + +From: Myeonghun Pak + +commit 0a9c56dd387605d17dabeedd9fdd2c4c1d0bab7b upstream. + +lsdc_pci_probe() initializes KMS polling before setting up vblank support, +requesting the IRQ and registering the DRM device. If any of those later +steps fails, probe returns without finalizing polling. The driver also +never finalizes polling on regular removal. + +Use drmm_kms_helper_poll_init() so polling is tied to the DRM device +lifetime and automatically finalized on probe failure and device removal. + +This issue was identified during our ongoing static-analysis research while +reviewing kernel code. + +Fixes: f39db26c5428 ("drm: Add kms driver for loongson display controller") +Cc: stable@vger.kernel.org +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Reviewed-by: Thomas Zimmermann +Acked-by: Jianmin Lv +Reviewed-by: Huacai Chen +Signed-off-by: Myeonghun Pak +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260513065706.23803-1-mhun512@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/loongson/lsdc_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/loongson/lsdc_drv.c ++++ b/drivers/gpu/drm/loongson/lsdc_drv.c +@@ -292,7 +292,7 @@ static int lsdc_pci_probe(struct pci_dev + + vga_client_register(pdev, lsdc_vga_set_decode); + +- drm_kms_helper_poll_init(ddev); ++ drmm_kms_helper_poll_init(ddev); + + if (loongson_vblank) { + ret = drm_vblank_init(ddev, descp->num_of_crtc); diff --git a/queue-7.0/drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch b/queue-7.0/drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch new file mode 100644 index 0000000000..2369698ae6 --- /dev/null +++ b/queue-7.0/drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch @@ -0,0 +1,43 @@ +From 459d75523b71c0ec254d153d8850d0b7008af396 Mon Sep 17 00:00:00 2001 +From: Gyeyoung Baek +Date: Sun, 19 Apr 2026 16:17:16 +0900 +Subject: drm/panfrost: Fix wait_bo ioctl leaking positive return from dma_resv_wait_timeout() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Gyeyoung Baek + +commit 459d75523b71c0ec254d153d8850d0b7008af396 upstream. + +dma_resv_wait_timeout() returns a positive 'remaining jiffies' value +on success, 0 on timeout, and -errno on failure. + +panfrost_ioctl_wait_bo() returns this 'long' result from an int-typed +ioctl handler, so positive values reach userspace as bogus errors. +Explicitly set ret to 0 on the success path. + +Fixes: f3ba91228e8e ("drm/panfrost: Add initial panfrost driver") +Cc: stable@vger.kernel.org +Signed-off-by: Gyeyoung Baek +Reviewed-by: Adrián Larumbe +Reviewed-by: Boris Brezillon +Reviewed-by: Steven Price +Link: https://patch.msgid.link/fe33f82fded7be1c18e2e0eb2db451d5a738cf39.1776581974.git.gye976@gmail.com +Signed-off-by: Steven Price +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/panfrost/panfrost_drv.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -390,6 +390,8 @@ panfrost_ioctl_wait_bo(struct drm_device + true, timeout); + if (!ret) + ret = timeout ? -ETIMEDOUT : -EBUSY; ++ else if (ret > 0) ++ ret = 0; + + drm_gem_object_put(gem_obj); + diff --git a/queue-7.0/drm-replace-old-pointer-to-new-idr.patch b/queue-7.0/drm-replace-old-pointer-to-new-idr.patch new file mode 100644 index 0000000000..57a91bef14 --- /dev/null +++ b/queue-7.0/drm-replace-old-pointer-to-new-idr.patch @@ -0,0 +1,72 @@ +From dc366607c41c45fd0ae6f3db090f31dd611b644a Mon Sep 17 00:00:00 2001 +From: Edward Adam Davis +Date: Wed, 13 May 2026 12:30:50 +0800 +Subject: drm: Replace old pointer to new idr + +From: Edward Adam Davis + +commit dc366607c41c45fd0ae6f3db090f31dd611b644a upstream. + +Commit 5e28b7b94408 introduced a logical error by failing to replace the +newly generated IDR pointer to old id's pointer at the correct location +within the "change handle" logic; this resulted in the issue reported by +syzbot [1]. + +Specifically, the new IDR object pointer is intended to replace the original +id's pointer during the normal execution flow. + +Additionally, an unnecessary conditional check for the ret exit path has +been removed. + +[1] +!RB_EMPTY_ROOT(&prime_fpriv->dmabufs) +WARNING: drivers/gpu/drm/drm_prime.c:224 at drm_prime_destroy_file_private+0x48/0x60 drivers/gpu/drm/drm_prime.c:224, CPU#0: syz.0.17/5833 +Call Trace: + drm_file_free.part.0+0x7e6/0xcc0 drivers/gpu/drm/drm_file.c:269 + drm_file_free drivers/gpu/drm/drm_file.c:237 [inline] + drm_close_helper.isra.0+0x186/0x200 drivers/gpu/drm/drm_file.c:290 + drm_release+0x1ab/0x360 drivers/gpu/drm/drm_file.c:438 + +Fixes: 5e28b7b94408 ("drm: Set old handle to NULL before prime swap in change_handle") +Reported-by: syzbot+d7c9eed171647e421013@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d7c9eed171647e421013 +Cc: stable@vger.kernel.org +Tested-by: syzbot+d7c9eed171647e421013@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/tencent_C267296443AAA4567771176886DFF364A305@qq.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/drm_gem.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -1049,17 +1049,12 @@ int drm_gem_change_handle_ioctl(struct d + + spin_unlock(&file_priv->table_lock); + +- if (ret < 0) +- goto out_unlock; +- + if (obj->dma_buf) { + ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, + handle); + if (ret < 0) { + spin_lock(&file_priv->table_lock); + idr_remove(&file_priv->object_idr, handle); +- idrobj = idr_replace(&file_priv->object_idr, obj, handle); +- WARN_ON(idrobj != NULL); + spin_unlock(&file_priv->table_lock); + goto out_unlock; + } +@@ -1071,7 +1066,9 @@ int drm_gem_change_handle_ioctl(struct d + + spin_lock(&file_priv->table_lock); + idr_remove(&file_priv->object_idr, args->handle); ++ idrobj = idr_replace(&file_priv->object_idr, obj, handle); + spin_unlock(&file_priv->table_lock); ++ WARN_ON(idrobj != NULL); + + out_unlock: + mutex_unlock(&file_priv->prime.lock); diff --git a/queue-7.0/drm-ttm-convert-eagain-from-dmem_cgroup_try_charge-to-enospc.patch b/queue-7.0/drm-ttm-convert-eagain-from-dmem_cgroup_try_charge-to-enospc.patch new file mode 100644 index 0000000000..e5ed4bc319 --- /dev/null +++ b/queue-7.0/drm-ttm-convert-eagain-from-dmem_cgroup_try_charge-to-enospc.patch @@ -0,0 +1,67 @@ +From 591711b32681a04b57d00c2a404658f8419a081c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= +Date: Fri, 8 May 2026 18:09:20 +0200 +Subject: drm/ttm: Convert -EAGAIN from dmem_cgroup_try_charge to -ENOSPC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +commit 591711b32681a04b57d00c2a404658f8419a081c upstream. + +dmem_cgroup_try_charge() returns -EAGAIN when the cgroup limit is +hit and the charge fails. TTM has no concept of -EAGAIN from resource +allocation; -ENOSPC is the canonical error meaning "no space, try +eviction". Convert at the source in ttm_resource_alloc() so no caller +needs to handle an unexpected error code, and clean up the now-redundant +-EAGAIN check in ttm_bo_alloc_resource(). + +Without this, -EAGAIN escaping ttm_resource_alloc() during an eviction +walk causes the walk to terminate early instead of continuing to the +next candidate. + +Cc: Friedrich Vock +Cc: Maarten Lankhorst +Cc: Tejun Heo +Cc: Maxime Ripard +Cc: Christian Koenig +Cc: dri-devel@lists.freedesktop.org +Cc: # v6.14+ +Fixes: 2b624a2c1865 ("drm/ttm: Handle cgroup based eviction in TTM") +Assisted-by: GitHub_Copilot:claude-sonnet-4.6 +Signed-off-by: Thomas Hellström +Reviewed-by: Maarten Lankhorst +Link: https://patch.msgid.link/20260508160920.230339-1-thomas.hellstrom@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/ttm/ttm_bo.c | 2 +- + drivers/gpu/drm/ttm/ttm_resource.c | 5 ++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/ttm/ttm_bo.c ++++ b/drivers/gpu/drm/ttm/ttm_bo.c +@@ -740,7 +740,7 @@ static int ttm_bo_alloc_resource(struct + may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM); + ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL); + if (ret) { +- if (ret != -ENOSPC && ret != -EAGAIN) { ++ if (ret != -ENOSPC) { + dmem_cgroup_pool_state_put(limit_pool); + return ret; + } +--- a/drivers/gpu/drm/ttm/ttm_resource.c ++++ b/drivers/gpu/drm/ttm/ttm_resource.c +@@ -398,8 +398,11 @@ int ttm_resource_alloc(struct ttm_buffer + + if (man->cg) { + ret = dmem_cgroup_try_charge(man->cg, bo->base.size, &pool, ret_limit_pool); +- if (ret) ++ if (ret) { ++ if (ret == -EAGAIN) ++ ret = -ENOSPC; + return ret; ++ } + } + + ret = man->func->alloc(man, bo, place, res_ptr); diff --git a/queue-7.0/drm-ttm-fix-ttm_bo_shrink-infinite-lru-walk-on-backup-failure.patch b/queue-7.0/drm-ttm-fix-ttm_bo_shrink-infinite-lru-walk-on-backup-failure.patch new file mode 100644 index 0000000000..a6812d9265 --- /dev/null +++ b/queue-7.0/drm-ttm-fix-ttm_bo_shrink-infinite-lru-walk-on-backup-failure.patch @@ -0,0 +1,61 @@ +From 1d59f36e95f7f7134db0e313c9d787cb0adb2153 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= +Date: Mon, 11 May 2026 18:24:43 +0200 +Subject: drm/ttm: Fix ttm_bo_shrink() infinite LRU walk on backup failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +commit 1d59f36e95f7f7134db0e313c9d787cb0adb2153 upstream. + +Apply the same fix as b2ed01e7ad ("drm/ttm: Fix ttm_bo_swapout() +infinite LRU walk on swapout failure") to the ttm_bo_shrink() path. + +Move del_bulk_move from before the backup to after success only, +using ttm_resource_del_bulk_move_unevictable() since the resource +is now unevictable once fully backed up. + +Fixes: 70d645deac98 ("drm/ttm: Add helpers for shrinking") +Cc: Christian König +Cc: Huang Rui +Cc: Matthew Auld +Cc: Matthew Brost +Cc: Dave Airlie +Cc: dri-devel@lists.freedesktop.org +Cc: stable@vger.kernel.org # v6.15+ +Assisted-by: GitHub_Copilot:claude-opus-4.6 +Reviewed-by: Matthew Auld +Link: https://patch.msgid.link/20260511162443.24352-1-thomas.hellstrom@linux.intel.com +Signed-off-by: Thomas Hellström +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/ttm/ttm_bo_util.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/ttm/ttm_bo_util.c ++++ b/drivers/gpu/drm/ttm/ttm_bo_util.c +@@ -1112,19 +1112,14 @@ long ttm_bo_shrink(struct ttm_operation_ + if (lret < 0) + return lret; + +- if (bo->bulk_move) { +- spin_lock(&bdev->lru_lock); +- ttm_resource_del_bulk_move(bo->resource, bo); +- spin_unlock(&bdev->lru_lock); +- } +- + lret = ttm_tt_backup(bdev, bo->ttm, (struct ttm_backup_flags) + {.purge = flags.purge, + .writeback = flags.writeback}); + +- if (lret <= 0 && bo->bulk_move) { ++ if (lret > 0) { + spin_lock(&bdev->lru_lock); +- ttm_resource_add_bulk_move(bo->resource, bo); ++ ttm_resource_del_bulk_move_unevictable(bo->resource, bo); ++ ttm_resource_move_to_lru_tail(bo->resource); + spin_unlock(&bdev->lru_lock); + } + diff --git a/queue-7.0/drm-ttm-fix-ttm_bo_swapout-infinite-lru-walk-on-swapout-failure.patch b/queue-7.0/drm-ttm-fix-ttm_bo_swapout-infinite-lru-walk-on-swapout-failure.patch new file mode 100644 index 0000000000..a3ab4ea5d5 --- /dev/null +++ b/queue-7.0/drm-ttm-fix-ttm_bo_swapout-infinite-lru-walk-on-swapout-failure.patch @@ -0,0 +1,107 @@ +From b2ed01e7ad3de80333e9b962a44024b094bc0b2b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= +Date: Tue, 28 Apr 2026 11:44:42 +0200 +Subject: drm/ttm: Fix ttm_bo_swapout() infinite LRU walk on swapout failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +commit b2ed01e7ad3de80333e9b962a44024b094bc0b2b upstream. + +When ttm_tt_swapout() fails, the current code calls +ttm_resource_add_bulk_move() followed by ttm_resource_move_to_lru_tail() +to restore the resource's bulk_move membership. + +However, ttm_resource_move_to_lru_tail() places the resource at the tail +of the LRU list which, relative to the walk cursor's hitch node (placed +immediately after the resource when it was yielded), puts the resource +*in front of the* the hitch. The next list_for_each_entry_continue() from +the hitch finds the same resource again, causing an infinite loop. + +Fix by deferring del_bulk_move to the success path only. + +On the success path, TTM_TT_FLAG_SWAPPED has just been set by +ttm_tt_swapout() but the resource is still tracked in the bulk_move range, +so ttm_resource_del_bulk_move()'s !ttm_resource_unevictable() guard would +incorrectly skip the removal. Introduce +ttm_resource_del_bulk_move_unevictable() which bypasses that guard. + +Reported-by: Jatin Kataria +Fixes: fc5d96670eb2 ("drm/ttm: Move swapped objects off the manager's LRU list") +Cc: Christian König +Cc: Matthew Brost +Cc: +Cc: # v6.13+ +Assisted-by: GitHub_Copilot:claude-sonnet-4.6 +Signed-off-by: Thomas Hellström +Reviewed-by: Christian König +Tested-by: Boqun Feng +Link: https://patch.msgid.link/20260428094442.16985-1-thomas.hellstrom@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/ttm/ttm_bo.c | 16 ++++++---------- + drivers/gpu/drm/ttm/ttm_resource.c | 13 +++++++++++++ + include/drm/ttm/ttm_resource.h | 2 ++ + 3 files changed, 21 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/ttm/ttm_bo.c ++++ b/drivers/gpu/drm/ttm/ttm_bo.c +@@ -1178,17 +1178,13 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *w + bdev->funcs->swap_notify(bo); + + if (ttm_tt_is_populated(tt)) { +- spin_lock(&bdev->lru_lock); +- ttm_resource_del_bulk_move(bo->resource, bo); +- spin_unlock(&bdev->lru_lock); +- + ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags); +- +- spin_lock(&bdev->lru_lock); +- if (ret) +- ttm_resource_add_bulk_move(bo->resource, bo); +- ttm_resource_move_to_lru_tail(bo->resource); +- spin_unlock(&bdev->lru_lock); ++ if (!ret) { ++ spin_lock(&bdev->lru_lock); ++ ttm_resource_del_bulk_move_unevictable(bo->resource, bo); ++ ttm_resource_move_to_lru_tail(bo->resource); ++ spin_unlock(&bdev->lru_lock); ++ } + } + + out: +--- a/drivers/gpu/drm/ttm/ttm_resource.c ++++ b/drivers/gpu/drm/ttm/ttm_resource.c +@@ -292,6 +292,19 @@ void ttm_resource_del_bulk_move(struct t + ttm_lru_bulk_move_del(bo->bulk_move, res); + } + ++/* ++ * Remove a resource from its bulk_move, bypassing the unevictable check. ++ * Use only when the resource is known to still be tracked in the range despite ++ * the BO having just become unevictable; asserts that this is the case. ++ */ ++void ttm_resource_del_bulk_move_unevictable(struct ttm_resource *res, ++ struct ttm_buffer_object *bo) ++{ ++ WARN_ON_ONCE(!ttm_resource_unevictable(res, bo)); ++ if (bo->bulk_move) ++ ttm_lru_bulk_move_del(bo->bulk_move, res); ++} ++ + /* Move a resource to the LRU or bulk tail */ + void ttm_resource_move_to_lru_tail(struct ttm_resource *res) + { +--- a/include/drm/ttm/ttm_resource.h ++++ b/include/drm/ttm/ttm_resource.h +@@ -448,6 +448,8 @@ void ttm_resource_add_bulk_move(struct t + struct ttm_buffer_object *bo); + void ttm_resource_del_bulk_move(struct ttm_resource *res, + struct ttm_buffer_object *bo); ++void ttm_resource_del_bulk_move_unevictable(struct ttm_resource *res, ++ struct ttm_buffer_object *bo); + void ttm_resource_move_to_lru_tail(struct ttm_resource *res); + + void ttm_resource_init(struct ttm_buffer_object *bo, diff --git a/queue-7.0/drm-xe-dma-buf-fix-uaf-with-retry-loop.patch b/queue-7.0/drm-xe-dma-buf-fix-uaf-with-retry-loop.patch new file mode 100644 index 0000000000..2758d409ae --- /dev/null +++ b/queue-7.0/drm-xe-dma-buf-fix-uaf-with-retry-loop.patch @@ -0,0 +1,139 @@ +From 155a372a1cc50fa93387c5d3cdfd614a61e1afd1 Mon Sep 17 00:00:00 2001 +From: Matthew Auld +Date: Fri, 8 May 2026 11:26:37 +0100 +Subject: drm/xe/dma-buf: fix UAF with retry loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Matthew Auld + +commit 155a372a1cc50fa93387c5d3cdfd614a61e1afd1 upstream. + +Retry doesn't work here, since bo will be freed on error, leading to +UAF. However, now that we do the alloc & init before the attach, we can +now combine this as one unit and have the init do the alloc for us. This +should make the retry safe. + +Reported by Sashiko. + +v2: Fix up the error unwind (CI) + +Closes: https://sashiko.dev/#/patchset/20260506184332.86743-2-matthew.auld%40intel.com +Fixes: eb289a5f6cc6 ("drm/xe: Convert xe_dma_buf.c for exhaustive eviction") +Signed-off-by: Matthew Auld +Cc: Thomas Hellström +Cc: Matthew Brost +Cc: # v6.18+ +Reviewed-by: Thomas Hellström +Link: https://patch.msgid.link/20260508102635.149172-4-matthew.auld@intel.com +(cherry picked from commit 479669418253e0f27f8cf5db01a731352ea592e7) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/xe/xe_dma_buf.c | 49 +++++++++------------------------------- + 1 file changed, 12 insertions(+), 37 deletions(-) + +--- a/drivers/gpu/drm/xe/xe_dma_buf.c ++++ b/drivers/gpu/drm/xe/xe_dma_buf.c +@@ -238,16 +238,8 @@ struct dma_buf *xe_gem_prime_export(stru + return buf; + } + +-/* +- * Takes ownership of @storage: on success it is transferred to the returned +- * drm_gem_object; on failure it is freed before returning the error. +- * This matches the contract of xe_bo_init_locked() which frees @storage on +- * its error paths, so callers need not (and must not) free @storage after +- * this call. +- */ + static struct drm_gem_object * +-xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, +- struct dma_buf *dma_buf) ++xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf) + { + struct dma_resv *resv = dma_buf->resv; + struct xe_device *xe = to_xe_device(dev); +@@ -258,10 +250,8 @@ xe_dma_buf_init_obj(struct drm_device *d + int ret = 0; + + dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm); +- if (!dummy_obj) { +- xe_bo_free(storage); ++ if (!dummy_obj) + return ERR_PTR(-ENOMEM); +- } + + dummy_obj->resv = resv; + xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) { +@@ -270,8 +260,7 @@ xe_dma_buf_init_obj(struct drm_device *d + if (ret) + break; + +- /* xe_bo_init_locked() frees storage on error */ +- bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size, ++ bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size, + 0, /* Will require 1way or 2way for vm_bind */ + ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec); + drm_exec_retry_on_contention(&exec); +@@ -322,7 +311,6 @@ struct drm_gem_object *xe_gem_prime_impo + const struct dma_buf_attach_ops *attach_ops; + struct dma_buf_attachment *attach; + struct drm_gem_object *obj; +- struct xe_bo *bo; + + if (dma_buf->ops == &xe_dmabuf_ops) { + obj = dma_buf->priv; +@@ -337,22 +325,14 @@ struct drm_gem_object *xe_gem_prime_impo + } + } + +- bo = xe_bo_alloc(); +- if (IS_ERR(bo)) +- return ERR_CAST(bo); +- + /* +- * xe_dma_buf_init_obj() takes ownership of the raw bo, so do not touch +- * on fail, since it will already take care of cleanup. On success we +- * still need to drop the ref, if something later fails. +- * +- * In addition this needs to happen before the attach, since +- * it will create a new attachment for this, and add it to the list of +- * attachments, at which point it is globally visible, and at any point +- * the export side can call into on invalidate_mappings callback, which +- * require a working object. ++ * This needs to happen before the attach, since it will create a new ++ * attachment for this, and add it to the list of attachments, at which ++ * point it is globally visible, and at any point the export side can ++ * call into on invalidate_mappings callback, which require a working ++ * object. + */ +- obj = xe_dma_buf_init_obj(dev, bo, dma_buf); ++ obj = xe_dma_buf_create_obj(dev, dma_buf); + if (IS_ERR(obj)) + return obj; + +@@ -362,20 +342,15 @@ struct drm_gem_object *xe_gem_prime_impo + attach_ops = test->attach_ops; + #endif + +- attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, &bo->ttm.base); ++ attach = dma_buf_dynamic_attach(dma_buf, dev->dev, attach_ops, obj); + if (IS_ERR(attach)) { +- obj = ERR_CAST(attach); +- goto out_err; ++ xe_bo_put(gem_to_xe_bo(obj)); ++ return ERR_CAST(attach); + } + + get_dma_buf(dma_buf); + obj->import_attach = attach; + return obj; +- +-out_err: +- xe_bo_put(bo); +- +- return obj; + } + + #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) diff --git a/queue-7.0/drm-xe-dma-buf-handle-empty-bo-and-uaf-races.patch b/queue-7.0/drm-xe-dma-buf-handle-empty-bo-and-uaf-races.patch new file mode 100644 index 0000000000..d1be2dc362 --- /dev/null +++ b/queue-7.0/drm-xe-dma-buf-handle-empty-bo-and-uaf-races.patch @@ -0,0 +1,117 @@ +From 981bedbbe61364fcc3a3b87ebaf648a66cd07108 Mon Sep 17 00:00:00 2001 +From: Matthew Auld +Date: Fri, 8 May 2026 11:26:36 +0100 +Subject: drm/xe/dma-buf: handle empty bo and UAF races +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Matthew Auld + +commit 981bedbbe61364fcc3a3b87ebaf648a66cd07108 upstream. + +There look to be some nasty races here when triggering the +invalidate_mappings hook: + +1) We do xe_bo_alloc() followed by the attach, before the actual full bo + init step in xe_dma_buf_init_obj(). However the bo is visible on the + attachments list after the attach. This is bad since exporter driver, + say amdgpu, can at any time call back into our invalidate_mappings hook, + with an empty/bogus bo, leading to potential bugs/crashes. + +2) Similar to 1) but here we get a UAF, when the invalidate_mappings + hook is triggered. For example, we get as far as xe_bo_init_locked() + but this fails in some way. But here the bo will be freed on error, but + we still have it attached from dma-buf pov, so if the + invalidate_mappings is now triggered then the bo we access is gone and + we trigger UAF and more bugs/crashes. + +To fix this, move the attach step until after we actually have a fully +set up buffer object. Note that the bo is not published to userspace +until later, so not sure what the comment "Don't publish the bo +until we have a valid attachment", is referring to. + +We have at least two different customers reporting hitting a NULL ptr +deref in evict_flags when importing something from amdgpu, followed by +triggering the evict flow. Hit rate is also pretty low, which would +hint at some kind of race, so something like 1) or 2) might explain +this. + +v2: + - Shuffle the order of the ops slightly (no functional change) + - Improve the comment to better explain the ordering (Matt B) + +Assisted-by: Gemini:gemini-3 #debug +Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7903 +Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/4055 +Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") +Signed-off-by: Matthew Auld +Cc: Thomas Hellström +Cc: Matthew Brost +Cc: # v6.8+ +Reviewed-by: Matthew Brost +Acked-by: Thomas Hellström +Link: https://patch.msgid.link/20260508102635.149172-3-matthew.auld@intel.com +(cherry picked from commit af1f2ad0c59fe4e2f924c526f66e968289d77971) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/xe/xe_dma_buf.c | 31 ++++++++++++++++--------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +--- a/drivers/gpu/drm/xe/xe_dma_buf.c ++++ b/drivers/gpu/drm/xe/xe_dma_buf.c +@@ -337,15 +337,25 @@ struct drm_gem_object *xe_gem_prime_impo + } + } + +- /* +- * Don't publish the bo until we have a valid attachment, and a +- * valid attachment needs the bo address. So pre-create a bo before +- * creating the attachment and publish. +- */ + bo = xe_bo_alloc(); + if (IS_ERR(bo)) + return ERR_CAST(bo); + ++ /* ++ * xe_dma_buf_init_obj() takes ownership of the raw bo, so do not touch ++ * on fail, since it will already take care of cleanup. On success we ++ * still need to drop the ref, if something later fails. ++ * ++ * In addition this needs to happen before the attach, since ++ * it will create a new attachment for this, and add it to the list of ++ * attachments, at which point it is globally visible, and at any point ++ * the export side can call into on invalidate_mappings callback, which ++ * require a working object. ++ */ ++ obj = xe_dma_buf_init_obj(dev, bo, dma_buf); ++ if (IS_ERR(obj)) ++ return obj; ++ + attach_ops = &xe_dma_buf_attach_ops; + #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) + if (test) +@@ -358,21 +368,12 @@ struct drm_gem_object *xe_gem_prime_impo + goto out_err; + } + +- /* +- * xe_dma_buf_init_obj() takes ownership of bo on both success +- * and failure, so we must not touch bo after this call. +- */ +- obj = xe_dma_buf_init_obj(dev, bo, dma_buf); +- if (IS_ERR(obj)) { +- dma_buf_detach(dma_buf, attach); +- return obj; +- } + get_dma_buf(dma_buf); + obj->import_attach = attach; + return obj; + + out_err: +- xe_bo_free(bo); ++ xe_bo_put(bo); + + return obj; + } diff --git a/queue-7.0/io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch b/queue-7.0/io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch new file mode 100644 index 0000000000..badb1a3b8e --- /dev/null +++ b/queue-7.0/io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch @@ -0,0 +1,52 @@ +From d6a2d7b04b5a093021a7a0e2e69e9d5237dfa8cc Mon Sep 17 00:00:00 2001 +From: Nicholas Carlini +Date: Mon, 11 May 2026 18:02:16 +0000 +Subject: io-wq: check that the predecessor is hashed in io_wq_remove_pending() + +From: Nicholas Carlini + +commit d6a2d7b04b5a093021a7a0e2e69e9d5237dfa8cc upstream. + +io_wq_remove_pending() needs to fix up wq->hash_tail[] if the cancelled +work was the tail of its hash bucket. When doing this, it checks whether +the preceding entry in acct->work_list has the same hash value, but +never checks that the predecessor is hashed at all. io_get_work_hash() +is simply atomic_read(&work->flags) >> IO_WQ_HASH_SHIFT, and the hash +bits are never set for non-hashed work, so it returns 0. Thus, when a +hashed bucket-0 work is cancelled while a non-hashed work is its list +predecessor, the check spuriously passes and a pointer to the non-hashed +io_kiocb is stored in wq->hash_tail[0]. + +Because non-hashed work is dequeued via the fast path in +io_get_next_work(), which never touches hash_tail[], the stale pointer +is never cleared. Therefore, after the non-hashed io_kiocb completes and +is freed back to req_cachep, wq->hash_tail[0] is a dangling pointer. The +io_wq is per-task (tctx->io_wq) and survives ring open/close, so the +dangling pointer persists for the lifetime of the task; the next hashed +bucket-0 enqueue dereferences it in io_wq_insert_work() and +wq_list_add_after() writes through freed memory. + +Add the missing io_wq_is_hashed() check so a non-hashed predecessor +never inherits a hash_tail[] slot. + +Cc: stable@vger.kernel.org +Fixes: 204361a77f40 ("io-wq: fix hang after cancelling pending hashed work") +Signed-off-by: Nicholas Carlini +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + io_uring/io-wq.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/io_uring/io-wq.c ++++ b/io_uring/io-wq.c +@@ -1124,7 +1124,8 @@ static inline void io_wq_remove_pending( + if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) { + if (prev) + prev_work = container_of(prev, struct io_wq_work, list); +- if (prev_work && io_get_work_hash(prev_work) == hash) ++ if (prev_work && io_wq_is_hashed(prev_work) && ++ io_get_work_hash(prev_work) == hash) + wq->hash_tail[hash] = prev_work; + else + wq->hash_tail[hash] = NULL; diff --git a/queue-7.0/iommu-amd-bounds-check-devid-in-__rlookup_amd_iommu.patch b/queue-7.0/iommu-amd-bounds-check-devid-in-__rlookup_amd_iommu.patch new file mode 100644 index 0000000000..de5e4d5284 --- /dev/null +++ b/queue-7.0/iommu-amd-bounds-check-devid-in-__rlookup_amd_iommu.patch @@ -0,0 +1,82 @@ +From 07d0f496fe7ec5abe3bee7e38be709521567bb33 Mon Sep 17 00:00:00 2001 +From: "Jose Fernandez (Anthropic)" +Date: Tue, 21 Apr 2026 19:26:13 +0000 +Subject: iommu/amd: Bounds-check devid in __rlookup_amd_iommu() + +From: Jose Fernandez (Anthropic) + +commit 07d0f496fe7ec5abe3bee7e38be709521567bb33 upstream. + +iommu_device_register() walks every device on the PCI bus via +bus_for_each_dev() and calls amd_iommu_probe_device() for each. The +inlined check_device() path computes the device's sbdf, calls +rlookup_amd_iommu() to find the owning IOMMU, and only afterwards +verifies devid <= pci_seg->last_bdf. __rlookup_amd_iommu() indexes +rlookup_table[devid] with no bounds check of its own, so for a PCI +device whose BDF is not described by the IVRS, the lookup reads past +the end of the allocation before the caller's bounds check can run. + +This was harmless before commit e874c666b15b ("iommu/amd: Change +rlookup, irq_lookup, and alias to use kvalloc()"): the table was a +zeroed page-order allocation, so the over-read returned NULL and the +caller's NULL check skipped the device. After that commit the table is +a tight kvcalloc() and the over-read returns adjacent slab contents, +which check_device() then dereferences as a struct amd_iommu *, +causing a boot-time GPF. + +Seen on Google Compute Engine ct6e VMs, where the virtualized IVRS +describes only the four TPU endpoints 00:04.0-07.0; the gVNIC at +00:08.0 (devid 0x40) indexes 56 bytes past the 456-byte allocation, +into the adjacent kmalloc-512 slab object: + + pci 0000:00:04.0: Adding to iommu group 0 + pci 0000:00:05.0: Adding to iommu group 1 + pci 0000:00:06.0: Adding to iommu group 2 + pci 0000:00:07.0: Adding to iommu group 3 + Oops: general protection fault, probably for non-canonical address 0x3a64695f78746382: 0000 [#1] SMP NOPTI + CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.18.22 #1 + Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 12/06/2025 + RIP: 0010:amd_iommu_probe_device+0x54/0x3a0 + Call Trace: + __iommu_probe_device+0x107/0x520 + probe_iommu_group+0x29/0x50 + bus_for_each_dev+0x7e/0xe0 + iommu_device_register+0xc9/0x240 + iommu_go_to_state+0x9c0/0x1c60 + amd_iommu_init+0x14/0x40 + pci_iommu_init+0x16/0x60 + do_one_initcall+0x47/0x2f0 + +Guard the array access in __rlookup_amd_iommu(). With the fix applied +on 6.18.22, the gVNIC at 00:08.0 is skipped cleanly and the VM boots. + +Fixes: e874c666b15b ("iommu/amd: Change rlookup, irq_lookup, and alias to use kvalloc()") +Cc: stable@vger.kernel.org +Reported-by: Ziyuan Chen +Tested-by: Ziyuan Chen +Reviewed-by: Josef Bacik +Assisted-by: Claude:unspecified +Signed-off-by: Jose Fernandez (Anthropic) +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/amd/iommu.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -351,8 +351,12 @@ static struct amd_iommu *__rlookup_amd_i + struct amd_iommu_pci_seg *pci_seg; + + for_each_pci_segment(pci_seg) { +- if (pci_seg->id == seg) +- return pci_seg->rlookup_table[devid]; ++ if (pci_seg->id != seg) ++ continue; ++ /* IVRS may not describe every device on the bus */ ++ if (devid > pci_seg->last_bdf) ++ return NULL; ++ return pci_seg->rlookup_table[devid]; + } + return NULL; + } diff --git a/queue-7.0/iommu-fix-ats-invalidation-timeouts-during-__iommu_remove_group_pasid.patch b/queue-7.0/iommu-fix-ats-invalidation-timeouts-during-__iommu_remove_group_pasid.patch new file mode 100644 index 0000000000..6fe3afdb78 --- /dev/null +++ b/queue-7.0/iommu-fix-ats-invalidation-timeouts-during-__iommu_remove_group_pasid.patch @@ -0,0 +1,43 @@ +From fc3523b16d2b4b88e61e69504b0ae0b18b869c8f Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:25 -0700 +Subject: iommu: Fix ATS invalidation timeouts during __iommu_remove_group_pasid() + +From: Nicolin Chen + +commit fc3523b16d2b4b88e61e69504b0ae0b18b869c8f upstream. + +If a device is blocked, its PASID domains are already detached. Repeating +iommu_remove_dev_pasid() is unnecessary and might trigger ATS invalidation +timeouts. + +Skip the iommu_remove_dev_pasid() call upon gdev->blocked. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Closes: https://sashiko.dev/#/patchset/20260407194644.171304-1-nicolinc%40nvidia.com +Reviewed-by: Kevin Tian +Signed-off-by: Nicolin Chen +Reviewed-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -3572,7 +3572,12 @@ static void __iommu_remove_group_pasid(s + struct group_device *device; + + for_each_group_device(group, device) { +- if (device->dev->iommu->max_pasids > 0) ++ /* ++ * A group-level detach cannot fail, even if there is a blocked ++ * device. In fact, blocked devices must be already detached for ++ * a pending device recovery. ++ */ ++ if (!device->blocked && device->dev->iommu->max_pasids > 0) + iommu_remove_dev_pasid(device->dev, pasid, domain); + } + } diff --git a/queue-7.0/iommu-fix-nested-pci_dev_reset_iommu_prepare-done.patch b/queue-7.0/iommu-fix-nested-pci_dev_reset_iommu_prepare-done.patch new file mode 100644 index 0000000000..ed8b08d4a0 --- /dev/null +++ b/queue-7.0/iommu-fix-nested-pci_dev_reset_iommu_prepare-done.patch @@ -0,0 +1,93 @@ +From 0d5fd7a9323ce6bedd170e21e1e90b8904917c75 Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:24 -0700 +Subject: iommu: Fix nested pci_dev_reset_iommu_prepare/done() + +From: Nicolin Chen + +commit 0d5fd7a9323ce6bedd170e21e1e90b8904917c75 upstream. + +Shuai found that cxl_reset_bus_function() calls pci_reset_bus_function() +internally while both are calling pci_dev_reset_iommu_prepare/done(). + +As pci_dev_reset_iommu_prepare() doesn't support re-entry, the inner call +will trigger a WARN_ON and return -EBUSY, resulting in failing the entire +device reset. + +On the other hand, removing the outer calls in the PCI callers is unsafe. +As pointed out by Kevin, device-specific quirks like reset_hinic_vf_dev() +execute custom firmware waits after their inner pcie_flr() completes. If +the IOMMU protection relies solely on the inner reset, the IOMMU will be +unblocked prematurely while the device is still resetting. + +Instead, fix this by making pci_dev_reset_iommu_prepare/done() reentrant. + +Introduce gdev->reset_depth to handle the re-entries on the same device. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Reported-by: Shuai Xue +Closes: https://lore.kernel.org/all/absKsk7qQOwzhpzv@Asurada-Nvidia/ +Suggested-by: Kevin Tian +Reviewed-by: Shuai Xue +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Lu Baolu +Signed-off-by: Nicolin Chen +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -82,6 +82,7 @@ struct group_device { + * - Device is undergoing a reset + */ + bool blocked; ++ unsigned int reset_depth; + }; + + /* Iterate over each struct group_device in a struct iommu_group */ +@@ -4015,20 +4016,23 @@ int pci_dev_reset_iommu_prepare(struct p + if (WARN_ON(!gdev)) + return -ENODEV; + +- /* Re-entry is not allowed */ +- if (WARN_ON(gdev->blocked)) +- return -EBUSY; ++ if (gdev->reset_depth++) ++ return 0; + + ret = __iommu_group_alloc_blocking_domain(group); +- if (ret) ++ if (ret) { ++ gdev->reset_depth--; + return ret; ++ } + + /* Stage RID domain at blocking_domain while retaining group->domain */ + if (group->domain != group->blocking_domain) { + ret = __iommu_attach_device(group->blocking_domain, &pdev->dev, + group->domain); +- if (ret) ++ if (ret) { ++ gdev->reset_depth--; + return ret; ++ } + } + + /* +@@ -4088,7 +4092,10 @@ void pci_dev_reset_iommu_done(struct pci + if (WARN_ON(!gdev)) + return; + +- if (!gdev->blocked) ++ /* Unbalanced done() calls would underflow the counter */ ++ if (WARN_ON(gdev->reset_depth == 0)) ++ return; ++ if (--gdev->reset_depth) + return; + + if (WARN_ON(!group->blocking_domain)) diff --git a/queue-7.0/iommu-fix-null-group-domain-dereference-in-pci_dev_reset_iommu_done.patch b/queue-7.0/iommu-fix-null-group-domain-dereference-in-pci_dev_reset_iommu_done.patch new file mode 100644 index 0000000000..239c5a4296 --- /dev/null +++ b/queue-7.0/iommu-fix-null-group-domain-dereference-in-pci_dev_reset_iommu_done.patch @@ -0,0 +1,46 @@ +From d769711fcddd005f1e654b3bde547140917fe696 Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:20 -0700 +Subject: iommu: Fix NULL group->domain dereference in pci_dev_reset_iommu_done() + +From: Nicolin Chen + +commit d769711fcddd005f1e654b3bde547140917fe696 upstream. + +Local sashiko review pointed it out that group->domain could be NULL when +a default domain fails to allocate during the first probe, which can crash +at domain->ops->attach_dev dereference in __iommu_attach_device() invoked +by pci_dev_reset_iommu_done(). + +pci_dev_reset_iommu_prepare() is fine as an old_domain pointer can be NULL. + +Skip the re-attach in pci_dev_reset_iommu_done() to fix the bug. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Signed-off-by: Nicolin Chen +Reviewed-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -4035,8 +4035,13 @@ void pci_dev_reset_iommu_done(struct pci + if (WARN_ON(!group->blocking_domain)) + return; + +- /* Re-attach RID domain back to group->domain */ +- if (group->domain != group->blocking_domain) { ++ /* ++ * Re-attach RID domain back to group->domain ++ * ++ * Leave the device parked in the blocking_domain if group->domain isn't ++ * initialized yet ++ */ ++ if (group->domain && group->domain != group->blocking_domain) { + WARN_ON(__iommu_attach_device(group->domain, &pdev->dev, + group->blocking_domain)); + } diff --git a/queue-7.0/iommu-fix-pasid-attach-in-pci_dev_reset_iommu_prepare-done.patch b/queue-7.0/iommu-fix-pasid-attach-in-pci_dev_reset_iommu_prepare-done.patch new file mode 100644 index 0000000000..17e6ba0ade --- /dev/null +++ b/queue-7.0/iommu-fix-pasid-attach-in-pci_dev_reset_iommu_prepare-done.patch @@ -0,0 +1,70 @@ +From 1615e8896a8f6d7b2adf6495e538a81bf6cea3e0 Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:23 -0700 +Subject: iommu: Fix pasid attach in pci_dev_reset_iommu_prepare/done() + +From: Nicolin Chen + +commit 1615e8896a8f6d7b2adf6495e538a81bf6cea3e0 upstream. + +Now the helpers handle per-gdev resets. Replace __iommu_set_group_pasid() +with set_dev_pasid() accordingly, in the pci_dev_reset_iommu_done(). + +Also add max_pasids check as other callers. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Reported-by: Shuai Xue +Closes: https://lore.kernel.org/all/ad858513-09fc-455e-bbc5-fe38a225cc78@linux.alibaba.com/ +Reviewed-by: Shuai Xue +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Signed-off-by: Nicolin Chen +Reviewed-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -4044,9 +4044,14 @@ int pci_dev_reset_iommu_prepare(struct p + * The pasid_array is mostly fenced by group->mutex, except one reader + * in iommu_attach_handle_get(), so it's safe to read without xa_lock. + */ +- xa_for_each_start(&group->pasid_array, pasid, entry, 1) +- iommu_remove_dev_pasid(&pdev->dev, pasid, +- pasid_array_entry_to_domain(entry)); ++ if (pdev->dev.iommu->max_pasids > 0) { ++ xa_for_each_start(&group->pasid_array, pasid, entry, 1) { ++ struct iommu_domain *pasid_dom = ++ pasid_array_entry_to_domain(entry); ++ ++ iommu_remove_dev_pasid(&pdev->dev, pasid, pasid_dom); ++ } ++ } + + group->recovery_cnt++; + return ret; +@@ -4113,10 +4118,16 @@ void pci_dev_reset_iommu_done(struct pci + * The pasid_array is mostly fenced by group->mutex, except one reader + * in iommu_attach_handle_get(), so it's safe to read without xa_lock. + */ +- xa_for_each_start(&group->pasid_array, pasid, entry, 1) +- WARN_ON(__iommu_set_group_pasid( +- pasid_array_entry_to_domain(entry), group, pasid, +- group->blocking_domain)); ++ if (pdev->dev.iommu->max_pasids > 0) { ++ xa_for_each_start(&group->pasid_array, pasid, entry, 1) { ++ struct iommu_domain *pasid_dom = ++ pasid_array_entry_to_domain(entry); ++ ++ WARN_ON(pasid_dom->ops->set_dev_pasid( ++ pasid_dom, &pdev->dev, pasid, ++ group->blocking_domain)); ++ } ++ } + + if (!WARN_ON(group->recovery_cnt == 0)) + group->recovery_cnt--; diff --git a/queue-7.0/iommu-fix-warn_on-in-__iommu_group_set_domain_nofail-due-to-reset.patch b/queue-7.0/iommu-fix-warn_on-in-__iommu_group_set_domain_nofail-due-to-reset.patch new file mode 100644 index 0000000000..9e71952880 --- /dev/null +++ b/queue-7.0/iommu-fix-warn_on-in-__iommu_group_set_domain_nofail-due-to-reset.patch @@ -0,0 +1,67 @@ +From 5474e6e17a262db45c60575c73f70210f5c7001f Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:26 -0700 +Subject: iommu: Fix WARN_ON in __iommu_group_set_domain_nofail() due to reset + +From: Nicolin Chen + +commit 5474e6e17a262db45c60575c73f70210f5c7001f upstream. + +In __iommu_group_set_domain_internal(), concurrent domain attachments are +rejected when any device in the group is recovering. This is necessary to +fence concurrent attachments to a multi-device group where devices might +share the same RID due to PCI DMA alias quirks, but triggers the WARN_ON in +__iommu_group_set_domain_nofail(). + +Other IOMMU_SET_DOMAIN_MUST_SUCCEED callers in detach/teardown paths, such +as __iommu_group_set_core_domain and __iommu_release_dma_ownership, should +not be rejected, as the domain would be freed anyway in these nofail paths +while group->domain is still pointing to it. So pci_dev_reset_iommu_done() +could trigger a UAF when re-attaching group->domain. + +Honor the IOMMU_SET_DOMAIN_MUST_SUCCEED flag, allowing the callers through +the group->recovery_cnt fence, so as to update the group->domain pointer. +Instead add a gdev->blocked check in the device iteration loop, to prevent +any concurrent per-device detachment. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Closes: https://sashiko.dev/#/patchset/20260407194644.171304-1-nicolinc%40nvidia.com +Reviewed-by: Kevin Tian +Reviewed-by: Lu Baolu +Signed-off-by: Nicolin Chen +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2472,9 +2472,10 @@ static int __iommu_group_set_domain_inte + + /* + * This is a concurrent attach during device recovery. Reject it until +- * pci_dev_reset_iommu_done() attaches the device to group->domain. ++ * pci_dev_reset_iommu_done() attaches the device to group->domain, if ++ * IOMMU_SET_DOMAIN_MUST_SUCCEED is not set. + */ +- if (group->recovery_cnt) ++ if (group->recovery_cnt && !(flags & IOMMU_SET_DOMAIN_MUST_SUCCEED)) + return -EBUSY; + + /* +@@ -2485,6 +2486,13 @@ static int __iommu_group_set_domain_inte + */ + result = 0; + for_each_group_device(group, gdev) { ++ /* ++ * Device under recovery is attached to group->blocking_domain. ++ * Don't change that. pci_dev_reset_iommu_done() will re-attach ++ * its domain to the updated group->domain, after the recovery. ++ */ ++ if (gdev->blocked) ++ continue; + ret = __iommu_device_set_domain(group, gdev->dev, new_domain, + group->domain, flags); + if (ret) { diff --git a/queue-7.0/iommu-replace-per-group-resetting_domain-with-per-gdev-blocked-flag.patch b/queue-7.0/iommu-replace-per-group-resetting_domain-with-per-gdev-blocked-flag.patch new file mode 100644 index 0000000000..22c1bcb02c --- /dev/null +++ b/queue-7.0/iommu-replace-per-group-resetting_domain-with-per-gdev-blocked-flag.patch @@ -0,0 +1,303 @@ +From b296ca1fb43aa435edd86131f5230f70c03b2829 Mon Sep 17 00:00:00 2001 +From: Nicolin Chen +Date: Fri, 24 Apr 2026 18:15:22 -0700 +Subject: iommu: Replace per-group resetting_domain with per-gdev blocked flag + +From: Nicolin Chen + +commit b296ca1fb43aa435edd86131f5230f70c03b2829 upstream. + +The core tracks device resetting states with a per-group resetting_domain, +while a reset is actually per group-device. Such a mismatch might lead to +confusion and even difficulty to untangle per-gdev handling requirement. + +Shuai found that cxl_reset_bus_function() calls pci_reset_bus_function() +internally while both are calling pci_dev_reset_iommu_prepare/done(). And +the solution requires the core to track at the group_device level as well. + +Introduce a 'blocked' flag to struct group_device, to allow a multi-device +group to isolate concurrent device resets independently. + +As the reset routine is per gdev, it cannot clear group->resetting_domain +without iterating over the device list to ensure no other device is being +reset. Simplify it by replacing the resetting_domain with a 'recovery_cnt' +in the struct iommu_group. + +No functional change. But this is essential to apply following bug fixes. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Cc: stable@vger.kernel.org +Reported-by: Shuai Xue +Closes: https://lore.kernel.org/all/absKsk7qQOwzhpzv@Asurada-Nvidia/ +Reviewed-by: Shuai Xue +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Lu Baolu +Signed-off-by: Nicolin Chen +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/iommu.c | 102 ++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 78 insertions(+), 24 deletions(-) + +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -61,14 +61,14 @@ struct iommu_group { + int id; + struct iommu_domain *default_domain; + struct iommu_domain *blocking_domain; +- /* +- * During a group device reset, @resetting_domain points to the physical +- * domain, while @domain points to the attached domain before the reset. +- */ +- struct iommu_domain *resetting_domain; + struct iommu_domain *domain; + struct list_head entry; + unsigned int owner_cnt; ++ /* ++ * Number of devices in the group undergoing or awaiting recovery. ++ * If non-zero, concurrent domain attachments are rejected. ++ */ ++ unsigned int recovery_cnt; + void *owner; + }; + +@@ -76,12 +76,32 @@ struct group_device { + struct list_head list; + struct device *dev; + char *name; ++ /* ++ * Device is blocked for a pending recovery while its group->domain is ++ * retained. This can happen when: ++ * - Device is undergoing a reset ++ */ ++ bool blocked; + }; + + /* Iterate over each struct group_device in a struct iommu_group */ + #define for_each_group_device(group, pos) \ + list_for_each_entry(pos, &(group)->devices, list) + ++static struct group_device *__dev_to_gdev(struct device *dev) ++{ ++ struct iommu_group *group = dev->iommu_group; ++ struct group_device *gdev; ++ ++ lockdep_assert_held(&group->mutex); ++ ++ for_each_group_device(group, gdev) { ++ if (gdev->dev == dev) ++ return gdev; ++ } ++ return NULL; ++} ++ + struct iommu_group_attribute { + struct attribute attr; + ssize_t (*show)(struct iommu_group *group, char *buf); +@@ -2195,6 +2215,8 @@ EXPORT_SYMBOL_GPL(iommu_attach_device); + + int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain) + { ++ struct group_device *gdev; ++ + /* + * This is called on the dma mapping fast path so avoid locking. This is + * racy, but we have an expectation that the driver will setup its DMAs +@@ -2205,14 +2227,18 @@ int iommu_deferred_attach(struct device + + guard(mutex)(&dev->iommu_group->mutex); + ++ gdev = __dev_to_gdev(dev); ++ if (WARN_ON(!gdev)) ++ return -ENODEV; ++ + /* +- * This is a concurrent attach during a device reset. Reject it until ++ * This is a concurrent attach during device recovery. Reject it until + * pci_dev_reset_iommu_done() attaches the device to group->domain. + * + * Note that this might fail the iommu_dma_map(). But there's nothing + * more we can do here. + */ +- if (dev->iommu_group->resetting_domain) ++ if (gdev->blocked) + return -EBUSY; + return __iommu_attach_device(domain, dev, NULL); + } +@@ -2269,19 +2295,24 @@ EXPORT_SYMBOL_GPL(iommu_get_domain_for_d + struct iommu_domain *iommu_driver_get_domain_for_dev(struct device *dev) + { + struct iommu_group *group = dev->iommu_group; ++ struct group_device *gdev; + + lockdep_assert_held(&group->mutex); + ++ gdev = __dev_to_gdev(dev); ++ if (WARN_ON(!gdev)) ++ return NULL; ++ + /* + * Driver handles the low-level __iommu_attach_device(), including the + * one invoked by pci_dev_reset_iommu_done() re-attaching the device to + * the cached group->domain. In this case, the driver must get the old +- * domain from group->resetting_domain rather than group->domain. This ++ * domain from group->blocking_domain rather than group->domain. This + * prevents it from re-attaching the device from group->domain (old) to + * group->domain (new). + */ +- if (group->resetting_domain) +- return group->resetting_domain; ++ if (gdev->blocked) ++ return group->blocking_domain; + + return group->domain; + } +@@ -2440,10 +2471,10 @@ static int __iommu_group_set_domain_inte + return -EINVAL; + + /* +- * This is a concurrent attach during a device reset. Reject it until ++ * This is a concurrent attach during device recovery. Reject it until + * pci_dev_reset_iommu_done() attaches the device to group->domain. + */ +- if (group->resetting_domain) ++ if (group->recovery_cnt) + return -EBUSY; + + /* +@@ -3577,10 +3608,10 @@ int iommu_attach_device_pasid(struct iom + mutex_lock(&group->mutex); + + /* +- * This is a concurrent attach during a device reset. Reject it until ++ * This is a concurrent attach during device recovery. Reject it until + * pci_dev_reset_iommu_done() attaches the device to group->domain. + */ +- if (group->resetting_domain) { ++ if (group->recovery_cnt) { + ret = -EBUSY; + goto out_unlock; + } +@@ -3670,10 +3701,10 @@ int iommu_replace_device_pasid(struct io + mutex_lock(&group->mutex); + + /* +- * This is a concurrent attach during a device reset. Reject it until ++ * This is a concurrent attach during device recovery. Reject it until + * pci_dev_reset_iommu_done() attaches the device to group->domain. + */ +- if (group->resetting_domain) { ++ if (group->recovery_cnt) { + ret = -EBUSY; + goto out_unlock; + } +@@ -3944,12 +3975,12 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_group + * routine wants to block any IOMMU activity: translation and ATS invalidation. + * + * This function attaches the device's RID/PASID(s) the group->blocking_domain, +- * setting the group->resetting_domain. This allows the IOMMU driver pausing any ++ * incrementing the group->recovery_cnt, to allow the IOMMU driver pausing any + * IOMMU activity while leaving the group->domain pointer intact. Later when the + * reset is finished, pci_dev_reset_iommu_done() can restore everything. + * + * Caller must use pci_dev_reset_iommu_prepare() with pci_dev_reset_iommu_done() +- * before/after the core-level reset routine, to unset the resetting_domain. ++ * before/after the core-level reset routine, to decrement the recovery_cnt. + * + * Return: 0 on success or negative error code if the preparation failed. + * +@@ -3962,6 +3993,7 @@ EXPORT_SYMBOL_NS_GPL(iommu_replace_group + int pci_dev_reset_iommu_prepare(struct pci_dev *pdev) + { + struct iommu_group *group = pdev->dev.iommu_group; ++ struct group_device *gdev; + unsigned long pasid; + void *entry; + int ret; +@@ -3971,8 +4003,12 @@ int pci_dev_reset_iommu_prepare(struct p + + guard(mutex)(&group->mutex); + ++ gdev = __dev_to_gdev(&pdev->dev); ++ if (WARN_ON(!gdev)) ++ return -ENODEV; ++ + /* Re-entry is not allowed */ +- if (WARN_ON(group->resetting_domain)) ++ if (WARN_ON(gdev->blocked)) + return -EBUSY; + + ret = __iommu_group_alloc_blocking_domain(group); +@@ -3988,6 +4024,13 @@ int pci_dev_reset_iommu_prepare(struct p + } + + /* ++ * Update gdev->blocked upon the domain change, as it is used to return ++ * the correct domain in iommu_driver_get_domain_for_dev() that might be ++ * called in a set_dev_pasid callback function. ++ */ ++ gdev->blocked = true; ++ ++ /* + * Stage PASID domains at blocking_domain while retaining pasid_array. + * + * The pasid_array is mostly fenced by group->mutex, except one reader +@@ -3997,7 +4040,7 @@ int pci_dev_reset_iommu_prepare(struct p + iommu_remove_dev_pasid(&pdev->dev, pasid, + pasid_array_entry_to_domain(entry)); + +- group->resetting_domain = group->blocking_domain; ++ group->recovery_cnt++; + return ret; + } + EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare); +@@ -4019,6 +4062,7 @@ EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_pr + void pci_dev_reset_iommu_done(struct pci_dev *pdev) + { + struct iommu_group *group = pdev->dev.iommu_group; ++ struct group_device *gdev; + unsigned long pasid; + void *entry; + +@@ -4027,11 +4071,13 @@ void pci_dev_reset_iommu_done(struct pci + + guard(mutex)(&group->mutex); + +- /* pci_dev_reset_iommu_prepare() was bypassed for the device */ +- if (!group->resetting_domain) ++ gdev = __dev_to_gdev(&pdev->dev); ++ if (WARN_ON(!gdev)) ++ return; ++ ++ if (!gdev->blocked) + return; + +- /* pci_dev_reset_iommu_prepare() was not successfully called */ + if (WARN_ON(!group->blocking_domain)) + return; + +@@ -4047,6 +4093,13 @@ void pci_dev_reset_iommu_done(struct pci + } + + /* ++ * Update gdev->blocked upon the domain change, as it is used to return ++ * the correct domain in iommu_driver_get_domain_for_dev() that might be ++ * called in a set_dev_pasid callback function. ++ */ ++ gdev->blocked = false; ++ ++ /* + * Re-attach PASID domains back to the domains retained in pasid_array. + * + * The pasid_array is mostly fenced by group->mutex, except one reader +@@ -4057,7 +4110,8 @@ void pci_dev_reset_iommu_done(struct pci + pasid_array_entry_to_domain(entry), group, pasid, + group->blocking_domain)); + +- group->resetting_domain = NULL; ++ if (!WARN_ON(group->recovery_cnt == 0)) ++ group->recovery_cnt--; + } + EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_done); + diff --git a/queue-7.0/iommu-vt-d-avoid-null-pointer-dereference-or-refcount-corruption.patch b/queue-7.0/iommu-vt-d-avoid-null-pointer-dereference-or-refcount-corruption.patch new file mode 100644 index 0000000000..2b94d6afc6 --- /dev/null +++ b/queue-7.0/iommu-vt-d-avoid-null-pointer-dereference-or-refcount-corruption.patch @@ -0,0 +1,63 @@ +From 79ea2feb917b05366b49d85573c9c5331f043b2c Mon Sep 17 00:00:00 2001 +From: Zhenzhong Duan +Date: Sat, 9 May 2026 10:43:46 +0800 +Subject: iommu/vt-d: Avoid NULL pointer dereference or refcount corruption + +From: Zhenzhong Duan + +commit 79ea2feb917b05366b49d85573c9c5331f043b2c upstream. + +Commit 60f030f7418d ("iommu/vt-d: Avoid use of NULL after WARN_ON_ONCE") +fixed a NULL pointer dereference in an unlikely situation partly. + +If dev_pasid is not found in the dev_pasids list, it remains NULL. +However, the teardown operations are executed unconditionally, this lead +to a NULL pointer dereference or refcount corruption. + +If the domain was never attached to this IOMMU, info will be NULL, which +would cause an immediate dereference when checking --info->refcnt. + +Even if info is not NULL, decrementing the refcount without having removed +a valid PASID might unbalance the count. This could lead to premature +dropping of the refcount to 0, potentially causing a use-after-free for the +remaining active devices sharing the domain. + +Fix it by returning early if dev_pasid is NULL, before executing the +teardown operations. + +Issue found by AI review and suggested by Kevin Tian. +https://sashiko.dev/#/patchset/20260421031347.1408890-1-zhenzhong.duan%40intel.com + +Fixes: 60f030f7418d ("iommu/vt-d: Avoid use of NULL after WARN_ON_ONCE") +Cc: stable@vger.kernel.org +Suggested-by: Kevin Tian +Signed-off-by: Zhenzhong Duan +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260422033538.95000-1-zhenzhong.duan@intel.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/intel/iommu.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -3544,12 +3544,13 @@ void domain_remove_dev_pasid(struct iomm + } + spin_unlock_irqrestore(&dmar_domain->lock, flags); + ++ if (WARN_ON_ONCE(!dev_pasid)) ++ return; ++ + cache_tag_unassign_domain(dmar_domain, dev, pasid); + domain_detach_iommu(dmar_domain, iommu); +- if (!WARN_ON_ONCE(!dev_pasid)) { +- intel_iommu_debugfs_remove_dev_pasid(dev_pasid); +- kfree(dev_pasid); +- } ++ intel_iommu_debugfs_remove_dev_pasid(dev_pasid); ++ kfree(dev_pasid); + } + + static int blocking_domain_set_dev_pasid(struct iommu_domain *domain, diff --git a/queue-7.0/iommu-vt-d-disable-dmar-for-intel-q35-igfx.patch b/queue-7.0/iommu-vt-d-disable-dmar-for-intel-q35-igfx.patch new file mode 100644 index 0000000000..e5a5401d87 --- /dev/null +++ b/queue-7.0/iommu-vt-d-disable-dmar-for-intel-q35-igfx.patch @@ -0,0 +1,47 @@ +From 2cda2e10dc8343ae01eae9e999a876b7e7d37861 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Naval=20Alcal=C3=A1?= +Date: Sat, 9 May 2026 10:43:44 +0800 +Subject: iommu/vt-d: Disable DMAR for Intel Q35 IGFX +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Naval Alcalá + +commit 2cda2e10dc8343ae01eae9e999a876b7e7d37861 upstream. + +Intel Q35 integrated graphics (8086:29b2) exhibits broken DMAR +behaviour similar to other G4x/GM45 devices for which DMAR is +already disabled via quirks. + +When DMAR is enabled, the system may hard lock up during boot or +early device initialization, requiring a reset. + +Add the missing PCI ID to the existing quirk list to disable +DMAR for this device. + +Fixes: 1f76249cc3be ("iommu/vt-d: Declare Broadwell igfx dmar support snafu") +Cc: stable@vger.kernel.org +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=201185 +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=216064 +Signed-off-by: Naval Alcalá +Link: https://lore.kernel.org/r/20260410161622.13549-1-ari@naval.cat +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/intel/iommu.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -3933,6 +3933,9 @@ static void quirk_iommu_igfx(struct pci_ + disable_igfx_iommu = 1; + } + ++/* Q35 integrated gfx dmar support is totally busted. */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x29b2, quirk_iommu_igfx); ++ + /* G4x/GM45 integrated gfx dmar support is totally busted. */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); diff --git a/queue-7.0/iommu-vt-d-fix-oops-due-to-out-of-scope-access.patch b/queue-7.0/iommu-vt-d-fix-oops-due-to-out-of-scope-access.patch new file mode 100644 index 0000000000..bcd8bae604 --- /dev/null +++ b/queue-7.0/iommu-vt-d-fix-oops-due-to-out-of-scope-access.patch @@ -0,0 +1,66 @@ +From a6dea58d8625c06b9654c0555f101742481335c3 Mon Sep 17 00:00:00 2001 +From: Zhenzhong Duan +Date: Sat, 9 May 2026 10:43:45 +0800 +Subject: iommu/vt-d: Fix oops due to out of scope access + +From: Zhenzhong Duan + +commit a6dea58d8625c06b9654c0555f101742481335c3 upstream. + +Below oops triggers when kill QEMU process: + + Oops: general protection fault, probably for non-canonical address 0x7fffffff844eaaa7: 0000 [#1] SMP NOPTI + Call Trace: + + do_raw_spin_lock+0xaa/0xc0 + _raw_spin_lock_irqsave+0x21/0x40 + domain_remove_dev_pasid+0x52/0x160 + intel_nested_set_dev_pasid+0x1b9/0x1e0 + __iommu_set_group_pasid+0x56/0x120 + pci_dev_reset_iommu_done+0xe3/0x180 + pcie_flr+0x65/0x160 + __pci_reset_function_locked+0x5b/0x120 + vfio_pci_core_close_device+0x63/0xe0 [vfio_pci_core] + vfio_df_close+0x4f/0xa0 + vfio_df_unbind_iommufd+0x2d/0x60 + vfio_device_fops_release+0x3e/0x40 + __fput+0xe5/0x2c0 + task_work_run+0x58/0xa0 + do_exit+0x2c8/0x600 + do_group_exit+0x2f/0xa0 + get_signal+0x863/0x8c0 + arch_do_signal_or_restart+0x24/0x100 + exit_to_user_mode_loop+0x87/0x380 + do_syscall_64+0x2ff/0x11e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The global static blocked domain is a dummy domain without corresponding +dmar_domain structure, accessing beyond iommu_domain structure triggers +oops easily. Fix it by return early in domain_remove_dev_pasid() like +identity domain. + +Fixes: 7d0c9da6c150 ("iommu/vt-d: Add set_dev_pasid callback for dma domain") +Cc: stable@vger.kernel.org +Signed-off-by: Zhenzhong Duan +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260421031347.1408890-1-zhenzhong.duan@intel.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/intel/iommu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -3529,8 +3529,8 @@ void domain_remove_dev_pasid(struct iomm + if (!domain) + return; + +- /* Identity domain has no meta data for pasid. */ +- if (domain->type == IOMMU_DOMAIN_IDENTITY) ++ /* Identity domain and blocked domain have no meta data for pasid. */ ++ if (domain->type == IOMMU_DOMAIN_IDENTITY || domain->type == IOMMU_DOMAIN_BLOCKED) + return; + + dmar_domain = to_dmar_domain(domain); diff --git a/queue-7.0/irqchip-gic-v5-allocate-its-parent-lpis-as-a-range.patch b/queue-7.0/irqchip-gic-v5-allocate-its-parent-lpis-as-a-range.patch new file mode 100644 index 0000000000..a9f22ed873 --- /dev/null +++ b/queue-7.0/irqchip-gic-v5-allocate-its-parent-lpis-as-a-range.patch @@ -0,0 +1,94 @@ +From a7c7e42654b6a8676610ee09d22901432c4851af Mon Sep 17 00:00:00 2001 +From: Sascha Bischoff +Date: Wed, 6 May 2026 09:37:43 +0000 +Subject: irqchip/gic-v5: Allocate ITS parent LPIs as a range + +From: Sascha Bischoff + +commit a7c7e42654b6a8676610ee09d22901432c4851af upstream. + +The ITS MSI domain no longer manages LPI allocation directly. LPIs are +allocated and freed by the parent LPI domain, which can now handle a +full range of interrupts and unwind partial allocations internally. + +Make the ITS domain request and release the parent IRQs as a single +range instead of iterating over each interrupt. The ITS allocation +path then only needs to reserve EventIDs, allocate the parent range, +and fill in the ITS irq_data for each MSI. Since no operation in the +per-MSI loop can fail, the partial parent-free unwind becomes +unnecessary. + +On teardown, reset the ITS irq_data for the range and then release the +parent range in one call, leaving LPI teardown to the LPI domain. + +Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") +Signed-off-by: Sascha Bischoff +Signed-off-by: Thomas Gleixner +Reviewed-by: Marc Zyngier +Reviewed-by: Lorenzo Pieralisi +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260506093634.382062-4-sascha.bischoff@arm.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-gic-v5-its.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +--- a/drivers/irqchip/irq-gic-v5-its.c ++++ b/drivers/irqchip/irq-gic-v5-its.c +@@ -937,6 +937,7 @@ static int gicv5_its_irq_domain_alloc(st + int ret, i; + + its_dev = info->scratchpad[0].ptr; ++ device_id = its_dev->device_id; + + ret = gicv5_its_alloc_eventid(its_dev, info, nr_irqs, &event_id_base); + if (ret) +@@ -946,14 +947,11 @@ static int gicv5_its_irq_domain_alloc(st + if (ret) + goto out_eventid; + +- device_id = its_dev->device_id; ++ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, NULL); ++ if (ret) ++ goto out_eventid; + + for (i = 0; i < nr_irqs; i++) { +- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, NULL); +- if (ret) { +- goto out_free_irqs; +- } +- + /* + * Store eventid and deviceid into the hwirq for later use. + * +@@ -972,12 +970,6 @@ static int gicv5_its_irq_domain_alloc(st + + return 0; + +-out_free_irqs: +- while (--i >= 0) { +- irqd = irq_domain_get_irq_data(domain, virq + i); +- irq_domain_reset_irq_data(irqd); +- irq_domain_free_irqs_parent(domain, virq + i, 1); +- } + out_eventid: + gicv5_its_free_eventid(its_dev, event_id_base, nr_irqs); + return ret; +@@ -1000,14 +992,14 @@ static void gicv5_its_irq_domain_free(st + bitmap_release_region(its_dev->event_map, event_id_base, + get_count_order(nr_irqs)); + +- /* Hierarchically free irq data */ + for (i = 0; i < nr_irqs; i++) { + d = irq_domain_get_irq_data(domain, virq + i); +- + irq_domain_reset_irq_data(d); +- irq_domain_free_irqs_parent(domain, virq + i, 1); + } + ++ /* Hierarchically free irq data */ ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++ + gicv5_its_syncr(its, its_dev); + gicv5_irs_syncr(); + } diff --git a/queue-7.0/irqchip-gic-v5-move-lpi-allocation-into-the-lpi-domain.patch b/queue-7.0/irqchip-gic-v5-move-lpi-allocation-into-the-lpi-domain.patch new file mode 100644 index 0000000000..2999460d71 --- /dev/null +++ b/queue-7.0/irqchip-gic-v5-move-lpi-allocation-into-the-lpi-domain.patch @@ -0,0 +1,210 @@ +From dec85d2fbd20de3711a71e65397dfdb40c3fa953 Mon Sep 17 00:00:00 2001 +From: Sascha Bischoff +Date: Wed, 6 May 2026 09:37:02 +0000 +Subject: irqchip/gic-v5: Move LPI allocation into the LPI domain + +From: Sascha Bischoff + +commit dec85d2fbd20de3711a71e65397dfdb40c3fa953 upstream. + +The IPI and ITS MSI domains currently allocate and release LPIs +directly, then pass the selected LPI ID to the parent LPI domain. This +leaks the LPI domain's allocation policy into its child domains and +forces each child to duplicate part of the parent domain's teardown. + +Make the LPI domain allocate LPIs in its .alloc() callback and release +them in a matching .free() callback. Child domains can then request a +parent interrupt without passing an implementation-specific LPI ID, +and the LPI lifetime is tied to the domain that owns the LPI +namespace. + +Remove the gicv5_alloc_lpi() and gicv5_free_lpi() wrappers now that no +external caller needs to manage LPIs directly. + +This is a preparatory change for an actual leakage problem in the +allocation code and therefore tagged with the same Fixes tag. + +Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") +Signed-off-by: Sascha Bischoff +Signed-off-by: Thomas Gleixner +Reviewed-by: Marc Zyngier +Reviewed-by: Lorenzo Pieralisi +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260506093634.382062-2-sascha.bischoff@arm.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-gic-v5-its.c | 14 +-------- + drivers/irqchip/irq-gic-v5.c | 53 ++++++++++++++++++------------------- + include/linux/irqchip/arm-gic-v5.h | 3 -- + 3 files changed, 28 insertions(+), 42 deletions(-) + +--- a/drivers/irqchip/irq-gic-v5-its.c ++++ b/drivers/irqchip/irq-gic-v5-its.c +@@ -929,8 +929,8 @@ static void gicv5_its_free_eventid(struc + static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) + { +- u32 device_id, event_id_base, lpi; + struct gicv5_its_dev *its_dev; ++ u32 device_id, event_id_base; + msi_alloc_info_t *info = arg; + irq_hw_number_t hwirq; + struct irq_data *irqd; +@@ -949,16 +949,8 @@ static int gicv5_its_irq_domain_alloc(st + device_id = its_dev->device_id; + + for (i = 0; i < nr_irqs; i++) { +- ret = gicv5_alloc_lpi(); +- if (ret < 0) { +- pr_debug("Failed to find free LPI!\n"); +- goto out_free_irqs; +- } +- lpi = ret; +- +- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi); ++ ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, NULL); + if (ret) { +- gicv5_free_lpi(lpi); + goto out_free_irqs; + } + +@@ -983,7 +975,6 @@ static int gicv5_its_irq_domain_alloc(st + out_free_irqs: + while (--i >= 0) { + irqd = irq_domain_get_irq_data(domain, virq + i); +- gicv5_free_lpi(irqd->parent_data->hwirq); + irq_domain_reset_irq_data(irqd); + irq_domain_free_irqs_parent(domain, virq + i, 1); + } +@@ -1013,7 +1004,6 @@ static void gicv5_its_irq_domain_free(st + for (i = 0; i < nr_irqs; i++) { + d = irq_domain_get_irq_data(domain, virq + i); + +- gicv5_free_lpi(d->parent_data->hwirq); + irq_domain_reset_irq_data(d); + irq_domain_free_irqs_parent(domain, virq + i, 1); + } +--- a/drivers/irqchip/irq-gic-v5.c ++++ b/drivers/irqchip/irq-gic-v5.c +@@ -59,16 +59,6 @@ static void release_lpi(u32 lpi) + ida_free(&lpi_ida, lpi); + } + +-int gicv5_alloc_lpi(void) +-{ +- return alloc_lpi(); +-} +- +-void gicv5_free_lpi(u32 lpi) +-{ +- release_lpi(lpi); +-} +- + static void gicv5_ppi_priority_init(void) + { + write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_PRI_MI), SYS_ICC_PPI_PRIORITYR0_EL1); +@@ -788,18 +778,36 @@ static void gicv5_lpi_config_reset(struc + gicv5_lpi_irq_write_pending_state(d, false); + } + ++static void gicv5_irq_lpi_domain_free(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs) ++{ ++ struct irq_data *d; ++ ++ if (WARN_ON_ONCE(nr_irqs != 1)) ++ return; ++ ++ d = irq_domain_get_irq_data(domain, virq); ++ ++ release_lpi(d->hwirq); ++ ++ irq_set_handler(virq, NULL); ++ irq_domain_reset_irq_data(d); ++} ++ + static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) + { + irq_hw_number_t hwirq; + struct irq_data *irqd; +- u32 *lpi = arg; + int ret; + + if (WARN_ON_ONCE(nr_irqs != 1)) + return -EINVAL; + +- hwirq = *lpi; ++ ret = alloc_lpi(); ++ if (ret < 0) ++ return ret; ++ hwirq = ret; + + irqd = irq_domain_get_irq_data(domain, virq); + +@@ -808,8 +816,10 @@ static int gicv5_irq_lpi_domain_alloc(st + irqd_set_single_target(irqd); + + ret = gicv5_irs_iste_alloc(hwirq); +- if (ret < 0) ++ if (ret < 0) { ++ release_lpi(hwirq); + return ret; ++ } + + gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI); + gicv5_lpi_config_reset(irqd); +@@ -819,7 +829,7 @@ static int gicv5_irq_lpi_domain_alloc(st + + static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = { + .alloc = gicv5_irq_lpi_domain_alloc, +- .free = gicv5_irq_domain_free, ++ .free = gicv5_irq_lpi_domain_free, + }; + + void __init gicv5_init_lpi_domain(void) +@@ -841,21 +851,12 @@ static int gicv5_irq_ipi_domain_alloc(st + { + struct irq_data *irqd; + int ret, i; +- u32 lpi; + + for (i = 0; i < nr_irqs; i++) { +- ret = gicv5_alloc_lpi(); +- if (ret < 0) ++ ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, NULL); ++ if (ret) + return ret; + +- lpi = ret; +- +- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi); +- if (ret) { +- gicv5_free_lpi(lpi); +- return ret; +- } +- + irqd = irq_domain_get_irq_data(domain, virq + i); + + irq_domain_set_hwirq_and_chip(domain, virq + i, i, +@@ -881,8 +882,6 @@ static void gicv5_irq_ipi_domain_free(st + if (!d) + return; + +- gicv5_free_lpi(d->parent_data->hwirq); +- + irq_set_handler(virq + i, NULL); + irq_domain_reset_irq_data(d); + irq_domain_free_irqs_parent(domain, virq + i, 1); +--- a/include/linux/irqchip/arm-gic-v5.h ++++ b/include/linux/irqchip/arm-gic-v5.h +@@ -398,9 +398,6 @@ struct gicv5_its_itt_cfg { + void gicv5_init_lpis(u32 max); + void gicv5_deinit_lpis(void); + +-int gicv5_alloc_lpi(void); +-void gicv5_free_lpi(u32 lpi); +- + void __init gicv5_its_of_probe(struct device_node *parent); + void __init gicv5_its_acpi_probe(void); + #endif diff --git a/queue-7.0/irqchip-gic-v5-support-range-allocation-for-lpis.patch b/queue-7.0/irqchip-gic-v5-support-range-allocation-for-lpis.patch new file mode 100644 index 0000000000..58c186ea89 --- /dev/null +++ b/queue-7.0/irqchip-gic-v5-support-range-allocation-for-lpis.patch @@ -0,0 +1,161 @@ +From eb6f6d523813ead9dc2799194a2839d42c049734 Mon Sep 17 00:00:00 2001 +From: Sascha Bischoff +Date: Wed, 6 May 2026 09:37:23 +0000 +Subject: irqchip/gic-v5: Support range allocation for LPIs + +From: Sascha Bischoff + +commit eb6f6d523813ead9dc2799194a2839d42c049734 upstream. + +The per-IPI parent allocation loop returns immediately on failure and leaks +any parent interrupts allocated by earlier iterations. + +The GICv5 LPI domain now owns LPI allocation and teardown internally, +but its irq_domain callbacks still reject requests where nr_irqs is +greater than one. This forces child domains to allocate and free LPIs +one at a time even when the interrupt core requests a contiguous +range. + +Handle multi-interrupt allocation and teardown in the LPI domain by +iterating over the requested range and unwinding any partially +allocated state on failure. + +Allocate the parent LPIs for the IPI domain with a single range +request as well, which cures the leakage problem. + +Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") +Signed-off-by: Sascha Bischoff +Signed-off-by: Thomas Gleixner +Reviewed-by: Marc Zyngier +Reviewed-by: Lorenzo Pieralisi +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260506093634.382062-3-sascha.bischoff@arm.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-gic-v5.c | 77 +++++++++++++++++++++++-------------------- + 1 file changed, 42 insertions(+), 35 deletions(-) + +--- a/drivers/irqchip/irq-gic-v5.c ++++ b/drivers/irqchip/irq-gic-v5.c +@@ -783,15 +783,14 @@ static void gicv5_irq_lpi_domain_free(st + { + struct irq_data *d; + +- if (WARN_ON_ONCE(nr_irqs != 1)) +- return; ++ for (unsigned int i = 0; i < nr_irqs; i++, virq++) { ++ d = irq_domain_get_irq_data(domain, virq); + +- d = irq_domain_get_irq_data(domain, virq); ++ release_lpi(d->hwirq); + +- release_lpi(d->hwirq); +- +- irq_set_handler(virq, NULL); +- irq_domain_reset_irq_data(d); ++ irq_set_handler(virq, NULL); ++ irq_domain_reset_irq_data(d); ++ } + } + + static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq, +@@ -799,32 +798,39 @@ static int gicv5_irq_lpi_domain_alloc(st + { + irq_hw_number_t hwirq; + struct irq_data *irqd; ++ unsigned int i; + int ret; + +- if (WARN_ON_ONCE(nr_irqs != 1)) +- return -EINVAL; +- +- ret = alloc_lpi(); +- if (ret < 0) +- return ret; +- hwirq = ret; ++ for (i = 0; i < nr_irqs; i++) { ++ ret = alloc_lpi(); ++ if (ret < 0) ++ goto out_free_lpis; ++ hwirq = ret; ++ ++ ret = gicv5_irs_iste_alloc(hwirq); ++ if (ret < 0) { ++ /* Undo partial state first, then clean up the rest */ ++ release_lpi(hwirq); ++ goto out_free_lpis; ++ } + +- irqd = irq_domain_get_irq_data(domain, virq); ++ irqd = irq_domain_get_irq_data(domain, virq + i); + +- irq_domain_set_info(domain, virq, hwirq, &gicv5_lpi_irq_chip, NULL, +- handle_fasteoi_irq, NULL, NULL); +- irqd_set_single_target(irqd); ++ irq_domain_set_info(domain, virq + i, hwirq, &gicv5_lpi_irq_chip, ++ NULL, handle_fasteoi_irq, NULL, NULL); ++ irqd_set_single_target(irqd); + +- ret = gicv5_irs_iste_alloc(hwirq); +- if (ret < 0) { +- release_lpi(hwirq); +- return ret; ++ gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI); ++ gicv5_lpi_config_reset(irqd); + } + +- gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI); +- gicv5_lpi_config_reset(irqd); +- + return 0; ++ ++out_free_lpis: ++ if (i) ++ gicv5_irq_lpi_domain_free(domain, virq, i); ++ ++ return ret; + } + + static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = { +@@ -850,21 +856,21 @@ static int gicv5_irq_ipi_domain_alloc(st + unsigned int nr_irqs, void *arg) + { + struct irq_data *irqd; +- int ret, i; ++ int ret; + +- for (i = 0; i < nr_irqs; i++) { +- ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, NULL); +- if (ret) +- return ret; ++ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); ++ if (ret) ++ return ret; + +- irqd = irq_domain_get_irq_data(domain, virq + i); ++ for (unsigned int i = 0; i < nr_irqs; i++, virq++) { ++ irqd = irq_domain_get_irq_data(domain, virq); + +- irq_domain_set_hwirq_and_chip(domain, virq + i, i, +- &gicv5_ipi_irq_chip, NULL); ++ irq_domain_set_hwirq_and_chip(domain, virq, i, ++ &gicv5_ipi_irq_chip, NULL); + + irqd_set_single_target(irqd); + +- irq_set_handler(virq + i, handle_percpu_irq); ++ irq_set_handler(virq, handle_percpu_irq); + } + + return 0; +@@ -884,8 +890,9 @@ static void gicv5_irq_ipi_domain_free(st + + irq_set_handler(virq + i, NULL); + irq_domain_reset_irq_data(d); +- irq_domain_free_irqs_parent(domain, virq + i, 1); + } ++ ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); + } + + static const struct irq_domain_ops gicv5_irq_ipi_domain_ops = { diff --git a/queue-7.0/irqchip-meson-gpio-use-the-correct-register-in-meson_s4_gpio_irq_set_type.patch b/queue-7.0/irqchip-meson-gpio-use-the-correct-register-in-meson_s4_gpio_irq_set_type.patch new file mode 100644 index 0000000000..e767717ab6 --- /dev/null +++ b/queue-7.0/irqchip-meson-gpio-use-the-correct-register-in-meson_s4_gpio_irq_set_type.patch @@ -0,0 +1,37 @@ +From 5363b67ac8ebcc3e227dbf59fc8061949109841d Mon Sep 17 00:00:00 2001 +From: Xianwei Zhao +Date: Fri, 8 May 2026 07:36:54 +0000 +Subject: irqchip/meson-gpio: Use the correct register in meson_s4_gpio_irq_set_type() + +From: Xianwei Zhao + +commit 5363b67ac8ebcc3e227dbf59fc8061949109841d upstream. + +meson_s4_gpio_irq_set_type() uses the both-edge trigger register for +configuring level type and single edge mode interrupts, which is not +correct. + +Use REG_EDGE_POL instead. + +Fixes: bbd6fcc76b39 ("irqchip: Add support for Amlogic A4 and A5 SoCs") +Signed-off-by: Xianwei Zhao +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260508-a9-gpio-irqchip-v1-1-9dc5f3e022e0@amlogic.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-meson-gpio.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/irqchip/irq-meson-gpio.c ++++ b/drivers/irqchip/irq-meson-gpio.c +@@ -415,8 +415,7 @@ static int meson_s4_gpio_irq_set_type(st + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + val |= BIT(ctl->params->edge_single_offset + idx); + +- meson_gpio_irq_update_bits(ctl, params->edge_pol_reg, +- BIT(idx) | BIT(12 + idx), val); ++ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, BIT(idx) | BIT(12 + idx), val); + return 0; + }; + diff --git a/queue-7.0/irqchip-riscv-imsic-clear-interrupt-move-state-during-cpu-offlining.patch b/queue-7.0/irqchip-riscv-imsic-clear-interrupt-move-state-during-cpu-offlining.patch new file mode 100644 index 0000000000..19857e0caa --- /dev/null +++ b/queue-7.0/irqchip-riscv-imsic-clear-interrupt-move-state-during-cpu-offlining.patch @@ -0,0 +1,53 @@ +From cefafbd561402b0fe6447449364a30315b9b1570 Mon Sep 17 00:00:00 2001 +From: Yong-Xuan Wang +Date: Fri, 8 May 2026 02:31:21 -0700 +Subject: irqchip/riscv-imsic: Clear interrupt move state during CPU offlining + +From: Yong-Xuan Wang + +commit cefafbd561402b0fe6447449364a30315b9b1570 upstream. + +Affinity changes of IMSIC interrupts have to be careful to not lose an +interrupt in the process. Each vector keeps track of an affinity change in +progress with two pointers in struct imsic_vector. + +imsic_vector::move_prev points to the previous CPU target data and +imsic_vector::move_next to the designated new CPU target data. + +imsic_vector::move_prev on the new CPU can only be cleared after the +previous CPU has cleared imsic_vector::move_next, which ususally happens in +__imsic_remote_sync(). + +In case of CPU hot-unplug __imsic_remote_sync() is not invoked because the +CPU is already marked offline. That means imsic_vector::move_prev becomes +stale until the CPU is onlined again. + +The stale pointer prevents further affinity changes for the affected +interrupts. + +Solve this by clearing the imsic_vector::move_prev pointers in the CPU +hotplug offline path. + +[ tglx: Replace word salad in change log ] + +Fixes: 0f67911e821c ("irqchip/riscv-imsic: Separate next and previous pointers in IMSIC vector") +Signed-off-by: Yong-Xuan Wang +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260508-imsic-v2-1-e9f08dd46cf5@sifive.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-riscv-imsic-early.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/irqchip/irq-riscv-imsic-early.c ++++ b/drivers/irqchip/irq-riscv-imsic-early.c +@@ -158,6 +158,8 @@ static int imsic_dying_cpu(unsigned int + /* Cleanup IPIs */ + imsic_ipi_dying_cpu(); + ++ imsic_local_sync_all(false); ++ + /* Mark per-CPU IMSIC state as offline */ + imsic_state_offline(); + diff --git a/queue-7.0/libceph-fix-potential-null-ptr-deref-in-decode_choose_args.patch b/queue-7.0/libceph-fix-potential-null-ptr-deref-in-decode_choose_args.patch new file mode 100644 index 0000000000..83fe4a1094 --- /dev/null +++ b/queue-7.0/libceph-fix-potential-null-ptr-deref-in-decode_choose_args.patch @@ -0,0 +1,47 @@ +From 28b0a2ab8c82d0bbdeb8013029c67c978ce6e4bf Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Tue, 12 May 2026 18:16:40 +0200 +Subject: libceph: Fix potential null-ptr-deref in decode_choose_args() + +From: Raphael Zimmer + +commit 28b0a2ab8c82d0bbdeb8013029c67c978ce6e4bf upstream. + +A message of type CEPH_MSG_OSD_MAP contains an OSD map that itself +contains a CRUSH map. When decoding this CRUSH map in crush_decode(), an +array of max_buckets CRUSH buckets is decoded, where some indices may +not refer to actual buckets and are therefore set to NULL. The received +CRUSH map may optionally contain choose_args that get decoded in +decode_choose_args(). When decoding a crush_choose_arg_map, a series of +choose_args for different buckets is decoded, with the bucket_index +being read from the incoming message. It is only checked that the bucket +index does not exceed max_buckets, but not that it doesn't point to an +index with a NULL bucket. If a (potentially corrupted) message contains +a crush_choose_arg_map including such a bucket_index, a null pointer +dereference may occur in the subsequent processing when attempting to +access the bucket with the given index. + +This patch fixes the issue by extending the affected check. Now, it is +only attempted to access the bucket if it is not NULL. + +Cc: stable@vger.kernel.org +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -389,7 +389,8 @@ static int decode_choose_args(void **p, + goto fail; + + if (arg->ids_size && +- arg->ids_size != c->buckets[bucket_index]->size) ++ (!c->buckets[bucket_index] || ++ arg->ids_size != c->buckets[bucket_index]->size)) + goto e_inval; + } + diff --git a/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-__ceph_x_decrypt.patch b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-__ceph_x_decrypt.patch new file mode 100644 index 0000000000..2850986224 --- /dev/null +++ b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-__ceph_x_decrypt.patch @@ -0,0 +1,47 @@ +From 821365487aa58d06bda65c676ba215d506ba9768 Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Tue, 28 Apr 2026 14:15:46 +0200 +Subject: libceph: Fix potential out-of-bounds access in __ceph_x_decrypt() + +From: Raphael Zimmer + +commit 821365487aa58d06bda65c676ba215d506ba9768 upstream. + +In __ceph_x_decrypt(), a part of the buffer p is interpreted as a +ceph_x_encrypt_header, and the magic field of this struct is accessed. +This happens without any guarantee that the buffer is large enough to +hold this struct. The function parameter ciphertext_len represents the +length of the ciphertext to decrypt and is guaranteed to be at most the +remaining size of the allocated buffer p. However, this value is not +necessarily greater than sizeof(ceph_x_encrypt_header). E.g., a message +frame of type FRAME_TAG_AUTH_REPLY_MORE, that is just as long to hold +the ciphertext at its end with a ciphertext_len of 8 or less, can +trigger an out-of-bounds memory access when accessing hdr->magic. + +This patch fixes the issue by adding a check to ensure that the +decrypted plaintext in the buffer is large enough to represent at least +the ceph_x_encrypt_header. + +Cc: stable@vger.kernel.org +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/auth_x.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/ceph/auth_x.c ++++ b/net/ceph/auth_x.c +@@ -115,6 +115,11 @@ static int __ceph_x_decrypt(const struct + if (ret) + return ret; + ++ if (plaintext_len < sizeof(*hdr)) { ++ pr_err("%s plaintext too small %d\n", __func__, plaintext_len); ++ return -EINVAL; ++ } ++ + hdr = p + ceph_crypt_data_offset(key); + if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) { + pr_err("%s bad magic\n", __func__); diff --git a/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-crush_decode.patch b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-crush_decode.patch new file mode 100644 index 0000000000..8c80dcc81b --- /dev/null +++ b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-crush_decode.patch @@ -0,0 +1,98 @@ +From 4c79fc2d598694bda845b46229c9d48b65042970 Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Wed, 22 Apr 2026 10:47:13 +0200 +Subject: libceph: Fix potential out-of-bounds access in crush_decode() + +From: Raphael Zimmer + +commit 4c79fc2d598694bda845b46229c9d48b65042970 upstream. + +A message of type CEPH_MSG_OSD_MAP containing a crush map with at least +one bucket has two fields holding the bucket algorithm. If the values +in these two fields differ, an out-of-bounds access can occur. This is +the case because the first algorithm field (alg) is used to allocate +the correct amount of memory for a bucket of this type, while the second +algorithm field inside the bucket (b->alg) is used in the subsequent +processing. + +This patch fixes the issue by adding a check that compares alg and +b->alg and aborts the processing in case they differ. Furthermore, +b->alg is set to 0 in this case, because the destruction of the crush +map also uses this field to determine the bucket type, which can again +result in an out-of-bounds access when trying to free the memory pointed +to by the fields of the bucket. To correctly free the memory allocated +for the bucket in such a case, the corresponding call to kfree is moved +from the algorithm-specific crush_destroy_bucket functions to the +generic crush_destroy_bucket(). + +Cc: stable@vger.kernel.org +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/crush/crush.c | 6 +----- + net/ceph/osdmap.c | 4 ++++ + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/net/ceph/crush/crush.c ++++ b/net/ceph/crush/crush.c +@@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const s + void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b) + { + kfree(b->h.items); +- kfree(b); + } + + void crush_destroy_bucket_list(struct crush_bucket_list *b) +@@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct cr + kfree(b->item_weights); + kfree(b->sum_weights); + kfree(b->h.items); +- kfree(b); + } + + void crush_destroy_bucket_tree(struct crush_bucket_tree *b) + { + kfree(b->h.items); + kfree(b->node_weights); +- kfree(b); + } + + void crush_destroy_bucket_straw(struct crush_bucket_straw *b) +@@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct c + kfree(b->straws); + kfree(b->item_weights); + kfree(b->h.items); +- kfree(b); + } + + void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b) + { + kfree(b->item_weights); + kfree(b->h.items); +- kfree(b); + } + + void crush_destroy_bucket(struct crush_bucket *b) +@@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_b + crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b); + break; + } ++ kfree(b); + } + + /** +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -517,6 +517,10 @@ static struct crush_map *crush_decode(vo + b->id = ceph_decode_32(p); + b->type = ceph_decode_16(p); + b->alg = ceph_decode_8(p); ++ if (b->alg != alg) { ++ b->alg = 0; ++ goto bad; ++ } + b->hash = ceph_decode_8(p); + b->weight = ceph_decode_32(p); + b->size = ceph_decode_32(p); diff --git a/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-osdmap_decode.patch b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-osdmap_decode.patch new file mode 100644 index 0000000000..d58d850b7b --- /dev/null +++ b/queue-7.0/libceph-fix-potential-out-of-bounds-access-in-osdmap_decode.patch @@ -0,0 +1,41 @@ +From 35d0ed82d03e5ee77ea4f31f20e29562a7721649 Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Tue, 5 May 2026 11:08:12 +0200 +Subject: libceph: Fix potential out-of-bounds access in osdmap_decode() + +From: Raphael Zimmer + +commit 35d0ed82d03e5ee77ea4f31f20e29562a7721649 upstream. + +When decoding osd_state and osd_weight from an incoming osdmap in +osdmap_decode(), both are decoded for each osd, i.e., map->max_osd +times. The ceph_decode_need() check only accounts for +sizeof(*map->osd_weight) once. This can potentially result in an +out-of-bounds memory access if the incoming message is corrupted such +that the max_osd value exceeds the actual content of the osdmap message. + +This patch fixes the issue by changing the corresponding part in the +ceph_decode_need() check to account for +map->max_osd*sizeof(*map->osd_weight). + +Cc: stable@vger.kernel.org +Fixes: dcbc919a5dc8 ("libceph: switch osdmap decoding to use ceph_decode_entity_addr") +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -1702,7 +1702,7 @@ static int osdmap_decode(void **p, void + ceph_decode_need(p, end, 3*sizeof(u32) + + map->max_osd*(struct_v >= 5 ? sizeof(u32) : + sizeof(u8)) + +- sizeof(*map->osd_weight), e_inval); ++ map->max_osd*sizeof(*map->osd_weight), e_inval); + if (ceph_decode_32(p) != map->max_osd) + goto e_inval; + diff --git a/queue-7.0/libceph-handle-rbtree-insertion-error-in-decode_choose_args.patch b/queue-7.0/libceph-handle-rbtree-insertion-error-in-decode_choose_args.patch new file mode 100644 index 0000000000..2ce34dbf82 --- /dev/null +++ b/queue-7.0/libceph-handle-rbtree-insertion-error-in-decode_choose_args.patch @@ -0,0 +1,48 @@ +From d289478cfc0bcf81c7914200d6abdcb78bd04ded Mon Sep 17 00:00:00 2001 +From: Raphael Zimmer +Date: Tue, 12 May 2026 09:29:30 +0200 +Subject: libceph: handle rbtree insertion error in decode_choose_args() + +From: Raphael Zimmer + +commit d289478cfc0bcf81c7914200d6abdcb78bd04ded upstream. + +A message of type CEPH_MSG_OSD_MAP contains an OSD map that itself +contains a CRUSH map. The received CRUSH map may optionally contain +choose_args that get decoded in decode_choose_args(). In this function, +num_choose_arg_maps is read from the message, and a corresponding number +of crush_choose_arg_maps gets decoded afterwards. Each +crush_choose_arg_map has a choose_args_index, which serves as the key +when inserting it into the choose_args rbtree of the decoded crush_map. +If a (potentially corrupted) message contains two crush_choose_arg_maps +with the same index, the assertion in insert_choose_arg_map() triggers a +kernel BUG when trying to insert the second crush_choose_arg_map. + +This patch fixes the issue by switching to the non-asserting rbtree +insertion function and rejecting the message if the insertion fails. + +[ idryomov: changelog ] + +Cc: stable@vger.kernel.org +Signed-off-by: Raphael Zimmer +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -394,7 +394,10 @@ static int decode_choose_args(void **p, + goto e_inval; + } + +- insert_choose_arg_map(&c->choose_args, arg_map); ++ if (!__insert_choose_arg_map(&c->choose_args, arg_map)) { ++ ret = -EEXIST; ++ goto fail; ++ } + } + + return 0; diff --git a/queue-7.0/netfs-fix-error-handling-in-netfs_extract_user_iter.patch b/queue-7.0/netfs-fix-error-handling-in-netfs_extract_user_iter.patch new file mode 100644 index 0000000000..bcb36f14ef --- /dev/null +++ b/queue-7.0/netfs-fix-error-handling-in-netfs_extract_user_iter.patch @@ -0,0 +1,67 @@ +From 0aad5704c6b4d14007d4eab15883e8524e4310f4 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 12 May 2026 13:33:46 +0100 +Subject: netfs: fix error handling in netfs_extract_user_iter() + +From: Paulo Alcantara + +commit 0aad5704c6b4d14007d4eab15883e8524e4310f4 upstream. + +In netfs_extract_user_iter(), if iov_iter_extract_pages() failed to +extract user pages, bail out on -ENOMEM, otherwise return the error +code only if @npages == 0, allowing short DIO reads and writes to be +issued. + +This fixes mmapstress02 from LTP tests against CIFS. + +Fixes: 85dd2c8ff368 ("netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator") +Reported-by: Xiaoli Feng +Signed-off-by: Paulo Alcantara (Red Hat) +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-10-dhowells@redhat.com +Cc: netfs@lists.linux.dev +Cc: stable@vger.kernel.org +Cc: linux-cifs@vger.kernel.org +Cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/netfs/iterator.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +--- a/fs/netfs/iterator.c ++++ b/fs/netfs/iterator.c +@@ -22,7 +22,7 @@ + * + * Extract the page fragments from the given amount of the source iterator and + * build up a second iterator that refers to all of those bits. This allows +- * the original iterator to disposed of. ++ * the original iterator to be disposed of. + * + * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA be + * allowed on the pages extracted. +@@ -67,8 +67,8 @@ ssize_t netfs_extract_user_iter(struct i + ret = iov_iter_extract_pages(orig, &pages, count, + max_pages - npages, extraction_flags, + &offset); +- if (ret < 0) { +- pr_err("Couldn't get user pages (rc=%zd)\n", ret); ++ if (unlikely(ret <= 0)) { ++ ret = ret ?: -EIO; + break; + } + +@@ -97,6 +97,13 @@ ssize_t netfs_extract_user_iter(struct i + npages += cur_npages; + } + ++ if (ret < 0 && (ret == -ENOMEM || npages == 0)) { ++ for (i = 0; i < npages; i++) ++ unpin_user_page(bv[i].bv_page); ++ kvfree(bv); ++ return ret; ++ } ++ + iov_iter_bvec(new, orig->data_source, bv, npages, orig_len - count); + return npages; + } diff --git a/queue-7.0/nfsd-fix-file-change-detection-in-cb_getattr.patch b/queue-7.0/nfsd-fix-file-change-detection-in-cb_getattr.patch new file mode 100644 index 0000000000..dfa6caadbc --- /dev/null +++ b/queue-7.0/nfsd-fix-file-change-detection-in-cb_getattr.patch @@ -0,0 +1,77 @@ +From 304d81a2fbf2b454def4debcb38ea173911b72cd Mon Sep 17 00:00:00 2001 +From: Scott Mayhew +Date: Tue, 7 Apr 2026 18:08:57 -0400 +Subject: nfsd: fix file change detection in CB_GETATTR + +From: Scott Mayhew + +commit 304d81a2fbf2b454def4debcb38ea173911b72cd upstream. + +RFC 8881, section 10.4.3 doesn't say anything about caching the file +size in the delegation record, nor does it say anything about comparing +a cached file size with the size reported by the client in the +CB_GETATTR reply for the purpose of determining if the client holds +modified data for the file. + +What section 10.4.3 of RFC 8881 does say is that the server should +compare the *current* file size with the size reported by the client +holding the delegation in the CB_GETATTR reply, and if they differ to +treat it as a modification regardless of the change attribute retrieved +via the CB_GETATTR. + +Doing otherwise would cause the server to believe the client holding the +delegation has a modified version of the file, even if the client +flushed the modifications to the server prior to the CB_GETATTR. This +would have the added side effect of subsequent CB_GETATTRs causing +updates to the mtime, ctime, and change attribute even if the client +holding the delegation makes no further updates to the file. + +Modify nfsd4_deleg_getattr_conflict() to obtain the current file size +via i_size_read(). Retain the ncf_cur_fsize field, since it's a +convenient way to return the file size back to nfsd4_encode_fattr4(), +but don't use it for the purpose of detecting file changes. Remove the +unnecessary initialization of ncf_cur_fsize in nfs4_open_delegation(). + +Also, if we recall the delegation (because the client didn't respond to +the CB_GETATTR), then skip the logic that checks the nfs4_cb_fattr +fields. + +Fixes: c5967721e106 ("NFSD: handle GETATTR conflict with write delegation") +Cc: stable@vger.kernel.org +Signed-off-by: Scott Mayhew +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4state.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6368,7 +6368,6 @@ nfs4_open_delegation(struct svc_rqst *rq + } + open->op_delegate_type = deleg_ts ? OPEN_DELEGATE_WRITE_ATTRS_DELEG : + OPEN_DELEGATE_WRITE; +- dp->dl_cb_fattr.ncf_cur_fsize = stat.size; + dp->dl_cb_fattr.ncf_initial_cinfo = nfsd4_change_attribute(&stat); + dp->dl_atime = stat.atime; + dp->dl_ctime = stat.ctime; +@@ -9417,11 +9416,15 @@ nfsd4_deleg_getattr_conflict(struct svc_ + if (status != nfserr_jukebox || + !nfsd_wait_for_delegreturn(rqstp, inode)) + goto out_status; ++ status = nfs_ok; ++ goto out_status; ++ } ++ if (!ncf->ncf_file_modified) { ++ if (ncf->ncf_initial_cinfo != ncf->ncf_cb_change) ++ ncf->ncf_file_modified = true; ++ else if (i_size_read(inode) != ncf->ncf_cb_fsize) ++ ncf->ncf_file_modified = true; + } +- if (!ncf->ncf_file_modified && +- (ncf->ncf_initial_cinfo != ncf->ncf_cb_change || +- ncf->ncf_cur_fsize != ncf->ncf_cb_fsize)) +- ncf->ncf_file_modified = true; + if (ncf->ncf_file_modified) { + int err; + diff --git a/queue-7.0/nfsd-fix-get_dir_delegation-when-vfs-leases-are-disabled.patch b/queue-7.0/nfsd-fix-get_dir_delegation-when-vfs-leases-are-disabled.patch new file mode 100644 index 0000000000..b72c51f7a7 --- /dev/null +++ b/queue-7.0/nfsd-fix-get_dir_delegation-when-vfs-leases-are-disabled.patch @@ -0,0 +1,46 @@ +From b0bf14546bcefa4ea49f5efcd7db2a99f0cabde9 Mon Sep 17 00:00:00 2001 +From: Olga Kornievskaia +Date: Fri, 3 Apr 2026 11:20:55 -0400 +Subject: nfsd: fix GET_DIR_DELEGATION when VFS leases are disabled + +From: Olga Kornievskaia + +commit b0bf14546bcefa4ea49f5efcd7db2a99f0cabde9 upstream. + +When leases are disabled on the server, running xfstest generic/309 leads +to an error because GET_DIR_DELEGATION returns EINVAL. + +nfsd_get_dir_deleg() can fail in several ways: like memory allocation and +unable to get a lease because either leases are disable or it's already +held. Currently only the condition "already held" is translated to +returning directory-delegation-is-unavailable error. However, other failure +conditions are likely temporary and thus should result in the same kind +of error. + +Fixes: 8b99f6a8c116 ("nfsd: wire up GET_DIR_DELEGATION handling") +Cc: stable@vger.kernel.org +Signed-off-by: Olga Kornievskaia +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4proc.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 85e94c30285a..2797da8cc950 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2535,10 +2535,6 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp, + dd = nfsd_get_dir_deleg(cstate, gdd, nf); + nfsd_file_put(nf); + if (IS_ERR(dd)) { +- int err = PTR_ERR(dd); +- +- if (err != -EAGAIN) +- return nfserrno(err); + gdd->gddrnf_status = GDD4_UNAVAIL; + return nfs_ok; + } +-- +2.54.0 + diff --git a/queue-7.0/nfsd-update-mtime-ctime-on-clone-in-presense-of-delegated-attributes.patch b/queue-7.0/nfsd-update-mtime-ctime-on-clone-in-presense-of-delegated-attributes.patch new file mode 100644 index 0000000000..368b0cd790 --- /dev/null +++ b/queue-7.0/nfsd-update-mtime-ctime-on-clone-in-presense-of-delegated-attributes.patch @@ -0,0 +1,112 @@ +From 2863bac7f49c4acd80a048ce52506a2b9c8db015 Mon Sep 17 00:00:00 2001 +From: Olga Kornievskaia +Date: Fri, 10 Apr 2026 12:09:19 -0400 +Subject: nfsd: update mtime/ctime on CLONE in presense of delegated attributes + +From: Olga Kornievskaia + +commit 2863bac7f49c4acd80a048ce52506a2b9c8db015 upstream. + +When delegated attributes are given on open, the file is opened with +NOCMTIME and modifying operations do not update mtime/ctime as to not get +out-of-sync with the client's delegated view. However, for CLONE operation, +the server should update its view of mtime/ctime and reflect that in any +GETATTR queries. + +Fixes: e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation") +Cc: stable@vger.kernel.org +Signed-off-by: Olga Kornievskaia +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4proc.c | 3 +++ + fs/nfsd/nfs4state.c | 44 +++++++++++++++++++++++++++++--------------- + fs/nfsd/state.h | 1 + + 3 files changed, 33 insertions(+), 15 deletions(-) + +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1413,6 +1413,9 @@ nfsd4_clone(struct svc_rqst *rqstp, stru + dst, clone->cl_dst_pos, clone->cl_count, + EX_ISSYNC(cstate->current_fh.fh_export)); + ++ if (!status && (READ_ONCE(dst->nf_file->f_mode) & FMODE_NOCMTIME) != 0) ++ nfsd_update_cmtime_attr(dst->nf_file, 0); ++ + nfsd_file_put(dst); + nfsd_file_put(src); + out: +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1226,10 +1226,6 @@ static void put_deleg_file(struct nfs4_f + + static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f) + { +- struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME | ATTR_DELEG }; +- struct inode *inode = file_inode(f); +- int ret; +- + /* don't do anything if FMODE_NOCMTIME isn't set */ + if ((READ_ONCE(f->f_mode) & FMODE_NOCMTIME) == 0) + return; +@@ -1247,17 +1243,7 @@ static void nfsd4_finalize_deleg_timesta + return; + + /* Stamp everything to "now" */ +- inode_lock(inode); +- ret = notify_change(&nop_mnt_idmap, f->f_path.dentry, &ia, NULL); +- inode_unlock(inode); +- if (ret) { +- struct inode *inode = file_inode(f); +- +- pr_notice_ratelimited("nfsd: Unable to update timestamps on inode %02x:%02x:%lu: %d\n", +- MAJOR(inode->i_sb->s_dev), +- MINOR(inode->i_sb->s_dev), +- inode->i_ino, ret); +- } ++ nfsd_update_cmtime_attr(f, ATTR_ATIME); + } + + static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) +@@ -9550,3 +9536,31 @@ out_delegees: + put_nfs4_file(fp); + return ERR_PTR(status); + } ++ ++/** ++ * nfsd_update_cmtime_attr - update file's delegated ctime/mtime, ++ * and optionally other attributes (ie ATTR_ATIME). ++ * @f: pointer to an opened file ++ * @flags: any additional flags that should be updated ++ * ++ * Given upon opening a file delegated attributes were issues, update ++ * @f attributes to current times. ++ */ ++void nfsd_update_cmtime_attr(struct file *f, unsigned int flags) ++{ ++ int ret; ++ struct inode *inode = file_inode(f); ++ struct iattr attr = { ++ .ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_DELEG | flags, ++ }; ++ ++ inode_lock(inode); ++ ret = notify_change(&nop_mnt_idmap, f->f_path.dentry, &attr, NULL); ++ inode_unlock(inode); ++ if (ret) ++ pr_notice_ratelimited("nfsd: Unable to update timestamps on " ++ "inode %02x:%02x:%lu: %d\n", ++ MAJOR(inode->i_sb->s_dev), ++ MINOR(inode->i_sb->s_dev), ++ inode->i_ino, ret); ++} +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -834,6 +834,7 @@ extern void nfsd4_shutdown_copy(struct n + void nfsd4_put_client(struct nfs4_client *clp); + void nfsd4_async_copy_reaper(struct nfsd_net *nn); + bool nfsd4_has_active_async_copies(struct nfs4_client *clp); ++void nfsd_update_cmtime_attr(struct file *f, unsigned int flags); + extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name, + struct xdr_netobj princhash, struct nfsd_net *nn); + extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); diff --git a/queue-7.0/nfsd-update-mtime-ctime-on-copy-in-presence-of-delegated-attributes.patch b/queue-7.0/nfsd-update-mtime-ctime-on-copy-in-presence-of-delegated-attributes.patch new file mode 100644 index 0000000000..fd59f9d4cc --- /dev/null +++ b/queue-7.0/nfsd-update-mtime-ctime-on-copy-in-presence-of-delegated-attributes.patch @@ -0,0 +1,70 @@ +From 4183cf383b6faec17a0882b84cd2d901dba62b16 Mon Sep 17 00:00:00 2001 +From: Olga Kornievskaia +Date: Fri, 10 Apr 2026 12:09:20 -0400 +Subject: nfsd: update mtime/ctime on COPY in presence of delegated attributes + +From: Olga Kornievskaia + +commit 4183cf383b6faec17a0882b84cd2d901dba62b16 upstream. + +When delegated attributes are given on open, the file is opened with +NOCMTIME and modifying operations do not update mtime/ctime as to not get +out-of-sync with the client's delegated view. However, for COPY operation, +the server should update its view of mtime/ctime and reflect that in any +GETATTR queries. + +Fixes: e5e9b24ab8fa ("nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation") +Cc: stable@vger.kernel.org +Signed-off-by: Olga Kornievskaia +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4proc.c | 11 ++++++++++- + fs/nfsd/xdr4.h | 1 + + 2 files changed, 11 insertions(+), 1 deletion(-) + +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2121,8 +2121,10 @@ do_callback: + + set_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags); + trace_nfsd_copy_async_done(copy); +- nfsd4_send_cb_offload(copy); + atomic_dec(©->cp_nn->pending_async_copies); ++ if (copy->cp_res.wr_bytes_written > 0 && copy->attr_update) ++ nfsd_update_cmtime_attr(copy->nf_dst->nf_file, 0); ++ nfsd4_send_cb_offload(copy); + return 0; + } + +@@ -2182,6 +2184,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struc + memcpy(&result->cb_stateid, ©->cp_stateid.cs_stid, + sizeof(result->cb_stateid)); + dup_copy_fields(copy, async_copy); ++ if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) & ++ FMODE_NOCMTIME) != 0) ++ async_copy->attr_update = true; + memcpy(async_copy->cp_cb_offload.co_referring_sessionid.data, + cstate->session->se_sessionid.data, + NFS4_MAX_SESSIONID_LEN); +@@ -2200,6 +2205,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struc + } else { + status = nfsd4_do_copy(copy, copy->nf_src->nf_file, + copy->nf_dst->nf_file, true); ++ if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) & ++ FMODE_NOCMTIME) != 0 && ++ copy->cp_res.wr_bytes_written > 0) ++ nfsd_update_cmtime_attr(copy->nf_dst->nf_file, 0); + } + out: + trace_nfsd_copy_done(copy, status); +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -752,6 +752,7 @@ struct nfsd4_copy { + + struct nfsd_file *nf_src; + struct nfsd_file *nf_dst; ++ bool attr_update; + + copy_stateid_t cp_stateid; + diff --git a/queue-7.0/nvme-apple-reset-q-sq_tail-during-queue-init.patch b/queue-7.0/nvme-apple-reset-q-sq_tail-during-queue-init.patch new file mode 100644 index 0000000000..50cb39f307 --- /dev/null +++ b/queue-7.0/nvme-apple-reset-q-sq_tail-during-queue-init.patch @@ -0,0 +1,35 @@ +From a6ab75639e23169a741b0b2e12191fd8acb32c73 Mon Sep 17 00:00:00 2001 +From: Nick Chan +Date: Thu, 14 May 2026 21:16:01 +0800 +Subject: nvme-apple: Reset q->sq_tail during queue init + +From: Nick Chan + +commit a6ab75639e23169a741b0b2e12191fd8acb32c73 upstream. + +Fixes a "duplicate tag error for tag 0" firmware crash during controller +reset while setting up a queue on Apple A11 / T8015 caused by stale +entries in the submission queue due to an invalid sq_tail offset after +reset. + +Fixes: 04d8ecf37b5e ("nvme: apple: Add Apple A11 support") +Cc: stable@vger.kernel.org +Suggested-by: Yuriy Havrylyuk +Reviewed-by: Sven Peter +Signed-off-by: Nick Chan +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/apple.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/nvme/host/apple.c ++++ b/drivers/nvme/host/apple.c +@@ -1009,6 +1009,7 @@ static void apple_nvme_init_queue(struct + unsigned int depth = apple_nvme_queue_depth(q); + struct apple_nvme *anv = queue_to_apple_nvme(q); + ++ q->sq_tail = 0; + q->cq_head = 0; + q->cq_phase = 1; + if (anv->hw->has_lsq_nvmmu) diff --git a/queue-7.0/platform-x86-intel-move-debugfs-register-before-creating-devices.patch b/queue-7.0/platform-x86-intel-move-debugfs-register-before-creating-devices.patch new file mode 100644 index 0000000000..d69890a1f7 --- /dev/null +++ b/queue-7.0/platform-x86-intel-move-debugfs-register-before-creating-devices.patch @@ -0,0 +1,55 @@ +From ad3bff944c0f4f2e913298a9664391af32f87491 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 30 Apr 2026 08:11:01 -0700 +Subject: platform/x86: intel: Move debugfs register before creating devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivas Pandruvada + +commit ad3bff944c0f4f2e913298a9664391af32f87491 upstream. + +It is possible that the driver handling device is enumerated before +registering debugfs. If the driver wants to access debugfs by calling +tpmi_get_debugfs_dir(), this will return error in this case. + +Hence register debugfs before creating devices. + +Fixes: 811f67c51636 ("platform/x86/intel/tpmi: Add new auxiliary driver for performance limits") +Signed-off-by: Srinivas Pandruvada +Cc: Stable@vger.kernel.org +Link: https://patch.msgid.link/20260430151103.1549733-2-srinivas.pandruvada@linux.intel.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/intel/vsec_tpmi.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/platform/x86/intel/vsec_tpmi.c ++++ b/drivers/platform/x86/intel/vsec_tpmi.c +@@ -813,10 +813,6 @@ static int intel_vsec_tpmi_init(struct a + + auxiliary_set_drvdata(auxdev, tpmi_info); + +- ret = tpmi_create_devices(tpmi_info); +- if (ret) +- return ret; +- + /* + * Allow debugfs when security policy allows. Everything this debugfs + * interface provides, can also be done via /dev/mem access. If +@@ -826,6 +822,12 @@ static int intel_vsec_tpmi_init(struct a + if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO)) + tpmi_dbgfs_register(tpmi_info); + ++ ret = tpmi_create_devices(tpmi_info); ++ if (ret) { ++ debugfs_remove_recursive(tpmi_info->dbgfs_dir); ++ return ret; ++ } ++ + return 0; + } + diff --git a/queue-7.0/platform-x86-lenovo-wmi-helpers-fix-memory-leak-in-lwmi_dev_evaluate_int.patch b/queue-7.0/platform-x86-lenovo-wmi-helpers-fix-memory-leak-in-lwmi_dev_evaluate_int.patch new file mode 100644 index 0000000000..b4f8be0959 --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-helpers-fix-memory-leak-in-lwmi_dev_evaluate_int.patch @@ -0,0 +1,55 @@ +From 0c3887a134f191723b53e2a47e501b534c8723ee Mon Sep 17 00:00:00 2001 +From: Rong Zhang +Date: Sun, 10 May 2026 04:25:31 +0000 +Subject: platform/x86: lenovo-wmi-helpers: Fix memory leak in lwmi_dev_evaluate_int() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rong Zhang + +commit 0c3887a134f191723b53e2a47e501b534c8723ee upstream. + +lwmi_dev_evaluate_int() leaks output.pointer when retval == NULL (found +by sashiko.dev [1]). + +Fix it by moving `ret_obj = output.pointer' outside of the `if (retval)' +block so that it is always freed by the __free cleanup callback. + +No functional change intended. + +Reviewed-by: Mark Pearson +Fixes: e521d16e76cd ("platform/x86: Add lenovo-wmi-helpers") +Cc: stable@vger.kernel.org +Link: https://sashiko.dev/#/patchset/20260331181208.421552-1-derekjohn.clark%40gmail.com [1] +Signed-off-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-2-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-helpers.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-helpers.c ++++ b/drivers/platform/x86/lenovo/wmi-helpers.c +@@ -46,7 +46,6 @@ int lwmi_dev_evaluate_int(struct wmi_dev + unsigned char *buf, size_t size, u32 *retval) + { + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; +- union acpi_object *ret_obj __free(kfree) = NULL; + struct acpi_buffer input = { size, buf }; + acpi_status status; + +@@ -55,8 +54,9 @@ int lwmi_dev_evaluate_int(struct wmi_dev + if (ACPI_FAILURE(status)) + return -EIO; + ++ union acpi_object *ret_obj __free(kfree) = output.pointer; ++ + if (retval) { +- ret_obj = output.pointer; + if (!ret_obj) + return -ENODATA; + diff --git a/queue-7.0/platform-x86-lenovo-wmi-helpers-move-gamezone-enums-to-wmi-helpers.patch b/queue-7.0/platform-x86-lenovo-wmi-helpers-move-gamezone-enums-to-wmi-helpers.patch new file mode 100644 index 0000000000..0947bbed97 --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-helpers-move-gamezone-enums-to-wmi-helpers.patch @@ -0,0 +1,119 @@ +From 7e27896e16a1c450085c3fe020eeb1b223880f37 Mon Sep 17 00:00:00 2001 +From: "Derek J. Clark" +Date: Sun, 10 May 2026 04:25:37 +0000 +Subject: platform/x86: lenovo-wmi-helpers: Move gamezone enums to wmi-helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Derek J. Clark + +commit 7e27896e16a1c450085c3fe020eeb1b223880f37 upstream. + +In a later patch in the series the thermal mode enum will be accessed +across three separate drivers (wmi-capdata, wmi-gamezonem and wmi-other). +An additional patch in the series will also add a function prototype that +needs to reference this enum in wmi-helpers.h. To avoid having all these +drivers begin to import each others headers, and to avoid declaring an +opaque enum to hande the second case, move the thermal mode enum to +helpers where it can be safely accessed by everything that needs it from +a single import. + +While at it, since the gamezone_events_type enum is the only remaining +item in the header, move that as well and remove the gamezone header +entirely. + +Cc: stable@vger.kernel.org +Reviewed-by: Mark Pearson +Reviewed-by: Rong Zhang +Tested-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-8-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-events.c | 2 +- + drivers/platform/x86/lenovo/wmi-gamezone.c | 1 - + drivers/platform/x86/lenovo/wmi-gamezone.h | 20 -------------------- + drivers/platform/x86/lenovo/wmi-helpers.h | 13 +++++++++++++ + drivers/platform/x86/lenovo/wmi-other.c | 1 - + 5 files changed, 14 insertions(+), 23 deletions(-) + delete mode 100644 drivers/platform/x86/lenovo/wmi-gamezone.h + +--- a/drivers/platform/x86/lenovo/wmi-events.c ++++ b/drivers/platform/x86/lenovo/wmi-events.c +@@ -17,7 +17,7 @@ + #include + + #include "wmi-events.h" +-#include "wmi-gamezone.h" ++#include "wmi-helpers.h" + + #define THERMAL_MODE_EVENT_GUID "D320289E-8FEA-41E0-86F9-911D83151B5F" + +--- a/drivers/platform/x86/lenovo/wmi-gamezone.c ++++ b/drivers/platform/x86/lenovo/wmi-gamezone.c +@@ -21,7 +21,6 @@ + #include + + #include "wmi-events.h" +-#include "wmi-gamezone.h" + #include "wmi-helpers.h" + #include "wmi-other.h" + +--- a/drivers/platform/x86/lenovo/wmi-gamezone.h ++++ /dev/null +@@ -1,20 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +- +-/* Copyright (C) 2025 Derek J. Clark */ +- +-#ifndef _LENOVO_WMI_GAMEZONE_H_ +-#define _LENOVO_WMI_GAMEZONE_H_ +- +-enum gamezone_events_type { +- LWMI_GZ_GET_THERMAL_MODE = 1, +-}; +- +-enum thermal_mode { +- LWMI_GZ_THERMAL_MODE_QUIET = 0x01, +- LWMI_GZ_THERMAL_MODE_BALANCED = 0x02, +- LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03, +- LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */ +- LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF, +-}; +- +-#endif /* !_LENOVO_WMI_GAMEZONE_H_ */ +--- a/drivers/platform/x86/lenovo/wmi-helpers.h ++++ b/drivers/platform/x86/lenovo/wmi-helpers.h +@@ -14,6 +14,19 @@ struct wmi_method_args_32 { + u32 arg1; + }; + ++enum lwmi_event_type { ++ LWMI_GZ_GET_THERMAL_MODE = 0x01, ++}; ++ ++enum thermal_mode { ++ LWMI_GZ_THERMAL_MODE_NONE = 0x00, ++ LWMI_GZ_THERMAL_MODE_QUIET = 0x01, ++ LWMI_GZ_THERMAL_MODE_BALANCED = 0x02, ++ LWMI_GZ_THERMAL_MODE_PERFORMANCE = 0x03, ++ LWMI_GZ_THERMAL_MODE_EXTREME = 0xE0, /* Ver 6+ */ ++ LWMI_GZ_THERMAL_MODE_CUSTOM = 0xFF, ++}; ++ + int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id, + unsigned char *buf, size_t size, u32 *retval); + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -47,7 +47,6 @@ + + #include "wmi-capdata.h" + #include "wmi-events.h" +-#include "wmi-gamezone.h" + #include "wmi-helpers.h" + #include "wmi-other.h" + #include "../firmware_attributes_class.h" diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-add-attribute-id-helper-functions.patch b/queue-7.0/platform-x86-lenovo-wmi-other-add-attribute-id-helper-functions.patch new file mode 100644 index 0000000000..993fbaf9e4 --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-add-attribute-id-helper-functions.patch @@ -0,0 +1,226 @@ +From 30a4ad208a7f7bdb790cd31d368595890045334f Mon Sep 17 00:00:00 2001 +From: "Derek J. Clark" +Date: Sun, 10 May 2026 04:25:38 +0000 +Subject: platform/x86: lenovo-wmi-other: Add Attribute ID helper functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Derek J. Clark + +commit 30a4ad208a7f7bdb790cd31d368595890045334f upstream. + +Adds lwmi_attr_id() function. In the same vein as LWMI_ATTR_ID_FAN_RPM(), +but as a generic, to de-duplicate attribute_id assignment boilerplate. + +Adds tunable_attr_01_id() function that breaks out the members of a +tunable_attr_01 struct and passes them to lwmi_attr_id(). + +No functional change intended. + +Cc: stable@vger.kernel.org +Reviewed-by: Rong Zhang +Tested-by: Rong Zhang +Reviewed-by: Mark Pearson +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-9-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-capdata.c | 8 ++-- + drivers/platform/x86/lenovo/wmi-capdata.h | 20 ++++++++++++ + drivers/platform/x86/lenovo/wmi-other.c | 49 ++++++++++++------------------ + 3 files changed, 44 insertions(+), 33 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-capdata.c ++++ b/drivers/platform/x86/lenovo/wmi-capdata.c +@@ -27,7 +27,6 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include +-#include + #include + #include + #include +@@ -48,6 +47,7 @@ + #include + + #include "wmi-capdata.h" ++#include "wmi-helpers.h" + + #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E" + #define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154" +@@ -58,9 +58,9 @@ + + #define LWMI_FEATURE_ID_FAN_TEST 0x05 + +-#define LWMI_ATTR_ID_FAN_TEST \ +- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ +- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST)) ++#define LWMI_ATTR_ID_FAN_TEST \ ++ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \ ++ LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE) + + enum lwmi_cd_type { + LENOVO_CAPABILITY_DATA_00, +--- a/drivers/platform/x86/lenovo/wmi-capdata.h ++++ b/drivers/platform/x86/lenovo/wmi-capdata.h +@@ -6,6 +6,7 @@ + #define _LENOVO_WMI_CAPDATA_H_ + + #include ++#include + #include + + #define LWMI_SUPP_VALID BIT(0) +@@ -19,6 +20,8 @@ + + #define LWMI_DEVICE_ID_FAN 0x04 + ++#define LWMI_TYPE_ID_NONE 0x00 ++ + struct component_match; + struct device; + struct cd_list; +@@ -57,6 +60,23 @@ struct lwmi_cd_binder { + cd_list_cb_t cd_fan_list_cb; + }; + ++/** ++ * lwmi_attr_id() - Formats a capability data attribute ID ++ * @dev_id: The u8 corresponding to the device ID. ++ * @feat_id: The u8 corresponding to the feature ID on the device. ++ * @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get. ++ * @type_id: The u8 corresponding to the sub-device. ++ * ++ * Return: encoded capability data attribute ID. ++ */ ++static inline u32 lwmi_attr_id(u8 dev_id, u8 feat_id, u8 mode_id, u8 type_id) ++{ ++ return (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, dev_id) | ++ FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, feat_id) | ++ FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode_id) | ++ FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, type_id)); ++} ++ + void lwmi_cd_match_add_all(struct device *master, struct component_match **matchptr); + int lwmi_cd00_get_data(struct cd_list *list, u32 attribute_id, struct capdata00 *output); + int lwmi_cd01_get_data(struct cd_list *list, u32 attribute_id, struct capdata01 *output); +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -61,8 +61,6 @@ + + #define LWMI_FEATURE_ID_FAN_RPM 0x03 + +-#define LWMI_TYPE_ID_NONE 0x00 +- + #define LWMI_FEATURE_VALUE_GET 17 + #define LWMI_FEATURE_VALUE_SET 18 + +@@ -70,13 +68,12 @@ + #define LWMI_FAN_NR 4 + #define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE) + +-#define LWMI_ATTR_ID_FAN_RPM(x) \ +- (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ +- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \ +- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x))) +- + #define LWMI_FAN_DIV 100 + ++#define LWMI_ATTR_ID_FAN_RPM(x) \ ++ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \ ++ LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x)) ++ + #define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other" + #define LWMI_OM_HWMON_NAME "lenovo_wmi_other" + +@@ -551,6 +548,18 @@ struct tunable_attr_01 { + u8 type_id; + }; + ++/** ++ * tunable_attr_01_id() - Formats a tunable_attr_01 to a capdata attribute ID ++ * @attr: The tunable_attr_01 to format. ++ * @mode: The u8 corresponding to the wmi-gamezone mode for set/get. ++ * ++ * Return: encoded capability data attribute ID. ++ */ ++static u32 tunable_attr_01_id(struct tunable_attr_01 *attr, u8 mode) ++{ ++ return lwmi_attr_id(attr->device_id, attr->feature_id, mode, attr->type_id); ++} ++ + static struct tunable_attr_01 ppt_pl1_spl = { + .device_id = LWMI_DEVICE_ID_CPU, + .feature_id = LWMI_FEATURE_ID_CPU_SPL, +@@ -714,12 +723,7 @@ static ssize_t attr_capdata01_show(struc + u32 attribute_id; + int value, ret; + +- attribute_id = +- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) | +- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) | +- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, +- LWMI_GZ_THERMAL_MODE_CUSTOM) | +- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id); ++ attribute_id = tunable_attr_01_id(tunable_attr, LWMI_GZ_THERMAL_MODE_CUSTOM); + + ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata); + if (ret) +@@ -774,7 +778,6 @@ static ssize_t attr_current_value_store( + struct wmi_method_args_32 args = {}; + struct capdata01 capdata; + enum thermal_mode mode; +- u32 attribute_id; + u32 value; + int ret; + +@@ -785,13 +788,9 @@ static ssize_t attr_current_value_store( + if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM) + return -EBUSY; + +- attribute_id = +- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) | +- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) | +- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) | +- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id); ++ args.arg0 = tunable_attr_01_id(tunable_attr, mode); + +- ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata); ++ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata); + if (ret) + return ret; + +@@ -802,7 +801,6 @@ static ssize_t attr_current_value_store( + if (value < capdata.min_value || value > capdata.max_value) + return -EINVAL; + +- args.arg0 = attribute_id; + args.arg1 = value; + + ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET, +@@ -836,7 +834,6 @@ static ssize_t attr_current_value_show(s + struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev); + struct wmi_method_args_32 args = {}; + enum thermal_mode mode; +- u32 attribute_id; + int retval; + int ret; + +@@ -844,13 +841,7 @@ static ssize_t attr_current_value_show(s + if (ret) + return ret; + +- attribute_id = +- FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) | +- FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) | +- FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) | +- FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id); +- +- args.arg0 = attribute_id; ++ args.arg0 = tunable_attr_01_id(tunable_attr, mode); + + ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, + (unsigned char *)&args, sizeof(args), diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-balance-component-bind-and-unbind.patch b/queue-7.0/platform-x86-lenovo-wmi-other-balance-component-bind-and-unbind.patch new file mode 100644 index 0000000000..29b600883b --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-balance-component-bind-and-unbind.patch @@ -0,0 +1,50 @@ +From 2fe2504abcfa4f82a4208e8d0c21ec0f22baca43 Mon Sep 17 00:00:00 2001 +From: Rong Zhang +Date: Sun, 10 May 2026 04:25:33 +0000 +Subject: platform/x86: lenovo-wmi-other: Balance component bind and unbind +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rong Zhang + +commit 2fe2504abcfa4f82a4208e8d0c21ec0f22baca43 upstream. + +When lwmi_om_master_bind() fails, the master device's components are +left bound, with the aggregate device destroyed due to the failure +(found by sashiko.dev [1]). + +Balance calls to component_bind_all() and component_unbind_all() when an +error is propagated to the component framework. + +No functional change intended. + +Reviewed-by: Mark Pearson +Reviewed-by: Ilpo Järvinen +Fixes: edc4b183b794 ("platform/x86: Add Lenovo Other Mode WMI Driver") +Cc: stable@vger.kernel.org +Link: https://sashiko.dev/#/patchset/20260331181208.421552-1-derekjohn.clark%40gmail.com [1] +Signed-off-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-4-derekjohn.clark@gmail.com +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-other.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -1067,8 +1067,11 @@ static int lwmi_om_master_bind(struct de + + priv->cd00_list = binder.cd00_list; + priv->cd01_list = binder.cd01_list; +- if (!priv->cd00_list || !priv->cd01_list) ++ if (!priv->cd00_list || !priv->cd01_list) { ++ component_unbind_all(dev, NULL); ++ + return -ENODEV; ++ } + + lwmi_om_fan_info_collect_cd00(priv); + diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-balance-ida-id-allocation-and-free.patch b/queue-7.0/platform-x86-lenovo-wmi-other-balance-ida-id-allocation-and-free.patch new file mode 100644 index 0000000000..8ba624554d --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-balance-ida-id-allocation-and-free.patch @@ -0,0 +1,138 @@ +From 55a279ae819adaea99a94c609f31970b70e0ec0c Mon Sep 17 00:00:00 2001 +From: Rong Zhang +Date: Sun, 10 May 2026 04:25:32 +0000 +Subject: platform/x86: lenovo-wmi-other: Balance IDA id allocation and free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rong Zhang + +commit 55a279ae819adaea99a94c609f31970b70e0ec0c upstream. + +Currently, the IDA id is only freed on wmi-other device removal or +failure to create firmware-attributes device, kset, or attributes. It +leaks IDA ids if the wmi-other device is bound multiple times, as the +unbind callback never frees the previously allocated IDA id. +Additionally, if the wmi-other device has failed to create a +firmware-attributes device before it gets removed, the wmi-device +removal callback double frees the same IDA id. + +These bugs were found by sashiko.dev [1]. + +Fix them by moving ida_free() into lwmi_om_fw_attr_remove() so it is +balanced with ida_alloc() in lwmi_om_fw_attr_add(). With them fixed, +properly set and utilize the validity of priv->ida_id to balance +firmware-attributes registration and removal, without relying on +propagating the registration error to the component framework, which is +more reliable and aligns with the hwmon device registration and removal +sequences. + +No functional change intended. + +Reviewed-by: Mark Pearson +Fixes: edc4b183b794 ("platform/x86: Add Lenovo Other Mode WMI Driver") +Cc: stable@vger.kernel.org +Link: https://sashiko.dev/#/patchset/20260331181208.421552-1-derekjohn.clark%40gmail.com [1] +Signed-off-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-3-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-other.c | 36 ++++++++++++++++++-------------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -956,17 +956,17 @@ static struct capdata01_attr_group cd01_ + /** + * lwmi_om_fw_attr_add() - Register all firmware_attributes_class members + * @priv: The Other Mode driver data. +- * +- * Return: Either 0, or an error code. + */ +-static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv) ++static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv) + { + unsigned int i; + int err; + +- priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL); +- if (priv->ida_id < 0) +- return priv->ida_id; ++ err = ida_alloc(&lwmi_om_ida, GFP_KERNEL); ++ if (err < 0) ++ goto err_no_ida; ++ ++ priv->ida_id = err; + + priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL, + MKDEV(0, 0), NULL, "%s-%u", +@@ -992,7 +992,7 @@ static int lwmi_om_fw_attr_add(struct lw + + cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; + } +- return 0; ++ return; + + err_remove_groups: + while (i--) +@@ -1006,7 +1006,12 @@ err_destroy_classdev: + + err_free_ida: + ida_free(&lwmi_om_ida, priv->ida_id); +- return err; ++ ++err_no_ida: ++ priv->ida_id = -EIDRM; ++ ++ dev_warn(&priv->wdev->dev, ++ "failed to register firmware-attributes device: %d\n", err); + } + + /** +@@ -1015,12 +1020,17 @@ err_free_ida: + */ + static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv) + { ++ if (priv->ida_id < 0) ++ return; ++ + for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) + sysfs_remove_group(&priv->fw_attr_kset->kobj, + cd01_attr_groups[i].attr_group); + + kset_unregister(priv->fw_attr_kset); + device_unregister(priv->fw_attr_dev); ++ ida_free(&lwmi_om_ida, priv->ida_id); ++ priv->ida_id = -EIDRM; + } + + /* ======== Self (master: lenovo-wmi-other) ======== */ +@@ -1062,7 +1072,9 @@ static int lwmi_om_master_bind(struct de + + lwmi_om_fan_info_collect_cd00(priv); + +- return lwmi_om_fw_attr_add(priv); ++ lwmi_om_fw_attr_add(priv); ++ ++ return 0; + } + + /** +@@ -1114,13 +1126,7 @@ static int lwmi_other_probe(struct wmi_d + + static void lwmi_other_remove(struct wmi_device *wdev) + { +- struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev); +- + component_master_del(&wdev->dev, &lwmi_om_master_ops); +- +- /* No IDA to free if the driver is never bound to its components. */ +- if (priv->ida_id >= 0) +- ida_free(&lwmi_om_ida, priv->ida_id); + } + + static const struct wmi_device_id lwmi_other_id_table[] = { diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-fix-tunable_attr_01-struct-members.patch b/queue-7.0/platform-x86-lenovo-wmi-other-fix-tunable_attr_01-struct-members.patch new file mode 100644 index 0000000000..42f956718b --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-fix-tunable_attr_01-struct-members.patch @@ -0,0 +1,48 @@ +From 71f3843e0f81e3c097a088c1121154bb9a44da0a Mon Sep 17 00:00:00 2001 +From: "Derek J. Clark" +Date: Sun, 10 May 2026 04:25:35 +0000 +Subject: platform/x86: lenovo-wmi-other: Fix tunable_attr_01 struct members +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Derek J. Clark + +commit 71f3843e0f81e3c097a088c1121154bb9a44da0a upstream. + +In struct tunable_attr_01 the capdata pointer is unused and the size of +the id members is u32 when it should be u8. Fix these prior to adding +additional members. + +No functional change intended. + +Reviewed-by: Mark Pearson +Cc: stable@vger.kernel.org +Reviewed-by: Rong Zhang +Tested-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-6-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-other.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -545,11 +545,10 @@ out: + /* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */ + + struct tunable_attr_01 { +- struct capdata01 *capdata; + struct device *dev; +- u32 feature_id; +- u32 device_id; +- u32 type_id; ++ u8 feature_id; ++ u8 device_id; ++ u8 type_id; + }; + + static struct tunable_attr_01 ppt_pl1_spl = { diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-limit-adding-attributes-to-supported-devices.patch b/queue-7.0/platform-x86-lenovo-wmi-other-limit-adding-attributes-to-supported-devices.patch new file mode 100644 index 0000000000..4973999f25 --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-limit-adding-attributes-to-supported-devices.patch @@ -0,0 +1,196 @@ +From 03bb5147da083cb91e5c8c2599fcb2f8fd05cb8f Mon Sep 17 00:00:00 2001 +From: "Derek J. Clark" +Date: Sun, 10 May 2026 04:25:39 +0000 +Subject: platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Derek J. Clark + +commit 03bb5147da083cb91e5c8c2599fcb2f8fd05cb8f upstream. + +Adds lwmi_is_attr_01_supported, and only creates the attribute subfolder +if the attribute is supported by the hardware. Due to some poorly +implemented BIOS this is a multi-step sequence of events. This is +because: +- Some BIOS support getting the capability data from custom mode (0xff), + while others only support it in no-mode (0x00). +- Some BIOS support get/set for the current value from custom mode (0xff), + while others only support it in no-mode (0x00). +- Some BIOS report capability data for a method that is not fully + implemented. +- Some BIOS have methods fully implemented, but no complimentary + capability data. + +To ensure we only expose fully implemented methods with corresponding +capability data, we check each outcome before reporting that an +attribute can be supported. + +Checking for lwmi_is_attr_01_supported during remove is not done to +ensure that we don't attempt to call cd01 or send WMI events if one of +the interfaces being removed was the cause of the driver unloading. + +Fixes: edc4b183b794 ("platform/x86: Add Lenovo Other Mode WMI Driver") +Reported-by: Kurt Borja +Closes: https://lore.kernel.org/platform-driver-x86/DG60P3SHXR8H.3NSEHMZ6J7XRC@gmail.com/ +Cc: stable@vger.kernel.org +Reviewed-by: Rong Zhang +Tested-by: Rong Zhang +Reviewed-by: Mark Pearson +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-10-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-other.c | 92 ++++++++++++++++++++++++++++++-- + 1 file changed, 88 insertions(+), 4 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -546,6 +546,8 @@ struct tunable_attr_01 { + u8 feature_id; + u8 device_id; + u8 type_id; ++ u8 cd_mode_id; /* mode arg for searching capdata */ ++ u8 cv_mode_id; /* mode arg for set/get current_value */ + }; + + /** +@@ -723,7 +725,7 @@ static ssize_t attr_capdata01_show(struc + u32 attribute_id; + int value, ret; + +- attribute_id = tunable_attr_01_id(tunable_attr, LWMI_GZ_THERMAL_MODE_CUSTOM); ++ attribute_id = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id); + + ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata); + if (ret) +@@ -788,7 +790,7 @@ static ssize_t attr_current_value_store( + if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM) + return -EBUSY; + +- args.arg0 = tunable_attr_01_id(tunable_attr, mode); ++ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id); + + ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata); + if (ret) +@@ -801,6 +803,7 @@ static ssize_t attr_current_value_store( + if (value < capdata.min_value || value > capdata.max_value) + return -EINVAL; + ++ args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cv_mode_id); + args.arg1 = value; + + ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET, +@@ -841,6 +844,10 @@ static ssize_t attr_current_value_show(s + if (ret) + return ret; + ++ /* If "no-mode" is the supported mode, ensure we never send current mode */ ++ if (tunable_attr->cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE) ++ mode = tunable_attr->cv_mode_id; ++ + args.arg0 = tunable_attr_01_id(tunable_attr, mode); + + ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, +@@ -852,6 +859,81 @@ static ssize_t attr_current_value_show(s + return sysfs_emit(buf, "%d\n", retval); + } + ++/** ++ * lwmi_attr_01_is_supported() - Determine if the given attribute is supported. ++ * @tunable_attr: The attribute to verify. ++ * ++ * For an attribute to be supported it must have a functional get/set method, ++ * as well as associated capability data stored in the capdata01 table. ++ * ++ * First check if the attribute has a corresponding data table under custom mode ++ * (0xff), then under no mode (0x00). If either of those passes, check if the ++ * supported field of the capdata struct is > 0. If it is supported, store the ++ * successful mode in the cd_mode_id field of tunable_attr. ++ * ++ * If the attribute capdata shows it is supported, attempt to determine the mode ++ * for the current value property get/set methods using a similar pattern to the ++ * capdata table check. If the value returned by either mode is 0 or an error, ++ * assume that mode is not supported. Otherwise, store the successful mode in the ++ * cv_mode_id field of tunable_attr. ++ * ++ * If any of the above checks fail then the attribute is not fully supported. ++ * ++ * Return: true if capdata and set/get modes are found, otherwise false. ++ */ ++static bool lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr) ++{ ++ u8 modes[2] = { LWMI_GZ_THERMAL_MODE_CUSTOM, LWMI_GZ_THERMAL_MODE_NONE }; ++ struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev); ++ struct wmi_method_args_32 args = {}; ++ bool cd_mode_found = false; ++ bool cv_mode_found = false; ++ struct capdata01 capdata; ++ int retval, ret, i; ++ ++ /* Determine tunable_attr->cd_mode_id */ ++ for (i = 0; i < ARRAY_SIZE(modes); i++) { ++ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]); ++ ++ ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata); ++ if (ret || !capdata.supported) ++ continue; ++ ++ tunable_attr->cd_mode_id = modes[i]; ++ cd_mode_found = true; ++ break; ++ } ++ ++ if (!cd_mode_found) ++ return cd_mode_found; ++ ++ dev_dbg(tunable_attr->dev, ++ "cd_mode_id: %#010x\n", args.arg0); ++ ++ /* Determine tunable_attr->cv_mode_id, returns 1 if supported */ ++ for (i = 0; i < ARRAY_SIZE(modes); i++) { ++ args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]); ++ ++ ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, ++ (u8 *)&args, sizeof(args), ++ &retval); ++ if (ret || !retval) ++ continue; ++ ++ tunable_attr->cv_mode_id = modes[i]; ++ cv_mode_found = true; ++ break; ++ } ++ ++ if (!cv_mode_found) ++ return cv_mode_found; ++ ++ dev_dbg(tunable_attr->dev, "cv_mode_id: %#010x, attribute support level: %#010x\n", ++ args.arg0, capdata.supported); ++ ++ return capdata.supported > 0; ++} ++ + /* Lenovo WMI Other Mode Attribute macros */ + #define __LWMI_ATTR_RO(_func, _name) \ + { \ +@@ -975,12 +1057,14 @@ static void lwmi_om_fw_attr_add(struct l + } + + for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) { ++ cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; ++ if (!lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr)) ++ continue; ++ + err = sysfs_create_group(&priv->fw_attr_kset->kobj, + cd01_attr_groups[i].attr_group); + if (err) + goto err_remove_groups; +- +- cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; + } + return; + diff --git a/queue-7.0/platform-x86-lenovo-wmi-other-zero-initialize-wmi-arguments.patch b/queue-7.0/platform-x86-lenovo-wmi-other-zero-initialize-wmi-arguments.patch new file mode 100644 index 0000000000..80d28713f3 --- /dev/null +++ b/queue-7.0/platform-x86-lenovo-wmi-other-zero-initialize-wmi-arguments.patch @@ -0,0 +1,76 @@ +From 816fbd5dacee977ca56bab79bf97f71f2f7ac24e Mon Sep 17 00:00:00 2001 +From: "Derek J. Clark" +Date: Sun, 10 May 2026 04:25:34 +0000 +Subject: platform/x86: lenovo-wmi-other: Zero initialize WMI arguments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Derek J. Clark + +commit 816fbd5dacee977ca56bab79bf97f71f2f7ac24e upstream. + +Adds explicit initialization of wmi_method_args_32 declarations with +zero values to prevent uninitialized data from being sent to the device +BIOS when passed. + +No functional change intended. + +Reviewed-by: Mark Pearson +Fixes: 22024ac5366f ("platform/x86: Add Lenovo Gamezone WMI Driver") +Fixes: edc4b183b794 ("platform/x86: Add Lenovo Other Mode WMI Driver") +Reported-by: Rong Zhang +Closes: https://lore.kernel.org/platform-driver-x86/95c7e7b539dd0af41189c754fcd35cec5b6fe182.camel@rong.moe/ +Cc: stable@vger.kernel.org +Reviewed-by: Rong Zhang +Tested-by: Rong Zhang +Signed-off-by: Derek J. Clark +Link: https://patch.msgid.link/20260510042546.436874-5-derekjohn.clark@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/lenovo/wmi-gamezone.c | 2 +- + drivers/platform/x86/lenovo/wmi-other.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/platform/x86/lenovo/wmi-gamezone.c ++++ b/drivers/platform/x86/lenovo/wmi-gamezone.c +@@ -200,7 +200,7 @@ static int lwmi_gz_profile_set(struct de + enum platform_profile_option profile) + { + struct lwmi_gz_priv *priv = dev_get_drvdata(dev); +- struct wmi_method_args_32 args; ++ struct wmi_method_args_32 args = {}; + enum thermal_mode mode; + int ret; + +--- a/drivers/platform/x86/lenovo/wmi-other.c ++++ b/drivers/platform/x86/lenovo/wmi-other.c +@@ -165,7 +165,7 @@ MODULE_PARM_DESC(relax_fan_constraint, + */ + static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set) + { +- struct wmi_method_args_32 args; ++ struct wmi_method_args_32 args = {}; + u32 method_id, retval; + int err; + +@@ -772,7 +772,7 @@ static ssize_t attr_current_value_store( + struct tunable_attr_01 *tunable_attr) + { + struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev); +- struct wmi_method_args_32 args; ++ struct wmi_method_args_32 args = {}; + struct capdata01 capdata; + enum thermal_mode mode; + u32 attribute_id; +@@ -835,7 +835,7 @@ static ssize_t attr_current_value_show(s + struct tunable_attr_01 *tunable_attr) + { + struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev); +- struct wmi_method_args_32 args; ++ struct wmi_method_args_32 args = {}; + enum thermal_mode mode; + u32 attribute_id; + int retval; diff --git a/queue-7.0/powerpc-warp-fix-error-handling-in-pika_dtm_thread.patch b/queue-7.0/powerpc-warp-fix-error-handling-in-pika_dtm_thread.patch new file mode 100644 index 0000000000..a46dda1334 --- /dev/null +++ b/queue-7.0/powerpc-warp-fix-error-handling-in-pika_dtm_thread.patch @@ -0,0 +1,39 @@ +From 108d7f951271cbd36ca36efc5e5d106966f5180c Mon Sep 17 00:00:00 2001 +From: Ma Ke +Date: Sun, 16 Nov 2025 10:44:11 +0800 +Subject: powerpc/warp: Fix error handling in pika_dtm_thread + +From: Ma Ke + +commit 108d7f951271cbd36ca36efc5e5d106966f5180c upstream. + +pika_dtm_thread() acquires client through of_find_i2c_device_by_node() +but fails to release it in error handling path. This could result in a +reference count leak, preventing proper cleanup and potentially +leading to resource exhaustion. Add put_device() to release the +reference in the error handling path. + +Found by code review. + +Cc: stable@vger.kernel.org +Fixes: 3984114f0562 ("powerpc/warp: Platform fix for i2c change") +Signed-off-by: Ma Ke +Reviewed-by: Christophe Leroy +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251116024411.21968-1-make24@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/44x/warp.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/powerpc/platforms/44x/warp.c ++++ b/arch/powerpc/platforms/44x/warp.c +@@ -293,6 +293,8 @@ static int pika_dtm_thread(void __iomem + schedule_timeout(HZ); + } + ++ put_device(&client->dev); ++ + return 0; + } + diff --git a/queue-7.0/riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch b/queue-7.0/riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch new file mode 100644 index 0000000000..e712c38226 --- /dev/null +++ b/queue-7.0/riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch @@ -0,0 +1,83 @@ +From b69bcb13ed7024a84d6cd8ad330f1e32782fcf28 Mon Sep 17 00:00:00 2001 +From: Vivian Wang +Date: Wed, 1 Apr 2026 09:53:17 +0800 +Subject: riscv: misaligned: Make enabling delegation depend on NONPORTABLE + +From: Vivian Wang + +commit b69bcb13ed7024a84d6cd8ad330f1e32782fcf28 upstream. + +The unaligned access emulation code in Linux has various deficiencies. +For example, it doesn't emulate vector instructions [1] [2], and doesn't +emulate KVM guest accesses. Therefore, requesting misaligned exception +delegation with SBI FWFT actually regresses vector instructions' and KVM +guests' behavior. + +Until Linux can handle it properly, guard these sbi_fwft_set() calls +behind RISCV_SBI_FWFT_DELEGATE_MISALIGNED, which in turn depends on +NONPORTABLE. Those who are sure that this wouldn't be a problem can +enable this option, perhaps getting better performance. + +The rest of the existing code proceeds as before, except as if +SBI_FWFT_MISALIGNED_EXC_DELEG is not available, to handle any remaining +address misaligned exceptions on a best-effort basis. The KVM SBI FWFT +implementation is also not touched, but it is disabled if the firmware +emulates unaligned accesses. + +Cc: stable@vger.kernel.org +Fixes: cf5a8abc6560 ("riscv: misaligned: request misaligned exception from SBI") +Reported-by: Songsong Zhang # KVM +Link: https://lore.kernel.org/linux-riscv/38ce44c1-08cf-4e3f-8ade-20da224f529c@iscas.ac.cn/ [1] +Link: https://lore.kernel.org/linux-riscv/b3cfcdac-0337-4db0-a611-258f2868855f@iscas.ac.cn/ [2] +Signed-off-by: Vivian Wang +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260401-riscv-misaligned-dont-delegate-v2-1-5014a288c097@iscas.ac.cn +Signed-off-by: Paul Walmsley +Signed-off-by: Greg Kroah-Hartman +--- + arch/riscv/Kconfig | 22 ++++++++++++++++++++++ + arch/riscv/kernel/traps_misaligned.c | 2 +- + 2 files changed, 23 insertions(+), 1 deletion(-) + +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -941,6 +941,28 @@ config RISCV_VECTOR_MISALIGNED + help + Enable detecting support for vector misaligned loads and stores. + ++config RISCV_SBI_FWFT_DELEGATE_MISALIGNED ++ bool "Request firmware delegation of unaligned access exceptions" ++ depends on RISCV_SBI ++ depends on NONPORTABLE ++ help ++ Use SBI FWFT to request delegation of load address misaligned and ++ store address misaligned exceptions, if possible, and prefer Linux ++ kernel emulation of these accesses to firmware emulation. ++ ++ Unfortunately, Linux's emulation is still incomplete. Namely, it ++ currently does not handle vector instructions and KVM guest accesses. ++ On platforms where these accesses would have been handled by firmware, ++ enabling this causes unexpected kernel oopses, userspaces crashes and ++ KVM guest crashes. If you are sure that these are not a problem for ++ your platform, you can say Y here, which may improve performance. ++ ++ Saying N here will not worsen emulation support for unaligned accesses ++ even in the case where the firmware also has incomplete support. It ++ simply keeps the firmware's emulation enabled. ++ ++ If you don't know what to do here, say N. ++ + choice + prompt "Unaligned Accesses Support" + default RISCV_PROBE_UNALIGNED_ACCESS +--- a/arch/riscv/kernel/traps_misaligned.c ++++ b/arch/riscv/kernel/traps_misaligned.c +@@ -584,7 +584,7 @@ static int cpu_online_check_unaligned_ac + + static bool misaligned_traps_delegated; + +-#ifdef CONFIG_RISCV_SBI ++#if defined(CONFIG_RISCV_SBI_FWFT_DELEGATE_MISALIGNED) + + static int cpu_online_sbi_unaligned_setup(unsigned int cpu) + { diff --git a/queue-7.0/series b/queue-7.0/series index c66d03568c..6d98396fba 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -1067,3 +1067,67 @@ hid-core-fix-size_t-specifier-in-hid_report_raw_even.patch ata-libata-scsi-fix-requeue-of-deferred-ata-pass-thr.patch media-staging-imx-configure-src_mux-in-csi_start.patch bluetooth-btmtk-accept-too-short-wmt-func_ctrl-events.patch +nvme-apple-reset-q-sq_tail-during-queue-init.patch +smb-client-fix-possible-infinite-loop-and-oob-read-in-symlink_data.patch +drm-loongson-use-managed-kms-polling.patch +drm-replace-old-pointer-to-new-idr.patch +drm-bridge-imx8qxp-pxl2dpi-avoid-err_ptr-with-device_node-cleanup.patch +drm-i915-dp-fix-vsc-dynamic-range-signaling-for-rgb-formats.patch +drm-amd-display-wrap-dcn32-phantom-plane-allocation-in-dc_run_with_preemption_enabled.patch +drm-ttm-fix-ttm_bo_swapout-infinite-lru-walk-on-swapout-failure.patch +platform-x86-intel-move-debugfs-register-before-creating-devices.patch +platform-x86-lenovo-wmi-helpers-move-gamezone-enums-to-wmi-helpers.patch +platform-x86-lenovo-wmi-helpers-fix-memory-leak-in-lwmi_dev_evaluate_int.patch +platform-x86-lenovo-wmi-other-balance-ida-id-allocation-and-free.patch +platform-x86-lenovo-wmi-other-balance-component-bind-and-unbind.patch +platform-x86-lenovo-wmi-other-zero-initialize-wmi-arguments.patch +platform-x86-lenovo-wmi-other-fix-tunable_attr_01-struct-members.patch +platform-x86-lenovo-wmi-other-add-attribute-id-helper-functions.patch +platform-x86-lenovo-wmi-other-limit-adding-attributes-to-supported-devices.patch +accel-rocket-fix-prep_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch +alsa-hda-realtek-add-mute-led-quirk-for-hp-pavilion-laptop-16-ag0xxx.patch +alsa-hda-realtek-add-quirk-for-samsung-galaxy-book5-360-headphone.patch +alsa-usb-audio-bound-midi-2.0-endpoint-descriptor-scans.patch +alsa-usb-audio-bound-midi-endpoint-descriptor-scans.patch +alsa-usb-audio-qcom-check-offload-mapping-failures.patch +btrfs-only-release-the-dirty-pages-io-tree-after-successful-writes.patch +ceph-fix-a-buffer-leak-in-__ceph_setxattr.patch +ceph-fix-bug_on-in-__ceph_build_xattrs_blob-due-to-stale-blob-size.patch +ceph-put-folios-not-suitable-for-writeback.patch +io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch +iommu-amd-bounds-check-devid-in-__rlookup_amd_iommu.patch +x86-kexec-push-kjump-return-address-even-for-non-kjump-kexec.patch +xfs-fix-memory-leak-on-error-in-xfs_alloc_zone_info.patch +virt-sev-guest-do-not-use-host-controlled-page-order-in-cleanup-path.patch +riscv-misaligned-make-enabling-delegation-depend-on-nonportable.patch +powerpc-warp-fix-error-handling-in-pika_dtm_thread.patch +netfs-fix-error-handling-in-netfs_extract_user_iter.patch +nfsd-fix-get_dir_delegation-when-vfs-leases-are-disabled.patch +nfsd-fix-file-change-detection-in-cb_getattr.patch +nfsd-update-mtime-ctime-on-clone-in-presense-of-delegated-attributes.patch +nfsd-update-mtime-ctime-on-copy-in-presence-of-delegated-attributes.patch +irqchip-riscv-imsic-clear-interrupt-move-state-during-cpu-offlining.patch +irqchip-meson-gpio-use-the-correct-register-in-meson_s4_gpio_irq_set_type.patch +irqchip-gic-v5-move-lpi-allocation-into-the-lpi-domain.patch +irqchip-gic-v5-support-range-allocation-for-lpis.patch +irqchip-gic-v5-allocate-its-parent-lpis-as-a-range.patch +libceph-fix-potential-out-of-bounds-access-in-osdmap_decode.patch +libceph-fix-potential-null-ptr-deref-in-decode_choose_args.patch +libceph-fix-potential-out-of-bounds-access-in-__ceph_x_decrypt.patch +libceph-fix-potential-out-of-bounds-access-in-crush_decode.patch +libceph-handle-rbtree-insertion-error-in-decode_choose_args.patch +iommu-vt-d-disable-dmar-for-intel-q35-igfx.patch +iommu-vt-d-fix-oops-due-to-out-of-scope-access.patch +iommu-vt-d-avoid-null-pointer-dereference-or-refcount-corruption.patch +iommu-fix-null-group-domain-dereference-in-pci_dev_reset_iommu_done.patch +iommu-replace-per-group-resetting_domain-with-per-gdev-blocked-flag.patch +iommu-fix-warn_on-in-__iommu_group_set_domain_nofail-due-to-reset.patch +iommu-fix-pasid-attach-in-pci_dev_reset_iommu_prepare-done.patch +iommu-fix-nested-pci_dev_reset_iommu_prepare-done.patch +iommu-fix-ats-invalidation-timeouts-during-__iommu_remove_group_pasid.patch +drm-i915-skip-__i915_request_skip-for-already-signaled-requests.patch +drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeout.patch +drm-xe-dma-buf-handle-empty-bo-and-uaf-races.patch +drm-xe-dma-buf-fix-uaf-with-retry-loop.patch +drm-ttm-fix-ttm_bo_shrink-infinite-lru-walk-on-backup-failure.patch +drm-ttm-convert-eagain-from-dmem_cgroup_try_charge-to-enospc.patch diff --git a/queue-7.0/smb-client-fix-possible-infinite-loop-and-oob-read-in-symlink_data.patch b/queue-7.0/smb-client-fix-possible-infinite-loop-and-oob-read-in-symlink_data.patch new file mode 100644 index 0000000000..0d5bc4b561 --- /dev/null +++ b/queue-7.0/smb-client-fix-possible-infinite-loop-and-oob-read-in-symlink_data.patch @@ -0,0 +1,44 @@ +From 7d9a7f1f96cd617ee9e75bb22217c709038e26b8 Mon Sep 17 00:00:00 2001 +From: Ye Bin +Date: Thu, 14 May 2026 21:14:18 +0800 +Subject: smb/client: fix possible infinite loop and oob read in symlink_data() + +From: Ye Bin + +commit 7d9a7f1f96cd617ee9e75bb22217c709038e26b8 upstream. + +On 32-bit architectures, the infinite loop is as follows: + + len = p->ErrorDataLength == 0xfffffff8 + u8 *next = p->ErrorContextData + len + next == p + +On 32-bit architectures, the out-of-bounds read is as follows: + + len = p->ErrorDataLength == 0xfffffff0 + u8 *next = p->ErrorContextData + len + next == (u8 *)p - 8 + +Reported-by: ChenXiaoSong +Fixes: 76894f3e2f71 ("cifs: improve symlink handling for smb2+") +Cc: stable@vger.kernel.org +Signed-off-by: Ye Bin +Reviewed-by: ChenXiaoSong +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2file.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -49,6 +49,9 @@ static struct smb2_symlink_err_rsp *syml + __func__, le32_to_cpu(p->ErrorId)); + + len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8); ++ if (len > end - ((u8 *)p + sizeof(*p))) ++ return ERR_PTR(-EINVAL); ++ + p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len); + } + } else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) && diff --git a/queue-7.0/virt-sev-guest-do-not-use-host-controlled-page-order-in-cleanup-path.patch b/queue-7.0/virt-sev-guest-do-not-use-host-controlled-page-order-in-cleanup-path.patch new file mode 100644 index 0000000000..f00d6a5233 --- /dev/null +++ b/queue-7.0/virt-sev-guest-do-not-use-host-controlled-page-order-in-cleanup-path.patch @@ -0,0 +1,80 @@ +From 23e6a1ca04ae44806439a5a446e62e4d42e80bb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20L=C3=B3pez?= +Date: Tue, 12 May 2026 12:00:41 +0200 +Subject: virt: sev-guest: Do not use host-controlled page order in cleanup path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Carlos López + +commit 23e6a1ca04ae44806439a5a446e62e4d42e80bb4 upstream. + +When issuing an extended guest request (SVM_VMGEXIT_EXT_GUEST_REQUEST), +get_ext_report() allocates a buffer to retrieve a certificate blob from the +host, keeping track of its size in report_req->certs_len. + +However, the host may return SNP_GUEST_VMM_ERR_INVALID_LEN, indicating +an invalid buffer size, as well as the expected length of such buffer. +get_ext_report() subsequently updates report_req->certs_len with the +host-controlled value, and cleans up the buffer by computing a page order +from such value. This is incorrect, as the host-provided length may not +match the page order of the original allocation, potentially resulting +in corruption in the page allocator. + +Fix this by using alloc_pages_exact() instead, and reusing @npages to +compute the size passed to free_pages_exact(). For consistency, also +use @npages to compute the size when allocating the pages, even though +this last change has no functional effect. + +Fixes: 3e385c0d6ce8 ("virt: sev-guest: Move SNP Guest Request data pages handling under snp_cmd_mutex") +Signed-off-by: Carlos López +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Michael Roth +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + drivers/virt/coco/sev-guest/sev-guest.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/virt/coco/sev-guest/sev-guest.c ++++ b/drivers/virt/coco/sev-guest/sev-guest.c +@@ -176,7 +176,6 @@ static int get_ext_report(struct snp_gue + struct snp_guest_req req = {}; + int ret, npages = 0, resp_len; + sockptr_t certs_address; +- struct page *page; + + if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data)) + return -EINVAL; +@@ -211,16 +210,15 @@ static int get_ext_report(struct snp_gue + * zeros to indicate that certificate data was not provided. + */ + npages = report_req->certs_len >> PAGE_SHIFT; +- page = alloc_pages(GFP_KERNEL_ACCOUNT | __GFP_ZERO, +- get_order(report_req->certs_len)); +- if (!page) ++ req.certs_data = alloc_pages_exact(npages << PAGE_SHIFT, ++ GFP_KERNEL_ACCOUNT | __GFP_ZERO); ++ if (!req.certs_data) + return -ENOMEM; + +- req.certs_data = page_address(page); + ret = set_memory_decrypted((unsigned long)req.certs_data, npages); + if (ret) { + pr_err("failed to mark page shared, ret=%d\n", ret); +- __free_pages(page, get_order(report_req->certs_len)); ++ free_pages_exact(req.certs_data, npages << PAGE_SHIFT); + return -EFAULT; + } + +@@ -277,7 +275,7 @@ e_free_data: + if (set_memory_encrypted((unsigned long)req.certs_data, npages)) + WARN_ONCE(ret, "failed to restore encryption mask (leak it)\n"); + else +- __free_pages(page, get_order(report_req->certs_len)); ++ free_pages_exact(req.certs_data, npages << PAGE_SHIFT); + } + return ret; + } diff --git a/queue-7.0/x86-kexec-push-kjump-return-address-even-for-non-kjump-kexec.patch b/queue-7.0/x86-kexec-push-kjump-return-address-even-for-non-kjump-kexec.patch new file mode 100644 index 0000000000..8b1bde4cad --- /dev/null +++ b/queue-7.0/x86-kexec-push-kjump-return-address-even-for-non-kjump-kexec.patch @@ -0,0 +1,52 @@ +From 786a45757dcdf8f2beb9d4a6db605db16c18b2b4 Mon Sep 17 00:00:00 2001 +From: David Woodhouse +Date: Tue, 28 Apr 2026 21:59:52 +0100 +Subject: x86/kexec: Push kjump return address even for non-kjump kexec + +From: David Woodhouse + +commit 786a45757dcdf8f2beb9d4a6db605db16c18b2b4 upstream. + +The version of purgatory code shipped by kexec-tools attempts to look above +the top of its stack to find a return address for a kjump, even in a non-kjump +kexec. + +After the commit in Fixes: the word above the stack might not be there, +leading to a fault (which is at least now caught by my exception-handling code +in kexec). + +That commit fixed things for the actual kjump path, but no longer +"gratuitously" pushes the unused return address to the stack in the non-kjump +path. Put that *back* in the non-kjump path, to prevent purgatory from +crashing when trying to access it. + +Fixes: 2cacf7f23a02 ("x86/kexec: Fix stack and handling of re-entry point for ::preserve_context") +Reported-by: Rohan Kakulawaram +Signed-off-by: David Woodhouse +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Dave Hansen +Tested-by: Rohan Kakulawaram +Cc: +Link: https://patch.msgid.link/32d627134143ffd957891cb697138e839c623211.camel@infradead.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/relocate_kernel_64.S | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/x86/kernel/relocate_kernel_64.S ++++ b/arch/x86/kernel/relocate_kernel_64.S +@@ -136,6 +136,14 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_ma + * %r13 original CR4 when relocate_kernel() was invoked + */ + ++ /* ++ * Set return address to 0 if not preserving context. The purgatory ++ * shipped in kexec-tools will unconditionally look for the return ++ * address on the stack and set a kexec_jump_back_entry= command ++ * line option if it's non-zero. There's no other way that it can ++ * tell a preserve-context (kjump) kexec from a normal one. ++ */ ++ pushq $0 + /* store the start address on the stack */ + pushq %rdx + diff --git a/queue-7.0/xfs-fix-memory-leak-on-error-in-xfs_alloc_zone_info.patch b/queue-7.0/xfs-fix-memory-leak-on-error-in-xfs_alloc_zone_info.patch new file mode 100644 index 0000000000..0e3595197d --- /dev/null +++ b/queue-7.0/xfs-fix-memory-leak-on-error-in-xfs_alloc_zone_info.patch @@ -0,0 +1,39 @@ +From 592975da8c3ca87b043077e6eafa37665eae7936 Mon Sep 17 00:00:00 2001 +From: Wilfred Mallawa +Date: Wed, 15 Apr 2026 09:45:14 +1000 +Subject: xfs: fix memory leak on error in xfs_alloc_zone_info() + +From: Wilfred Mallawa + +commit 592975da8c3ca87b043077e6eafa37665eae7936 upstream. + +Currently, the 0th index of the zi_used_bucket_bitmap array is not freed +on error due to the pre-decrement then evaluate semantic of the while +loop used in xfs_alloc_zone_info(). Fix it by allowing for the i == 0 +case to be covered. + +Fixes: 080d01c41d44 ("xfs: implement zoned garbage collection") +Cc: stable@vger.kernel.org # v6.15 +Reviewed-by: Damien Le Moal +Reviewed-by: Carlos Maiolino +Signed-off-by: Wilfred Mallawa +Reviewed-by: Hans Holmberg +Reviewed-by: Christoph Hellwig +Reviewed-by: Darrick J. Wong +Signed-off-by: Carlos Maiolino +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_zone_alloc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/xfs/xfs_zone_alloc.c ++++ b/fs/xfs/xfs_zone_alloc.c +@@ -1214,7 +1214,7 @@ xfs_alloc_zone_info( + return zi; + + out_free_bitmaps: +- while (--i > 0) ++ while (--i >= 0) + kvfree(zi->zi_used_bucket_bitmap[i]); + kfree(zi); + return NULL;