From: Greg Kroah-Hartman Date: Thu, 8 Jan 2026 13:24:49 +0000 (+0100) Subject: 6.1-stable patches X-Git-Tag: v6.1.160~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62137680a8a3b3ea153ac1e403d6a225fde57401;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: alsa-hda-cs35l41-fix-null-pointer-dereference-in-cs35l41_hda_read_acpi.patch alsa-wavefront-clear-substream-pointers-on-close.patch alsa-wavefront-fix-integer-overflow-in-sample-size-validation.patch alsa-wavefront-use-guard-for-spin-locks.patch alsa-wavefront-use-standard-print-api.patch arm-dts-microchip-sama5d2-fix-spi-flexcom-fifo-size-to-32.patch arm-dts-microchip-sama7g5-fix-uart-fifo-size-to-32.patch arm64-dts-ti-k3-j721e-sk-fix-pinmux-for-pin-y1-used-by-power-regulator.patch asoc-stm-stm32_sai_sub-convert-to-platform-remove-callback-returning-void.patch asoc-stm32-sai-fix-clk-prepare-imbalance-on-probe-failure.patch asoc-stm32-sai-fix-of-node-leak-on-probe.patch asoc-stm32-sai-use-the-devm_clk_get_optional-helper.patch btrfs-don-t-log-conflicting-inode-if-it-s-a-dir-moved-in-the-current-transaction.patch btrfs-don-t-rewrite-ret-from-inode_permission.patch can-gs_usb-gs_can_open-fix-error-handling.patch crypto-af_alg-zero-initialize-memory-allocated-via-sock_kmalloc.patch drm-amdgpu-add-missing-lock-to-amdgpu_ttm_access_memory_sdma.patch drm-amdgpu-cleanup-scheduler-job-initialization-v2.patch drm-gma500-remove-unused-helper-psb_fbdev_fb_setcolreg.patch drm-mediatek-fix-probe-memory-leak.patch ext4-fix-string-copying-in-parse_apply_sb_mount_options.patch f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch f2fs-fix-to-avoid-updating-zero-sized-extent-in-extent-cache.patch f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch f2fs-keep-posix_fadv_noreuse-ranges.patch f2fs-remove-unused-gc_failure_pin.patch f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch fscache-delete-fscache_cookie_lru_timer-when-fscache-exits-to-avoid-uaf.patch fuse-fix-readahead-reclaim-deadlock.patch gfs2-fix-freeze-error-handling.patch iommu-arm-smmu-convert-to-platform-remove-callback-returning-void.patch iommu-arm-smmu-drop-if-with-an-always-false-condition.patch iommu-mediatek-fix-use-after-free-on-probe-deferral.patch iommu-mediatek-improve-safety-for-mediatek-smi-property-in-larb-nodes.patch iommu-mediatek-v1-fix-device-leaks-on-probe.patch iommu-mtk_iommu_v1-convert-to-platform-remove-callback-returning-void.patch iommu-qcom-fix-device-leak-on-of_xlate.patch iommu-qcom-index-contexts-by-asid-number-to-allow-asid-0.patch iommu-qcom-use-the-asid-read-from-device-tree-if-specified.patch jbd2-fix-the-inconsistency-between-checksum-and-data-in-memory-for-journal-sb.patch kbuild-use-crc32-and-a-1mib-dictionary-for-xz-compressed-modules.patch ksmbd-fix-out-of-bounds-in-parse_sec_desc.patch kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch kvm-svm-don-t-skip-unrelated-instruction-if-int3-into-is-replaced.patch kvm-x86-mmu-use-emultype-flag-to-track-write-pfs-to-shadow-pages.patch lockd-fix-vfs_test_lock-calls.patch media-amphion-add-a-frame-flush-mode-for-decoder.patch media-amphion-make-some-vpu_v4l2-functions-static.patch media-amphion-remove-vpu_vb_is_codecconfig.patch media-mediatek-vcodec-fix-a-reference-leak-in-mtk_vcodec_fw_vpu_init.patch media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch mm-consider-non-anon-swap-cache-folios-in-folio_expected_ref_count.patch mm-simplify-folio_expected_ref_count.patch mptcp-avoid-deadlock-on-fallback-while-reinjecting.patch mptcp-fallback-earlier-on-simult-connection.patch mptcp-initialise-rcv_mss-before-calling-tcp_send_active_reset-in-mptcp_do_fastclose.patch mptcp-pm-ignore-unknown-endpoint-flags.patch net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch nfsd-clear-seclabel-in-the-suppattr_exclcreat-bitmap.patch nfsd-nfsv4-file-creation-neglects-setting-acl.patch page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch pci-brcmstb-fix-disabling-l0s-capability.patch pmdomain-imx-fix-reference-count-leak-in-imx_gpc_probe.patch pmdomain-use-device_get_match_data.patch powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch scsi-ufs-core-add-ufshcd_update_evt_hist-for-ufs-suspend-error.patch serial-make-uart_remove_one_port-return-void.patch sunrpc-svcauth_gss-avoid-null-deref-on-zero-length-gss_token-in-gss_read_proxy_verf.patch tty-introduce-and-use-tty_port_tty_vhangup-helper.patch usb-dwc3-keep-susphy-enabled-during-exit-to-avoid-controller-faults.patch usb-ohci-nxp-fix-device-leak-on-probe-failure.patch usb-ohci-nxp-use-helper-function-devm_clk_get_enabled.patch virtio_console-fix-order-of-fields-cols-and-rows.patch wifi-mac80211-discard-beacon-frames-to-non-broadcast-address.patch wifi-mt76-fix-dts-power-limits-on-little-endian-systems.patch xhci-dbgtty-fix-device-unregister-fixup.patch --- diff --git a/queue-6.1/alsa-hda-cs35l41-fix-null-pointer-dereference-in-cs35l41_hda_read_acpi.patch b/queue-6.1/alsa-hda-cs35l41-fix-null-pointer-dereference-in-cs35l41_hda_read_acpi.patch new file mode 100644 index 0000000000..7e58397b3f --- /dev/null +++ b/queue-6.1/alsa-hda-cs35l41-fix-null-pointer-dereference-in-cs35l41_hda_read_acpi.patch @@ -0,0 +1,42 @@ +From stable+bounces-201733-greg=kroah.com@vger.kernel.org Tue Dec 16 13:05:52 2025 +From: Sasha Levin +Date: Tue, 16 Dec 2025 06:46:35 -0500 +Subject: ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_hda_read_acpi() +To: stable@vger.kernel.org +Cc: Denis Arefev , Richard Fitzgerald , Takashi Iwai , Sasha Levin +Message-ID: <20251216114635.2768427-1-sashal@kernel.org> + +From: Denis Arefev + +[ Upstream commit c34b04cc6178f33c08331568c7fd25c5b9a39f66 ] + +The acpi_get_first_physical_node() function can return NULL, in which +case the get_device() function also returns NULL, but this value is +then dereferenced without checking,so add a check to prevent a crash. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 7b2f3eb492da ("ALSA: hda: cs35l41: Add support for CS35L41 in HDA systems") +Cc: stable@vger.kernel.org +Signed-off-by: Denis Arefev +Reviewed-by: Richard Fitzgerald +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20251202101338.11437-1-arefev@swemel.ru +[ NULL check right after acpi_dev_put(adev) cleanup call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/pci/hda/cs35l41_hda.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -1278,6 +1278,8 @@ static int cs35l41_hda_read_acpi(struct + + physdev = get_device(acpi_get_first_physical_node(adev)); + acpi_dev_put(adev); ++ if (!physdev) ++ return -ENODEV; + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) diff --git a/queue-6.1/alsa-wavefront-clear-substream-pointers-on-close.patch b/queue-6.1/alsa-wavefront-clear-substream-pointers-on-close.patch new file mode 100644 index 0000000000..9bce1cde12 --- /dev/null +++ b/queue-6.1/alsa-wavefront-clear-substream-pointers-on-close.patch @@ -0,0 +1,47 @@ +From stable+bounces-201341-greg=kroah.com@vger.kernel.org Tue Dec 16 12:29:40 2025 +From: Sasha Levin +Date: Tue, 16 Dec 2025 06:24:47 -0500 +Subject: ALSA: wavefront: Clear substream pointers on close +To: stable@vger.kernel.org +Cc: Junrui Luo , Yuhao Jiang , Takashi Iwai , Sasha Levin +Message-ID: <20251216112447.2760018-2-sashal@kernel.org> + +From: Junrui Luo + +[ Upstream commit e11c5c13ce0ab2325d38fe63500be1dd88b81e38 ] + +Clear substream pointers in close functions to avoid leaving dangling +pointers, helping to improve code safety and +prevents potential issues. + +Reported-by: Yuhao Jiang +Reported-by: Junrui Luo +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881DF762CAB45EE42F6D812AFC2A@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/isa/wavefront/wavefront_midi.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/isa/wavefront/wavefront_midi.c ++++ b/sound/isa/wavefront/wavefront_midi.c +@@ -278,6 +278,7 @@ static int snd_wavefront_midi_input_clos + return -EIO; + + guard(spinlock_irqsave)(&midi->open); ++ midi->substream_input[mpu] = NULL; + midi->mode[mpu] &= ~MPU401_MODE_INPUT; + + return 0; +@@ -300,6 +301,7 @@ static int snd_wavefront_midi_output_clo + return -EIO; + + guard(spinlock_irqsave)(&midi->open); ++ midi->substream_output[mpu] = NULL; + midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; + return 0; + } diff --git a/queue-6.1/alsa-wavefront-fix-integer-overflow-in-sample-size-validation.patch b/queue-6.1/alsa-wavefront-fix-integer-overflow-in-sample-size-validation.patch new file mode 100644 index 0000000000..6e21b529cb --- /dev/null +++ b/queue-6.1/alsa-wavefront-fix-integer-overflow-in-sample-size-validation.patch @@ -0,0 +1,43 @@ +From stable+bounces-201180-greg=kroah.com@vger.kernel.org Tue Dec 16 12:01:28 2025 +From: Sasha Levin +Date: Tue, 16 Dec 2025 05:59:24 -0500 +Subject: ALSA: wavefront: Fix integer overflow in sample size validation +To: stable@vger.kernel.org +Cc: Junrui Luo , Takashi Iwai , Sasha Levin +Message-ID: <20251216105924.2751369-2-sashal@kernel.org> + +From: Junrui Luo + +[ Upstream commit 0c4a13ba88594fd4a27292853e736c6b4349823d ] + +The wavefront_send_sample() function has an integer overflow issue +when validating sample size. The header->size field is u32 but gets +cast to int for comparison with dev->freemem + +Fix by using unsigned comparison to avoid integer overflow. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881B47789D1B060CE8BF4C3AFC2A@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/isa/wavefront/wavefront_synth.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/isa/wavefront/wavefront_synth.c ++++ b/sound/isa/wavefront/wavefront_synth.c +@@ -950,9 +950,9 @@ wavefront_send_sample (snd_wavefront_t * + if (header->size) { + dev->freemem = wavefront_freemem (dev); + +- if (dev->freemem < (int)header->size) { ++ if (dev->freemem < 0 || dev->freemem < header->size) { + dev_err(dev->card->dev, +- "insufficient memory to load %d byte sample.\n", ++ "insufficient memory to load %u byte sample.\n", + header->size); + return -ENOMEM; + } diff --git a/queue-6.1/alsa-wavefront-use-guard-for-spin-locks.patch b/queue-6.1/alsa-wavefront-use-guard-for-spin-locks.patch new file mode 100644 index 0000000000..585f2b78aa --- /dev/null +++ b/queue-6.1/alsa-wavefront-use-guard-for-spin-locks.patch @@ -0,0 +1,367 @@ +From stable+bounces-201337-greg=kroah.com@vger.kernel.org Tue Dec 16 12:29:29 2025 +From: Sasha Levin +Date: Tue, 16 Dec 2025 06:24:46 -0500 +Subject: ALSA: wavefront: Use guard() for spin locks +To: stable@vger.kernel.org +Cc: Takashi Iwai , Sasha Levin +Message-ID: <20251216112447.2760018-1-sashal@kernel.org> + +From: Takashi Iwai + +[ Upstream commit 4b97f8e614ba46a50bd181d40b5a1424411a211a ] + +Clean up the code using guard() for spin locks. + +Merely code refactoring, and no behavior change. + +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20250829145300.5460-19-tiwai@suse.de +Stable-dep-of: e11c5c13ce0a ("ALSA: wavefront: Clear substream pointers on close") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/isa/wavefront/wavefront_midi.c | 127 +++++++++++++--------------------- + sound/isa/wavefront/wavefront_synth.c | 18 ++-- + 2 files changed, 59 insertions(+), 86 deletions(-) + +--- a/sound/isa/wavefront/wavefront_midi.c ++++ b/sound/isa/wavefront/wavefront_midi.c +@@ -113,7 +113,6 @@ static void snd_wavefront_midi_output_wr + { + snd_wavefront_midi_t *midi = &card->wavefront.midi; + snd_wavefront_mpu_id mpu; +- unsigned long flags; + unsigned char midi_byte; + int max = 256, mask = 1; + int timeout; +@@ -142,11 +141,9 @@ static void snd_wavefront_midi_output_wr + break; + } + +- spin_lock_irqsave (&midi->virtual, flags); +- if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) { +- spin_unlock_irqrestore (&midi->virtual, flags); ++ guard(spinlock_irqsave)(&midi->virtual); ++ if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) + goto __second; +- } + if (output_ready (midi)) { + if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) { + if (!midi->isvirtual || +@@ -160,14 +157,11 @@ static void snd_wavefront_midi_output_wr + del_timer(&midi->timer); + } + midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; +- spin_unlock_irqrestore (&midi->virtual, flags); + goto __second; + } + } else { +- spin_unlock_irqrestore (&midi->virtual, flags); + return; + } +- spin_unlock_irqrestore (&midi->virtual, flags); + } + + __second: +@@ -185,15 +179,13 @@ static void snd_wavefront_midi_output_wr + break; + } + +- spin_lock_irqsave (&midi->virtual, flags); ++ guard(spinlock_irqsave)(&midi->virtual); + if (!midi->isvirtual) + mask = 0; + mpu = midi->output_mpu ^ mask; + mask = 0; /* don't invert the value from now */ +- if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) { +- spin_unlock_irqrestore (&midi->virtual, flags); ++ if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) + return; +- } + if (snd_rawmidi_transmit_empty(midi->substream_output[mpu])) + goto __timer; + if (output_ready (midi)) { +@@ -215,20 +207,16 @@ static void snd_wavefront_midi_output_wr + del_timer(&midi->timer); + } + midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; +- spin_unlock_irqrestore (&midi->virtual, flags); + return; + } + } else { +- spin_unlock_irqrestore (&midi->virtual, flags); + return; + } +- spin_unlock_irqrestore (&midi->virtual, flags); + } + } + + static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -243,17 +231,15 @@ static int snd_wavefront_midi_input_open + if (!midi) + return -EIO; + +- spin_lock_irqsave (&midi->open, flags); ++ guard(spinlock_irqsave)(&midi->open); + midi->mode[mpu] |= MPU401_MODE_INPUT; + midi->substream_input[mpu] = substream; +- spin_unlock_irqrestore (&midi->open, flags); + + return 0; + } + + static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -268,17 +254,15 @@ static int snd_wavefront_midi_output_ope + if (!midi) + return -EIO; + +- spin_lock_irqsave (&midi->open, flags); ++ guard(spinlock_irqsave)(&midi->open); + midi->mode[mpu] |= MPU401_MODE_OUTPUT; + midi->substream_output[mpu] = substream; +- spin_unlock_irqrestore (&midi->open, flags); + + return 0; + } + + static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -293,16 +277,14 @@ static int snd_wavefront_midi_input_clos + if (!midi) + return -EIO; + +- spin_lock_irqsave (&midi->open, flags); ++ guard(spinlock_irqsave)(&midi->open); + midi->mode[mpu] &= ~MPU401_MODE_INPUT; +- spin_unlock_irqrestore (&midi->open, flags); + + return 0; + } + + static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -317,15 +299,13 @@ static int snd_wavefront_midi_output_clo + if (!midi) + return -EIO; + +- spin_lock_irqsave (&midi->open, flags); ++ guard(spinlock_irqsave)(&midi->open); + midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; +- spin_unlock_irqrestore (&midi->open, flags); + return 0; + } + + static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -341,30 +321,27 @@ static void snd_wavefront_midi_input_tri + if (!midi) + return; + +- spin_lock_irqsave (&midi->virtual, flags); ++ guard(spinlock_irqsave)(&midi->virtual); + if (up) { + midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER; + } else { + midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER; + } +- spin_unlock_irqrestore (&midi->virtual, flags); + } + + static void snd_wavefront_midi_output_timer(struct timer_list *t) + { + snd_wavefront_midi_t *midi = from_timer(midi, t, timer); + snd_wavefront_card_t *card = midi->timer_card; +- unsigned long flags; + +- spin_lock_irqsave (&midi->virtual, flags); +- mod_timer(&midi->timer, 1 + jiffies); +- spin_unlock_irqrestore (&midi->virtual, flags); ++ scoped_guard(spinlock_irqsave, &midi->virtual) { ++ mod_timer(&midi->timer, 1 + jiffies); ++ } + snd_wavefront_midi_output_write(card); + } + + static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + snd_wavefront_mpu_id mpu; + +@@ -380,22 +357,22 @@ static void snd_wavefront_midi_output_tr + if (!midi) + return; + +- spin_lock_irqsave (&midi->virtual, flags); +- if (up) { +- if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { +- if (!midi->istimer) { +- timer_setup(&midi->timer, +- snd_wavefront_midi_output_timer, +- 0); +- mod_timer(&midi->timer, 1 + jiffies); ++ scoped_guard(spinlock_irqsave, &midi->virtual) { ++ if (up) { ++ if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { ++ if (!midi->istimer) { ++ timer_setup(&midi->timer, ++ snd_wavefront_midi_output_timer, ++ 0); ++ mod_timer(&midi->timer, 1 + jiffies); ++ } ++ midi->istimer++; ++ midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; + } +- midi->istimer++; +- midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; ++ } else { ++ midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; + } +- } else { +- midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; + } +- spin_unlock_irqrestore (&midi->virtual, flags); + + if (up) + snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data); +@@ -405,7 +382,6 @@ void + snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) + + { +- unsigned long flags; + snd_wavefront_midi_t *midi; + static struct snd_rawmidi_substream *substream = NULL; + static int mpu = external_mpu; +@@ -419,37 +395,37 @@ snd_wavefront_midi_interrupt (snd_wavefr + return; + } + +- spin_lock_irqsave (&midi->virtual, flags); +- while (--max) { ++ scoped_guard(spinlock_irqsave, &midi->virtual) { ++ while (--max) { + +- if (input_avail (midi)) { +- byte = read_data (midi); ++ if (input_avail(midi)) { ++ byte = read_data(midi); + +- if (midi->isvirtual) { +- if (byte == WF_EXTERNAL_SWITCH) { +- substream = midi->substream_input[external_mpu]; +- mpu = external_mpu; +- } else if (byte == WF_INTERNAL_SWITCH) { +- substream = midi->substream_output[internal_mpu]; ++ if (midi->isvirtual) { ++ if (byte == WF_EXTERNAL_SWITCH) { ++ substream = midi->substream_input[external_mpu]; ++ mpu = external_mpu; ++ } else if (byte == WF_INTERNAL_SWITCH) { ++ substream = midi->substream_output[internal_mpu]; ++ mpu = internal_mpu; ++ } /* else just leave it as it is */ ++ } else { ++ substream = midi->substream_input[internal_mpu]; + mpu = internal_mpu; +- } /* else just leave it as it is */ +- } else { +- substream = midi->substream_input[internal_mpu]; +- mpu = internal_mpu; +- } ++ } + +- if (substream == NULL) { +- continue; +- } ++ if (substream == NULL) { ++ continue; ++ } + +- if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { +- snd_rawmidi_receive(substream, &byte, 1); ++ if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { ++ snd_rawmidi_receive(substream, &byte, 1); ++ } ++ } else { ++ break; + } +- } else { +- break; + } +- } +- spin_unlock_irqrestore (&midi->virtual, flags); ++ } + + snd_wavefront_midi_output_write(card); + } +@@ -471,13 +447,10 @@ void + snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) + + { +- unsigned long flags; +- +- spin_lock_irqsave (&card->wavefront.midi.virtual, flags); ++ guard(spinlock_irqsave)(&card->wavefront.midi.virtual); + // snd_wavefront_midi_input_close (card->ics2115_external_rmidi); + // snd_wavefront_midi_output_close (card->ics2115_external_rmidi); + card->wavefront.midi.isvirtual = 0; +- spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); + } + + int +--- a/sound/isa/wavefront/wavefront_synth.c ++++ b/sound/isa/wavefront/wavefront_synth.c +@@ -1740,10 +1740,10 @@ snd_wavefront_internal_interrupt (snd_wa + return; + } + +- spin_lock(&dev->irq_lock); +- dev->irq_ok = 1; +- dev->irq_cnt++; +- spin_unlock(&dev->irq_lock); ++ scoped_guard(spinlock, &dev->irq_lock) { ++ dev->irq_ok = 1; ++ dev->irq_cnt++; ++ } + wake_up(&dev->interrupt_sleeper); + } + +@@ -1795,11 +1795,11 @@ wavefront_should_cause_interrupt (snd_wa + wait_queue_entry_t wait; + + init_waitqueue_entry(&wait, current); +- spin_lock_irq(&dev->irq_lock); +- add_wait_queue(&dev->interrupt_sleeper, &wait); +- dev->irq_ok = 0; +- outb (val,port); +- spin_unlock_irq(&dev->irq_lock); ++ scoped_guard(spinlock_irq, &dev->irq_lock) { ++ add_wait_queue(&dev->interrupt_sleeper, &wait); ++ dev->irq_ok = 0; ++ outb(val, port); ++ } + while (!dev->irq_ok && time_before(jiffies, timeout)) { + schedule_timeout_uninterruptible(1); + barrier(); diff --git a/queue-6.1/alsa-wavefront-use-standard-print-api.patch b/queue-6.1/alsa-wavefront-use-standard-print-api.patch new file mode 100644 index 0000000000..b394c69177 --- /dev/null +++ b/queue-6.1/alsa-wavefront-use-standard-print-api.patch @@ -0,0 +1,1000 @@ +From stable+bounces-201178-greg=kroah.com@vger.kernel.org Tue Dec 16 12:01:19 2025 +From: Sasha Levin +Date: Tue, 16 Dec 2025 05:59:23 -0500 +Subject: ALSA: wavefront: Use standard print API +To: stable@vger.kernel.org +Cc: Takashi Iwai , Jaroslav Kysela , Sasha Levin +Message-ID: <20251216105924.2751369-1-sashal@kernel.org> + +From: Takashi Iwai + +[ Upstream commit 8b4ac5429938dd5f1fbf2eea0687f08cbcccb6be ] + +Use the standard print API with dev_*() instead of the old house-baked +one. It gives better information and allows dynamically control of +debug prints. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20240807133452.9424-36-tiwai@suse.de +Stable-dep-of: 0c4a13ba8859 ("ALSA: wavefront: Fix integer overflow in sample size validation") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/sound/snd_wavefront.h | 4 + sound/isa/wavefront/wavefront.c | 61 +++++----- + sound/isa/wavefront/wavefront_fx.c | 36 +++--- + sound/isa/wavefront/wavefront_midi.c | 15 +- + sound/isa/wavefront/wavefront_synth.c | 196 +++++++++++++++++----------------- + 5 files changed, 158 insertions(+), 154 deletions(-) + +--- a/include/sound/snd_wavefront.h ++++ b/include/sound/snd_wavefront.h +@@ -137,8 +137,4 @@ extern int snd_wavefront_fx_ioctl (str + extern int snd_wavefront_fx_open (struct snd_hwdep *, struct file *); + extern int snd_wavefront_fx_release (struct snd_hwdep *, struct file *); + +-/* prefix in all snd_printk() delivered messages */ +- +-#define LOGNAME "WaveFront: " +- + #endif /* __SOUND_SND_WAVEFRONT_H__ */ +--- a/sound/isa/wavefront/wavefront.c ++++ b/sound/isa/wavefront/wavefront.c +@@ -140,7 +140,7 @@ snd_wavefront_pnp (int dev, snd_wavefron + + err = pnp_activate_dev(pdev); + if (err < 0) { +- snd_printk(KERN_ERR "PnP WSS pnp configure failure\n"); ++ dev_err(&pdev->dev, "PnP WSS pnp configure failure\n"); + return err; + } + +@@ -156,7 +156,7 @@ snd_wavefront_pnp (int dev, snd_wavefron + + err = pnp_activate_dev(pdev); + if (err < 0) { +- snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n"); ++ dev_err(&pdev->dev, "PnP ICS2115 pnp configure failure\n"); + return err; + } + +@@ -174,26 +174,27 @@ snd_wavefront_pnp (int dev, snd_wavefron + + err = pnp_activate_dev(pdev); + if (err < 0) { +- snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n"); ++ dev_err(&pdev->dev, "PnP MPU401 pnp configure failure\n"); + cs4232_mpu_port[dev] = SNDRV_AUTO_PORT; + } else { + cs4232_mpu_port[dev] = pnp_port_start(pdev, 0); + cs4232_mpu_irq[dev] = pnp_irq(pdev, 0); + } + +- snd_printk (KERN_INFO "CS4232 MPU: port=0x%lx, irq=%i\n", +- cs4232_mpu_port[dev], +- cs4232_mpu_irq[dev]); ++ dev_info(&pdev->dev, "CS4232 MPU: port=0x%lx, irq=%i\n", ++ cs4232_mpu_port[dev], ++ cs4232_mpu_irq[dev]); + } + +- snd_printdd ("CS4232: pcm port=0x%lx, fm port=0x%lx, dma1=%i, dma2=%i, irq=%i\nICS2115: port=0x%lx, irq=%i\n", +- cs4232_pcm_port[dev], +- fm_port[dev], +- dma1[dev], +- dma2[dev], +- cs4232_pcm_irq[dev], +- ics2115_port[dev], +- ics2115_irq[dev]); ++ dev_dbg(&pdev->dev, ++ "CS4232: pcm port=0x%lx, fm port=0x%lx, dma1=%i, dma2=%i, irq=%i\nICS2115: port=0x%lx, irq=%i\n", ++ cs4232_pcm_port[dev], ++ fm_port[dev], ++ dma1[dev], ++ dma2[dev], ++ cs4232_pcm_irq[dev], ++ ics2115_port[dev], ++ ics2115_irq[dev]); + + return 0; + } +@@ -251,7 +252,7 @@ static struct snd_hwdep *snd_wavefront_n + struct snd_hwdep *fx_processor; + + if (snd_wavefront_fx_start (&acard->wavefront)) { +- snd_printk (KERN_ERR "cannot initialize YSS225 FX processor"); ++ dev_err(card->dev, "cannot initialize YSS225 FX processor"); + return NULL; + } + +@@ -282,7 +283,7 @@ static struct snd_rawmidi *snd_wavefront + first = 0; + acard->wavefront.midi.base = port; + if (snd_wavefront_midi_start (acard)) { +- snd_printk (KERN_ERR "cannot initialize MIDI interface\n"); ++ dev_err(card->dev, "cannot initialize MIDI interface\n"); + return NULL; + } + } +@@ -349,7 +350,7 @@ snd_wavefront_probe (struct snd_card *ca + cs4232_pcm_irq[dev], dma1[dev], dma2[dev], + WSS_HW_DETECT, 0, &chip); + if (err < 0) { +- snd_printk(KERN_ERR "can't allocate WSS device\n"); ++ dev_err(card->dev, "can't allocate WSS device\n"); + return err; + } + +@@ -369,7 +370,7 @@ snd_wavefront_probe (struct snd_card *ca + err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3_CS, 0, &opl3); + if (err < 0) { +- snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n"); ++ dev_err(card->dev, "can't allocate or detect OPL3 synth\n"); + return err; + } + +@@ -385,14 +386,14 @@ snd_wavefront_probe (struct snd_card *ca + devm_request_region(card->dev, ics2115_port[dev], 16, + "ICS2115"); + if (acard->wavefront.res_base == NULL) { +- snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n", +- ics2115_port[dev], ics2115_port[dev] + 16 - 1); ++ dev_err(card->dev, "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n", ++ ics2115_port[dev], ics2115_port[dev] + 16 - 1); + return -EBUSY; + } + if (devm_request_irq(card->dev, ics2115_irq[dev], + snd_wavefront_ics2115_interrupt, + 0, "ICS2115", acard)) { +- snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]); ++ dev_err(card->dev, "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]); + return -EBUSY; + } + +@@ -402,7 +403,7 @@ snd_wavefront_probe (struct snd_card *ca + + wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard); + if (wavefront_synth == NULL) { +- snd_printk (KERN_ERR "can't create WaveFront synth device\n"); ++ dev_err(card->dev, "can't create WaveFront synth device\n"); + return -ENOMEM; + } + +@@ -414,7 +415,7 @@ snd_wavefront_probe (struct snd_card *ca + + err = snd_wss_mixer(chip); + if (err < 0) { +- snd_printk (KERN_ERR "can't allocate mixer device\n"); ++ dev_err(card->dev, "can't allocate mixer device\n"); + return err; + } + +@@ -425,7 +426,7 @@ snd_wavefront_probe (struct snd_card *ca + cs4232_mpu_port[dev], 0, + cs4232_mpu_irq[dev], NULL); + if (err < 0) { +- snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n"); ++ dev_err(card->dev, "can't allocate CS4232 MPU-401 device\n"); + return err; + } + midi_dev++; +@@ -441,7 +442,7 @@ snd_wavefront_probe (struct snd_card *ca + ics2115_port[dev], + internal_mpu); + if (ics2115_internal_rmidi == NULL) { +- snd_printk (KERN_ERR "can't setup ICS2115 internal MIDI device\n"); ++ dev_err(card->dev, "can't setup ICS2115 internal MIDI device\n"); + return -ENOMEM; + } + midi_dev++; +@@ -457,7 +458,7 @@ snd_wavefront_probe (struct snd_card *ca + ics2115_port[dev], + external_mpu); + if (ics2115_external_rmidi == NULL) { +- snd_printk (KERN_ERR "can't setup ICS2115 external MIDI device\n"); ++ dev_err(card->dev, "can't setup ICS2115 external MIDI device\n"); + return -ENOMEM; + } + midi_dev++; +@@ -471,7 +472,7 @@ snd_wavefront_probe (struct snd_card *ca + acard, + ics2115_port[dev]); + if (fx_processor == NULL) { +- snd_printk (KERN_ERR "can't setup FX device\n"); ++ dev_err(card->dev, "can't setup FX device\n"); + return -ENOMEM; + } + +@@ -525,11 +526,11 @@ static int snd_wavefront_isa_match(struc + return 0; + #endif + if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { +- snd_printk(KERN_ERR "specify CS4232 port\n"); ++ dev_err(pdev, "specify CS4232 port\n"); + return 0; + } + if (ics2115_port[dev] == SNDRV_AUTO_PORT) { +- snd_printk(KERN_ERR "specify ICS2115 port\n"); ++ dev_err(pdev, "specify ICS2115 port\n"); + return 0; + } + return 1; +@@ -585,7 +586,7 @@ static int snd_wavefront_pnp_detect(stru + + if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) { + if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { +- snd_printk (KERN_ERR "isapnp detection failed\n"); ++ dev_err(card->dev, "isapnp detection failed\n"); + return -ENODEV; + } + } +--- a/sound/isa/wavefront/wavefront_fx.c ++++ b/sound/isa/wavefront/wavefront_fx.c +@@ -38,7 +38,7 @@ wavefront_fx_idle (snd_wavefront_t *dev) + } + + if (x & 0x80) { +- snd_printk ("FX device never idle.\n"); ++ dev_err(dev->card->dev, "FX device never idle.\n"); + return 0; + } + +@@ -64,14 +64,14 @@ wavefront_fx_memset (snd_wavefront_t *de + unsigned short *data) + { + if (page < 0 || page > 7) { +- snd_printk ("FX memset: " +- "page must be >= 0 and <= 7\n"); ++ dev_err(dev->card->dev, ++ "FX memset: page must be >= 0 and <= 7\n"); + return -EINVAL; + } + + if (addr < 0 || addr > 0x7f) { +- snd_printk ("FX memset: " +- "addr must be >= 0 and <= 7f\n"); ++ dev_err(dev->card->dev, ++ "FX memset: addr must be >= 0 and <= 7f\n"); + return -EINVAL; + } + +@@ -83,7 +83,7 @@ wavefront_fx_memset (snd_wavefront_t *de + outb ((data[0] >> 8), dev->fx_dsp_msb); + outb ((data[0] & 0xff), dev->fx_dsp_lsb); + +- snd_printk ("FX: addr %d:%x set to 0x%x\n", ++ dev_err(dev->card->dev, "FX: addr %d:%x set to 0x%x\n", + page, addr, data[0]); + + } else { +@@ -102,9 +102,9 @@ wavefront_fx_memset (snd_wavefront_t *de + } + + if (i != cnt) { +- snd_printk ("FX memset " +- "(0x%x, 0x%x, 0x%lx, %d) incomplete\n", +- page, addr, (unsigned long) data, cnt); ++ dev_err(dev->card->dev, ++ "FX memset (0x%x, 0x%x, 0x%lx, %d) incomplete\n", ++ page, addr, (unsigned long) data, cnt); + return -EIO; + } + } +@@ -123,7 +123,7 @@ snd_wavefront_fx_detect (snd_wavefront_t + */ + + if (inb (dev->fx_status) & 0x80) { +- snd_printk ("Hmm, probably a Maui or Tropez.\n"); ++ dev_err(dev->card->dev, "Hmm, probably a Maui or Tropez.\n"); + return -1; + } + +@@ -180,15 +180,15 @@ snd_wavefront_fx_ioctl (struct snd_hwdep + + case WFFX_MEMSET: + if (r.data[2] <= 0) { +- snd_printk ("cannot write " +- "<= 0 bytes to FX\n"); ++ dev_err(dev->card->dev, ++ "cannot write <= 0 bytes to FX\n"); + return -EIO; + } else if (r.data[2] == 1) { + pd = (unsigned short *) &r.data[3]; + } else { + if (r.data[2] > 256) { +- snd_printk ("cannot write " +- "> 512 bytes to FX\n"); ++ dev_err(dev->card->dev, ++ "cannot write > 512 bytes to FX\n"); + return -EIO; + } + page_data = memdup_user((unsigned char __user *) +@@ -208,8 +208,8 @@ snd_wavefront_fx_ioctl (struct snd_hwdep + break; + + default: +- snd_printk ("FX: ioctl %d not yet supported\n", +- r.request); ++ dev_err(dev->card->dev, "FX: ioctl %d not yet supported\n", ++ r.request); + return -ENOTTY; + } + return err; +@@ -254,8 +254,8 @@ snd_wavefront_fx_start (snd_wavefront_t + goto out; + } + } else { +- snd_printk(KERN_ERR "invalid address" +- " in register data\n"); ++ dev_err(dev->card->dev, ++ "invalid address in register data\n"); + err = -1; + goto out; + } +--- a/sound/isa/wavefront/wavefront_midi.c ++++ b/sound/isa/wavefront/wavefront_midi.c +@@ -476,7 +476,8 @@ snd_wavefront_midi_start (snd_wavefront_ + for (i = 0; i < 30000 && !output_ready (midi); i++); + + if (!output_ready (midi)) { +- snd_printk ("MIDI interface not ready for command\n"); ++ dev_err(card->wavefront.card->dev, ++ "MIDI interface not ready for command\n"); + return -1; + } + +@@ -498,7 +499,8 @@ snd_wavefront_midi_start (snd_wavefront_ + } + + if (!ok) { +- snd_printk ("cannot set UART mode for MIDI interface"); ++ dev_err(card->wavefront.card->dev, ++ "cannot set UART mode for MIDI interface"); + dev->interrupts_are_midi = 0; + return -1; + } +@@ -506,7 +508,8 @@ snd_wavefront_midi_start (snd_wavefront_ + /* Route external MIDI to WaveFront synth (by default) */ + + if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) { +- snd_printk ("can't enable MIDI-IN-2-synth routing.\n"); ++ dev_warn(card->wavefront.card->dev, ++ "can't enable MIDI-IN-2-synth routing.\n"); + /* XXX error ? */ + } + +@@ -522,14 +525,16 @@ snd_wavefront_midi_start (snd_wavefront_ + */ + + if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { +- snd_printk ("virtual MIDI mode not disabled\n"); ++ dev_warn(card->wavefront.card->dev, ++ "virtual MIDI mode not disabled\n"); + return 0; /* We're OK, but missing the external MIDI dev */ + } + + snd_wavefront_midi_enable_virtual (card); + + if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) { +- snd_printk ("cannot enable virtual MIDI mode.\n"); ++ dev_warn(card->wavefront.card->dev, ++ "cannot enable virtual MIDI mode.\n"); + snd_wavefront_midi_disable_virtual (card); + } + return 0; +--- a/sound/isa/wavefront/wavefront_synth.c ++++ b/sound/isa/wavefront/wavefront_synth.c +@@ -116,7 +116,7 @@ MODULE_PARM_DESC(osrun_time, "how many s + + #define DPRINT(cond, ...) \ + if ((dev->debug & (cond)) == (cond)) { \ +- snd_printk (__VA_ARGS__); \ ++ pr_debug(__VA_ARGS__); \ + } + #else + #define DPRINT(cond, args...) +@@ -341,7 +341,7 @@ snd_wavefront_cmd (snd_wavefront_t *dev, + + wfcmd = wavefront_get_command(cmd); + if (!wfcmd) { +- snd_printk ("command 0x%x not supported.\n", ++ dev_err(dev->card->dev, "command 0x%x not supported.\n", + cmd); + return 1; + } +@@ -623,7 +623,7 @@ wavefront_get_sample_status (snd_wavefro + /* check sample status */ + + if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) { +- snd_printk ("cannot request sample count.\n"); ++ dev_err(dev->card->dev, "cannot request sample count.\n"); + return -1; + } + +@@ -635,8 +635,8 @@ wavefront_get_sample_status (snd_wavefro + wbuf[1] = i >> 7; + + if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { +- snd_printk(KERN_WARNING "cannot identify sample " +- "type of slot %d\n", i); ++ dev_warn(dev->card->dev, ++ "cannot identify sample type of slot %d\n", i); + dev->sample_status[i] = WF_ST_EMPTY; + continue; + } +@@ -661,9 +661,9 @@ wavefront_get_sample_status (snd_wavefro + break; + + default: +- snd_printk ("unknown sample type for " +- "slot %d (0x%x)\n", +- i, rbuf[0]); ++ dev_err(dev->card->dev, ++ "unknown sample type for slot %d (0x%x)\n", ++ i, rbuf[0]); + } + + if (rbuf[0] != WF_ST_EMPTY) { +@@ -671,9 +671,10 @@ wavefront_get_sample_status (snd_wavefro + } + } + +- snd_printk ("%d samples used (%d real, %d aliases, %d multi), " +- "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi, +- WF_MAX_SAMPLE - dev->samples_used); ++ dev_info(dev->card->dev, ++ "%d samples used (%d real, %d aliases, %d multi), %d empty\n", ++ dev->samples_used, sc_real, sc_alias, sc_multi, ++ WF_MAX_SAMPLE - dev->samples_used); + + + return (0); +@@ -706,8 +707,8 @@ wavefront_get_patch_status (snd_wavefron + } else if (x == 3) { /* Bad patch number */ + dev->patch_status[i] = 0; + } else { +- snd_printk ("upload patch " +- "error 0x%x\n", x); ++ dev_err(dev->card->dev, ++ "upload patch error 0x%x\n", x); + dev->patch_status[i] = 0; + return 1; + } +@@ -724,7 +725,8 @@ wavefront_get_patch_status (snd_wavefron + } + + } +- snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2); ++ dev_info(dev->card->dev, "%d patch slots filled, %d in use\n", ++ cnt, cnt2); + + return (0); + } +@@ -760,8 +762,8 @@ wavefront_get_program_status (snd_wavefr + } else if (x == 1) { /* Bad program number */ + dev->prog_status[i] = 0; + } else { +- snd_printk ("upload program " +- "error 0x%x\n", x); ++ dev_err(dev->card->dev, ++ "upload program error 0x%x\n", x); + dev->prog_status[i] = 0; + } + } +@@ -772,7 +774,7 @@ wavefront_get_program_status (snd_wavefr + } + } + +- snd_printk ("%d programs slots in use\n", cnt); ++ dev_info(dev->card->dev, "%d programs slots in use\n", cnt); + + return (0); + } +@@ -796,7 +798,7 @@ wavefront_send_patch (snd_wavefront_t *d + munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); + + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) { +- snd_printk ("download patch failed\n"); ++ dev_err(dev->card->dev, "download patch failed\n"); + return -EIO; + } + +@@ -837,7 +839,7 @@ wavefront_send_program (snd_wavefront_t + munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); + + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) { +- snd_printk ("download patch failed\n"); ++ dev_err(dev->card->dev, "download patch failed\n"); + return -EIO; + } + +@@ -851,7 +853,7 @@ wavefront_freemem (snd_wavefront_t *dev) + char rbuf[8]; + + if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { +- snd_printk ("can't get memory stats.\n"); ++ dev_err(dev->card->dev, "can't get memory stats.\n"); + return -1; + } else { + return demunge_int32 (rbuf, 4); +@@ -901,7 +903,7 @@ wavefront_send_sample (snd_wavefront_t * + x = wavefront_find_free_sample(dev); + if (x < 0) + return -ENOMEM; +- snd_printk ("unspecified sample => %d\n", x); ++ dev_info(dev->card->dev, "unspecified sample => %d\n", x); + header->number = x; + } + +@@ -935,9 +937,9 @@ wavefront_send_sample (snd_wavefront_t * + + if (dev->rom_samples_rdonly) { + if (dev->sample_status[header->number] & WF_SLOT_ROM) { +- snd_printk ("sample slot %d " +- "write protected\n", +- header->number); ++ dev_err(dev->card->dev, ++ "sample slot %d write protected\n", ++ header->number); + return -EACCES; + } + } +@@ -949,9 +951,9 @@ wavefront_send_sample (snd_wavefront_t * + dev->freemem = wavefront_freemem (dev); + + if (dev->freemem < (int)header->size) { +- snd_printk ("insufficient memory to " +- "load %d byte sample.\n", +- header->size); ++ dev_err(dev->card->dev, ++ "insufficient memory to load %d byte sample.\n", ++ header->size); + return -ENOMEM; + } + +@@ -960,8 +962,8 @@ wavefront_send_sample (snd_wavefront_t * + skip = WF_GET_CHANNEL(&header->hdr.s); + + if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { +- snd_printk ("channel selection only " +- "possible on 16-bit samples"); ++ dev_err(dev->card->dev, ++ "channel selection only possible on 16-bit samples"); + return -EINVAL; + } + +@@ -1057,8 +1059,8 @@ wavefront_send_sample (snd_wavefront_t * + header->size ? + WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, + NULL, sample_hdr)) { +- snd_printk ("sample %sdownload refused.\n", +- header->size ? "" : "header "); ++ dev_err(dev->card->dev, "sample %sdownload refused.\n", ++ header->size ? "" : "header "); + return -EIO; + } + +@@ -1083,8 +1085,8 @@ wavefront_send_sample (snd_wavefront_t * + } + + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) { +- snd_printk ("download block " +- "request refused.\n"); ++ dev_err(dev->card->dev, ++ "download block request refused.\n"); + return -EIO; + } + +@@ -1145,13 +1147,13 @@ wavefront_send_sample (snd_wavefront_t * + dma_ack = wavefront_read(dev); + if (dma_ack != WF_DMA_ACK) { + if (dma_ack == -1) { +- snd_printk ("upload sample " +- "DMA ack timeout\n"); ++ dev_err(dev->card->dev, ++ "upload sample DMA ack timeout\n"); + return -EIO; + } else { +- snd_printk ("upload sample " +- "DMA ack error 0x%x\n", +- dma_ack); ++ dev_err(dev->card->dev, ++ "upload sample DMA ack error 0x%x\n", ++ dma_ack); + return -EIO; + } + } +@@ -1195,7 +1197,7 @@ wavefront_send_alias (snd_wavefront_t *d + munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); + + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { +- snd_printk ("download alias failed.\n"); ++ dev_err(dev->card->dev, "download alias failed.\n"); + return -EIO; + } + +@@ -1248,7 +1250,7 @@ wavefront_send_multisample (snd_wavefron + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE, + (unsigned char *) (long) ((num_samples*2)+3), + msample_hdr)) { +- snd_printk ("download of multisample failed.\n"); ++ dev_err(dev->card->dev, "download of multisample failed.\n"); + kfree(msample_hdr); + return -EIO; + } +@@ -1271,7 +1273,7 @@ wavefront_fetch_multisample (snd_wavefro + munge_int32 (header->number, number, 2); + + if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { +- snd_printk ("upload multisample failed.\n"); ++ dev_err(dev->card->dev, "upload multisample failed.\n"); + return -EIO; + } + +@@ -1290,16 +1292,16 @@ wavefront_fetch_multisample (snd_wavefro + + val = wavefront_read(dev); + if (val == -1) { +- snd_printk ("upload multisample failed " +- "during sample loop.\n"); ++ dev_err(dev->card->dev, ++ "upload multisample failed during sample loop.\n"); + return -EIO; + } + d[0] = val; + + val = wavefront_read(dev); + if (val == -1) { +- snd_printk ("upload multisample failed " +- "during sample loop.\n"); ++ dev_err(dev->card->dev, ++ "upload multisample failed during sample loop.\n"); + return -EIO; + } + d[1] = val; +@@ -1334,7 +1336,7 @@ wavefront_send_drum (snd_wavefront_t *de + } + + if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { +- snd_printk ("download drum failed.\n"); ++ dev_err(dev->card->dev, "download drum failed.\n"); + return -EIO; + } + +@@ -1352,7 +1354,7 @@ wavefront_find_free_sample (snd_wavefron + return i; + } + } +- snd_printk ("no free sample slots!\n"); ++ dev_err(dev->card->dev, "no free sample slots!\n"); + return -1; + } + +@@ -1368,7 +1370,7 @@ wavefront_find_free_patch (snd_wavefront + return i; + } + } +- snd_printk ("no free patch slots!\n"); ++ dev_err(dev->card->dev, "no free patch slots!\n"); + return -1; + } + #endif +@@ -1385,7 +1387,7 @@ wavefront_load_patch (snd_wavefront_t *d + + if (copy_from_user (header, addr, sizeof(wavefront_patch_info) - + sizeof(wavefront_any))) { +- snd_printk ("bad address for load patch.\n"); ++ dev_err(dev->card->dev, "bad address for load patch.\n"); + err = -EFAULT; + goto __error; + } +@@ -1463,8 +1465,8 @@ wavefront_load_patch (snd_wavefront_t *d + break; + + default: +- snd_printk ("unknown patch type %d.\n", +- header->subkey); ++ dev_err(dev->card->dev, "unknown patch type %d.\n", ++ header->subkey); + err = -EINVAL; + break; + } +@@ -1527,13 +1529,13 @@ wavefront_synth_control (snd_wavefront_c + switch (wc->cmd) { + + case WFC_DISABLE_INTERRUPTS: +- snd_printk ("interrupts disabled.\n"); ++ dev_dbg(dev->card->dev, "interrupts disabled.\n"); + outb (0x80|0x20, dev->control_port); + dev->interrupts_are_midi = 1; + return 0; + + case WFC_ENABLE_INTERRUPTS: +- snd_printk ("interrupts enabled.\n"); ++ dev_dbg(dev->card->dev, "interrupts enabled.\n"); + outb (0x80|0x40|0x20, dev->control_port); + dev->interrupts_are_midi = 1; + return 0; +@@ -1550,7 +1552,7 @@ wavefront_synth_control (snd_wavefront_c + case WFC_IDENTIFY_SLOT_TYPE: + i = wc->wbuf[0] | (wc->wbuf[1] << 7); + if (i <0 || i >= WF_MAX_SAMPLE) { +- snd_printk ("invalid slot ID %d\n", ++ dev_err(dev->card->dev, "invalid slot ID %d\n", + i); + wc->status = EINVAL; + return -EINVAL; +@@ -1561,7 +1563,7 @@ wavefront_synth_control (snd_wavefront_c + + case WFC_DEBUG_DRIVER: + dev->debug = wc->wbuf[0]; +- snd_printk ("debug = 0x%x\n", dev->debug); ++ dev_dbg(dev->card->dev, "debug = 0x%x\n", dev->debug); + return 0; + + case WFC_UPLOAD_PATCH: +@@ -1578,8 +1580,8 @@ wavefront_synth_control (snd_wavefront_c + return 0; + + case WFC_UPLOAD_SAMPLE_ALIAS: +- snd_printk ("support for sample alias upload " +- "being considered.\n"); ++ dev_err(dev->card->dev, ++ "support for sample alias upload being considered.\n"); + wc->status = EINVAL; + return -EINVAL; + } +@@ -1620,9 +1622,8 @@ wavefront_synth_control (snd_wavefront_c + break; + + case WFC_UPLOAD_SAMPLE_ALIAS: +- snd_printk ("support for " +- "sample aliases still " +- "being considered.\n"); ++ dev_err(dev->card->dev, ++ "support for sample aliases still being considered.\n"); + break; + + case WFC_VMIDI_OFF: +@@ -1760,7 +1761,7 @@ snd_wavefront_internal_interrupt (snd_wa + */ + + static int +-snd_wavefront_interrupt_bits (int irq) ++snd_wavefront_interrupt_bits(snd_wavefront_t *dev, int irq) + + { + int bits; +@@ -1780,7 +1781,7 @@ snd_wavefront_interrupt_bits (int irq) + break; + + default: +- snd_printk ("invalid IRQ %d\n", irq); ++ dev_err(dev->card->dev, "invalid IRQ %d\n", irq); + bits = -1; + } + +@@ -1815,7 +1816,7 @@ wavefront_reset_to_cleanliness (snd_wave + + /* IRQ already checked */ + +- bits = snd_wavefront_interrupt_bits (dev->irq); ++ bits = snd_wavefront_interrupt_bits(dev, dev->irq); + + /* try reset of port */ + +@@ -1885,7 +1886,7 @@ wavefront_reset_to_cleanliness (snd_wave + */ + + if (!dev->irq_ok) { +- snd_printk ("intr not received after h/w un-reset.\n"); ++ dev_err(dev->card->dev, "intr not received after h/w un-reset.\n"); + goto gone_bad; + } + +@@ -1909,18 +1910,18 @@ wavefront_reset_to_cleanliness (snd_wave + dev->data_port, ramcheck_time*HZ); + + if (!dev->irq_ok) { +- snd_printk ("post-RAM-check interrupt not received.\n"); ++ dev_err(dev->card->dev, "post-RAM-check interrupt not received.\n"); + goto gone_bad; + } + + if (!wavefront_wait (dev, STAT_CAN_READ)) { +- snd_printk ("no response to HW version cmd.\n"); ++ dev_err(dev->card->dev, "no response to HW version cmd.\n"); + goto gone_bad; + } + + hwv[0] = wavefront_read(dev); + if (hwv[0] == -1) { +- snd_printk ("board not responding correctly.\n"); ++ dev_err(dev->card->dev, "board not responding correctly.\n"); + goto gone_bad; + } + +@@ -1932,11 +1933,11 @@ wavefront_reset_to_cleanliness (snd_wave + + hwv[0] = wavefront_read(dev); + if (hwv[0] == -1) { +- snd_printk ("on-board RAM test failed " +- "(bad error code).\n"); ++ dev_err(dev->card->dev, ++ "on-board RAM test failed (bad error code).\n"); + } else { +- snd_printk ("on-board RAM test failed " +- "(error code: 0x%x).\n", ++ dev_err(dev->card->dev, ++ "on-board RAM test failed (error code: 0x%x).\n", + hwv[0]); + } + goto gone_bad; +@@ -1946,12 +1947,12 @@ wavefront_reset_to_cleanliness (snd_wave + + hwv[1] = wavefront_read(dev); + if (hwv[1] == -1) { +- snd_printk ("incorrect h/w response.\n"); ++ dev_err(dev->card->dev, "incorrect h/w response.\n"); + goto gone_bad; + } + +- snd_printk ("hardware version %d.%d\n", +- hwv[0], hwv[1]); ++ dev_info(dev->card->dev, "hardware version %d.%d\n", ++ hwv[0], hwv[1]); + + return 0; + +@@ -1971,7 +1972,7 @@ wavefront_download_firmware (snd_wavefro + + err = request_firmware(&firmware, path, dev->card->dev); + if (err < 0) { +- snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path); ++ dev_err(dev->card->dev, "firmware (%s) download failed!!!\n", path); + return 1; + } + +@@ -1982,16 +1983,16 @@ wavefront_download_firmware (snd_wavefro + if (section_length == 0) + break; + if (section_length < 0 || section_length > WF_SECTION_MAX) { +- snd_printk(KERN_ERR +- "invalid firmware section length %d\n", +- section_length); ++ dev_err(dev->card->dev, ++ "invalid firmware section length %d\n", ++ section_length); + goto failure; + } + buf++; + len++; + + if (firmware->size < len + section_length) { +- snd_printk(KERN_ERR "firmware section read error.\n"); ++ dev_err(dev->card->dev, "firmware section read error.\n"); + goto failure; + } + +@@ -2008,15 +2009,14 @@ wavefront_download_firmware (snd_wavefro + + /* get ACK */ + if (!wavefront_wait(dev, STAT_CAN_READ)) { +- snd_printk(KERN_ERR "time out for firmware ACK.\n"); ++ dev_err(dev->card->dev, "time out for firmware ACK.\n"); + goto failure; + } + err = inb(dev->data_port); + if (err != WF_ACK) { +- snd_printk(KERN_ERR +- "download of section #%d not " +- "acknowledged, ack = 0x%x\n", +- section_cnt_downloaded + 1, err); ++ dev_err(dev->card->dev, ++ "download of section #%d not acknowledged, ack = 0x%x\n", ++ section_cnt_downloaded + 1, err); + goto failure; + } + +@@ -2028,7 +2028,7 @@ wavefront_download_firmware (snd_wavefro + + failure: + release_firmware(firmware); +- snd_printk(KERN_ERR "firmware download failed!!!\n"); ++ dev_err(dev->card->dev, "firmware download failed!!!\n"); + return 1; + } + +@@ -2040,7 +2040,7 @@ wavefront_do_reset (snd_wavefront_t *dev + char voices[1]; + + if (wavefront_reset_to_cleanliness (dev)) { +- snd_printk ("hw reset failed.\n"); ++ dev_err(dev->card->dev, "hw reset failed.\n"); + goto gone_bad; + } + +@@ -2064,7 +2064,7 @@ wavefront_do_reset (snd_wavefront_t *dev + (osrun_time*HZ)); + + if (!dev->irq_ok) { +- snd_printk ("no post-OS interrupt.\n"); ++ dev_err(dev->card->dev, "no post-OS interrupt.\n"); + goto gone_bad; + } + +@@ -2074,7 +2074,7 @@ wavefront_do_reset (snd_wavefront_t *dev + dev->data_port, (10*HZ)); + + if (!dev->irq_ok) { +- snd_printk ("no post-OS interrupt(2).\n"); ++ dev_err(dev->card->dev, "no post-OS interrupt(2).\n"); + goto gone_bad; + } + +@@ -2094,20 +2094,20 @@ wavefront_do_reset (snd_wavefront_t *dev + if (dev->freemem < 0) + goto gone_bad; + +- snd_printk ("available DRAM %dk\n", dev->freemem / 1024); ++ dev_info(dev->card->dev, "available DRAM %dk\n", dev->freemem / 1024); + + if (wavefront_write (dev, 0xf0) || + wavefront_write (dev, 1) || + (wavefront_read (dev) < 0)) { + dev->debug = 0; +- snd_printk ("MPU emulation mode not set.\n"); ++ dev_err(dev->card->dev, "MPU emulation mode not set.\n"); + goto gone_bad; + } + + voices[0] = 32; + + if (snd_wavefront_cmd (dev, WFC_SET_NVOICES, NULL, voices)) { +- snd_printk ("cannot set number of voices to 32.\n"); ++ dev_err(dev->card->dev, "cannot set number of voices to 32.\n"); + goto gone_bad; + } + +@@ -2187,8 +2187,8 @@ snd_wavefront_detect (snd_wavefront_card + dev->fw_version[0] = rbuf[0]; + dev->fw_version[1] = rbuf[1]; + +- snd_printk ("firmware %d.%d already loaded.\n", +- rbuf[0], rbuf[1]); ++ dev_info(dev->card->dev, "firmware %d.%d already loaded.\n", ++ rbuf[0], rbuf[1]); + + /* check that a command actually works */ + +@@ -2197,22 +2197,24 @@ snd_wavefront_detect (snd_wavefront_card + dev->hw_version[0] = rbuf[0]; + dev->hw_version[1] = rbuf[1]; + } else { +- snd_printk ("not raw, but no " +- "hardware version!\n"); ++ dev_err(dev->card->dev, ++ "not raw, but no hardware version!\n"); + return -1; + } + + if (!wf_raw) { + return 0; + } else { +- snd_printk ("reloading firmware as you requested.\n"); ++ dev_info(dev->card->dev, ++ "reloading firmware as you requested.\n"); + dev->israw = 1; + } + + } else { + + dev->israw = 1; +- snd_printk ("no response to firmware probe, assume raw.\n"); ++ dev_info(dev->card->dev, ++ "no response to firmware probe, assume raw.\n"); + + } + diff --git a/queue-6.1/arm-dts-microchip-sama5d2-fix-spi-flexcom-fifo-size-to-32.patch b/queue-6.1/arm-dts-microchip-sama5d2-fix-spi-flexcom-fifo-size-to-32.patch new file mode 100644 index 0000000000..33d305807b --- /dev/null +++ b/queue-6.1/arm-dts-microchip-sama5d2-fix-spi-flexcom-fifo-size-to-32.patch @@ -0,0 +1,73 @@ +From stable+bounces-204389-greg=kroah.com@vger.kernel.org Wed Dec 31 22:07:42 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 16:07:37 -0500 +Subject: ARM: dts: microchip: sama5d2: fix spi flexcom fifo size to 32 +To: stable@vger.kernel.org +Cc: Nicolas Ferre , Claudiu Beznea , Sasha Levin +Message-ID: <20251231210737.3501550-1-sashal@kernel.org> + +From: Nicolas Ferre + +[ Upstream commit 7d5864dc5d5ea6a35983dd05295fb17f2f2f44ce ] + +Unlike standalone spi peripherals, on sama5d2, the flexcom spi have fifo +size of 32 data. Fix flexcom/spi nodes where this property is wrong. + +Fixes: 6b9a3584c7ed ("ARM: dts: at91: sama5d2: Add missing flexcom definitions") +Cc: stable@vger.kernel.org # 5.8+ +Signed-off-by: Nicolas Ferre +Link: https://lore.kernel.org/r/20251114140225.30372-1-nicolas.ferre@microchip.com +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/boot/dts/sama5d2.dtsi | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/sama5d2.dtsi ++++ b/arch/arm/boot/dts/sama5d2.dtsi +@@ -568,7 +568,7 @@ + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(12))>; + dma-names = "tx", "rx"; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + +@@ -639,7 +639,7 @@ + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(14))>; + dma-names = "tx", "rx"; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + +@@ -852,7 +852,7 @@ + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(16))>; + dma-names = "tx", "rx"; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + +@@ -923,7 +923,7 @@ + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(18))>; + dma-names = "tx", "rx"; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + +@@ -995,7 +995,7 @@ + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(20))>; + dma-names = "tx", "rx"; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + diff --git a/queue-6.1/arm-dts-microchip-sama7g5-fix-uart-fifo-size-to-32.patch b/queue-6.1/arm-dts-microchip-sama7g5-fix-uart-fifo-size-to-32.patch new file mode 100644 index 0000000000..fa985f3426 --- /dev/null +++ b/queue-6.1/arm-dts-microchip-sama7g5-fix-uart-fifo-size-to-32.patch @@ -0,0 +1,46 @@ +From stable+bounces-204394-greg=kroah.com@vger.kernel.org Wed Dec 31 23:31:52 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 17:31:46 -0500 +Subject: ARM: dts: microchip: sama7g5: fix uart fifo size to 32 +To: stable@vger.kernel.org +Cc: Nicolas Ferre , Claudiu Beznea , Sasha Levin +Message-ID: <20251231223146.3547624-1-sashal@kernel.org> + +From: Nicolas Ferre + +[ Upstream commit 5654889a94b0de5ad6ceae3793e7f5e0b61b50b6 ] + +On some flexcom nodes related to uart, the fifo sizes were wrong: fix +them to 32 data. + +Fixes: 7540629e2fc7 ("ARM: dts: at91: add sama7g5 SoC DT and sama7g5-ek") +Cc: stable@vger.kernel.org # 5.15+ +Signed-off-by: Nicolas Ferre +Link: https://lore.kernel.org/r/20251114103313.20220-2-nicolas.ferre@microchip.com +Signed-off-by: Claudiu Beznea +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/boot/dts/sama7g5.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/sama7g5.dtsi ++++ b/arch/arm/boot/dts/sama7g5.dtsi +@@ -706,7 +706,7 @@ + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + }; +@@ -732,7 +732,7 @@ + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; +- atmel,fifo-size = <16>; ++ atmel,fifo-size = <32>; + status = "disabled"; + }; + }; diff --git a/queue-6.1/arm64-dts-ti-k3-j721e-sk-fix-pinmux-for-pin-y1-used-by-power-regulator.patch b/queue-6.1/arm64-dts-ti-k3-j721e-sk-fix-pinmux-for-pin-y1-used-by-power-regulator.patch new file mode 100644 index 0000000000..3d5f9ebebb --- /dev/null +++ b/queue-6.1/arm64-dts-ti-k3-j721e-sk-fix-pinmux-for-pin-y1-used-by-power-regulator.patch @@ -0,0 +1,67 @@ +From stable+bounces-204856-greg=kroah.com@vger.kernel.org Mon Jan 5 17:53:57 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 11:48:43 -0500 +Subject: arm64: dts: ti: k3-j721e-sk: Fix pinmux for pin Y1 used by power regulator +To: stable@vger.kernel.org +Cc: Siddharth Vadapalli , Yemike Abhilash Chandra , Vignesh Raghavendra , Sasha Levin +Message-ID: <20260105164843.2676258-1-sashal@kernel.org> + +From: Siddharth Vadapalli + +[ Upstream commit 51f89c488f2ecc020f82bfedd77482584ce8027a ] + +The SoC pin Y1 is incorrectly defined in the WKUP Pinmux device-tree node +(pinctrl@4301c000) leading to the following silent failure: + + pinctrl-single 4301c000.pinctrl: mux offset out of range: 0x1dc (0x178) + +According to the datasheet for the J721E SoC [0], the pin Y1 belongs to the +MAIN Pinmux device-tree node (pinctrl@11c000). This is confirmed by the +address of the pinmux register for it on page 142 of the datasheet which is +0x00011C1DC. + +Hence fix it. + +[0]: https://www.ti.com/lit/ds/symlink/tda4vm.pdf + +Fixes: 97b67cc102dc ("arm64: dts: ti: k3-j721e-sk: Add DT nodes for power regulators") +Cc: stable@vger.kernel.org +Signed-off-by: Siddharth Vadapalli +Reviewed-by: Yemike Abhilash Chandra +Link: https://patch.msgid.link/20251119160148.2752616-1-s-vadapalli@ti.com +Signed-off-by: Vignesh Raghavendra +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/boot/dts/ti/k3-j721e-sk.dts | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +@@ -425,6 +425,12 @@ + J721E_IOPAD(0x124, PIN_INPUT, 7) /* (Y24) PRG0_PRU1_GPO9.GPIO0_72 */ + >; + }; ++ ++ vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { ++ pinctrl-single,pins = < ++ J721E_IOPAD(0x1dc, PIN_OUTPUT, 7) /* (Y1) SPI1_CLK.GPIO0_118 */ ++ >; ++ }; + }; + + &wkup_pmx0 { +@@ -480,12 +486,6 @@ + >; + }; + +- vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { +- pinctrl-single,pins = < +- J721E_IOPAD(0x1dc, PIN_OUTPUT, 7) /* (Y1) SPI1_CLK.GPIO0_118 */ +- >; +- }; +- + wkup_i2c0_pins_default: wkup-i2c0-pins-default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0xf8, PIN_INPUT_PULLUP, 0) /* (J25) WKUP_I2C0_SCL */ diff --git a/queue-6.1/asoc-stm-stm32_sai_sub-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/asoc-stm-stm32_sai_sub-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..24bc0906b4 --- /dev/null +++ b/queue-6.1/asoc-stm-stm32_sai_sub-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,64 @@ +From stable+bounces-204817-greg=kroah.com@vger.kernel.org Mon Jan 5 16:04:04 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 09:51:31 -0500 +Subject: ASoC: stm: stm32_sai_sub: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Takashi Iwai" , "Nicolas Ferre" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260105145135.2613585-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit a3bd37e2e2bce4fb1757a940fa985d556662ba80 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Acked-by: Takashi Iwai +Acked-by: Nicolas Ferre +Link: https://lore.kernel.org/r/20230315150745.67084-139-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/stm/stm32_sai_sub.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/sound/soc/stm/stm32_sai_sub.c ++++ b/sound/soc/stm/stm32_sai_sub.c +@@ -1570,7 +1570,7 @@ err_unprepare_pclk: + return ret; + } + +-static int stm32_sai_sub_remove(struct platform_device *pdev) ++static void stm32_sai_sub_remove(struct platform_device *pdev) + { + struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev); + +@@ -1578,8 +1578,6 @@ static int stm32_sai_sub_remove(struct p + snd_dmaengine_pcm_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); +- +- return 0; + } + + #ifdef CONFIG_PM_SLEEP +@@ -1629,7 +1627,7 @@ static struct platform_driver stm32_sai_ + .pm = &stm32_sai_sub_pm_ops, + }, + .probe = stm32_sai_sub_probe, +- .remove = stm32_sai_sub_remove, ++ .remove_new = stm32_sai_sub_remove, + }; + + module_platform_driver(stm32_sai_sub_driver); diff --git a/queue-6.1/asoc-stm32-sai-fix-clk-prepare-imbalance-on-probe-failure.patch b/queue-6.1/asoc-stm32-sai-fix-clk-prepare-imbalance-on-probe-failure.patch new file mode 100644 index 0000000000..47287d1474 --- /dev/null +++ b/queue-6.1/asoc-stm32-sai-fix-clk-prepare-imbalance-on-probe-failure.patch @@ -0,0 +1,93 @@ +From stable+bounces-204804-greg=kroah.com@vger.kernel.org Mon Jan 5 15:10:30 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 09:06:13 -0500 +Subject: ASoC: stm32: sai: fix clk prepare imbalance on probe failure +To: stable@vger.kernel.org +Cc: Johan Hovold , Olivier Moysan , olivier moysan , Mark Brown , Sasha Levin +Message-ID: <20260105140613.2598547-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 312ec2f0d9d1a5656f76d770bbf1d967e9289aa7 ] + +Make sure to unprepare the parent clock also on probe failures (e.g. +probe deferral). + +Fixes: a14bf98c045b ("ASoC: stm32: sai: fix possible circular locking") +Cc: stable@vger.kernel.org # 5.5 +Cc: Olivier Moysan +Signed-off-by: Johan Hovold +Reviewed-by: olivier moysan +Link: https://patch.msgid.link/20251124104908.15754-3-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/stm/stm32_sai_sub.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +--- a/sound/soc/stm/stm32_sai_sub.c ++++ b/sound/soc/stm/stm32_sai_sub.c +@@ -1483,14 +1483,21 @@ static int stm32_sai_sub_parse_of(struct + if (of_find_property(np, "#clock-cells", NULL)) { + ret = stm32_sai_add_mclk_provider(sai); + if (ret < 0) +- return ret; ++ goto err_unprepare_pclk; + } else { + sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); +- if (IS_ERR(sai->sai_mclk)) +- return PTR_ERR(sai->sai_mclk); ++ if (IS_ERR(sai->sai_mclk)) { ++ ret = PTR_ERR(sai->sai_mclk); ++ goto err_unprepare_pclk; ++ } + } + + return 0; ++ ++err_unprepare_pclk: ++ clk_unprepare(sai->pdata->pclk); ++ ++ return ret; + } + + static int stm32_sai_sub_probe(struct platform_device *pdev) +@@ -1534,26 +1541,33 @@ static int stm32_sai_sub_probe(struct pl + IRQF_SHARED, dev_name(&pdev->dev), sai); + if (ret) { + dev_err(&pdev->dev, "IRQ request returned %d\n", ret); +- return ret; ++ goto err_unprepare_pclk; + } + + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) + conf = &stm32_sai_pcm_config_spdif; + + ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); +- if (ret) +- return dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); ++ if (ret) { ++ ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); ++ goto err_unprepare_pclk; ++ } + + ret = snd_soc_register_component(&pdev->dev, &stm32_component, + &sai->cpu_dai_drv, 1); + if (ret) { + snd_dmaengine_pcm_unregister(&pdev->dev); +- return ret; ++ goto err_unprepare_pclk; + } + + pm_runtime_enable(&pdev->dev); + + return 0; ++ ++err_unprepare_pclk: ++ clk_unprepare(sai->pdata->pclk); ++ ++ return ret; + } + + static int stm32_sai_sub_remove(struct platform_device *pdev) diff --git a/queue-6.1/asoc-stm32-sai-fix-of-node-leak-on-probe.patch b/queue-6.1/asoc-stm32-sai-fix-of-node-leak-on-probe.patch new file mode 100644 index 0000000000..263f0e07d8 --- /dev/null +++ b/queue-6.1/asoc-stm32-sai-fix-of-node-leak-on-probe.patch @@ -0,0 +1,149 @@ +From stable+bounces-204821-greg=kroah.com@vger.kernel.org Mon Jan 5 15:55:49 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 09:51:35 -0500 +Subject: ASoC: stm32: sai: fix OF node leak on probe +To: stable@vger.kernel.org +Cc: Johan Hovold , Olivier Moysan , olivier moysan , Mark Brown , Sasha Levin +Message-ID: <20260105145135.2613585-5-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 23261f0de09427367e99f39f588e31e2856a690e ] + +The reference taken to the sync provider OF node when probing the +platform device is currently only dropped if the set_sync() callback +fails during DAI probe. + +Make sure to drop the reference on platform probe failures (e.g. probe +deferral) and on driver unbind. + +This also avoids a potential use-after-free in case the DAI is ever +reprobed without first rebinding the platform driver. + +Fixes: 5914d285f6b7 ("ASoC: stm32: sai: Add synchronization support") +Fixes: d4180b4c02e7 ("ASoC: stm32: sai: fix set_sync service") +Cc: Olivier Moysan +Cc: stable@vger.kernel.org # 4.16: d4180b4c02e7 +Signed-off-by: Johan Hovold +Reviewed-by: olivier moysan +Link: https://patch.msgid.link/20251124104908.15754-4-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/stm/stm32_sai.c | 12 +++--------- + sound/soc/stm/stm32_sai_sub.c | 23 ++++++++++++++++------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +--- a/sound/soc/stm/stm32_sai.c ++++ b/sound/soc/stm/stm32_sai.c +@@ -122,7 +122,6 @@ static int stm32_sai_set_sync(struct stm + if (!pdev) { + dev_err(&sai_client->pdev->dev, + "Device not found for node %pOFn\n", np_provider); +- of_node_put(np_provider); + return -ENODEV; + } + +@@ -131,21 +130,16 @@ static int stm32_sai_set_sync(struct stm + if (!sai_provider) { + dev_err(&sai_client->pdev->dev, + "SAI sync provider data not found\n"); +- ret = -EINVAL; +- goto error; ++ return -EINVAL; + } + + /* Configure sync client */ + ret = stm32_sai_sync_conf_client(sai_client, synci); + if (ret < 0) +- goto error; ++ return ret; + + /* Configure sync provider */ +- ret = stm32_sai_sync_conf_provider(sai_provider, synco); +- +-error: +- of_node_put(np_provider); +- return ret; ++ return stm32_sai_sync_conf_provider(sai_provider, synco); + } + + static int stm32_sai_probe(struct platform_device *pdev) +--- a/sound/soc/stm/stm32_sai_sub.c ++++ b/sound/soc/stm/stm32_sai_sub.c +@@ -1435,7 +1435,8 @@ static int stm32_sai_sub_parse_of(struct + dev_err(&pdev->dev, + "External synchro not supported\n"); + of_node_put(args.np); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_put_sync_provider; + } + sai->sync = SAI_SYNC_EXTERNAL; + +@@ -1444,7 +1445,8 @@ static int stm32_sai_sub_parse_of(struct + (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) { + dev_err(&pdev->dev, "Wrong SAI index\n"); + of_node_put(args.np); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_put_sync_provider; + } + + if (of_property_match_string(args.np, "compatible", +@@ -1458,7 +1460,8 @@ static int stm32_sai_sub_parse_of(struct + if (!sai->synco) { + dev_err(&pdev->dev, "Unknown SAI sub-block\n"); + of_node_put(args.np); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_put_sync_provider; + } + } + +@@ -1468,13 +1471,15 @@ static int stm32_sai_sub_parse_of(struct + + of_node_put(args.np); + sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); +- if (IS_ERR(sai->sai_ck)) +- return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), +- "Missing kernel clock sai_ck\n"); ++ if (IS_ERR(sai->sai_ck)) { ++ ret = dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), ++ "Missing kernel clock sai_ck\n"); ++ goto err_put_sync_provider; ++ } + + ret = clk_prepare(sai->pdata->pclk); + if (ret < 0) +- return ret; ++ goto err_put_sync_provider; + + if (STM_SAI_IS_F4(sai->pdata)) + return 0; +@@ -1496,6 +1501,8 @@ static int stm32_sai_sub_parse_of(struct + + err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); ++err_put_sync_provider: ++ of_node_put(sai->np_sync_provider); + + return ret; + } +@@ -1566,6 +1573,7 @@ static int stm32_sai_sub_probe(struct pl + + err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); ++ of_node_put(sai->np_sync_provider); + + return ret; + } +@@ -1578,6 +1586,7 @@ static void stm32_sai_sub_remove(struct + snd_dmaengine_pcm_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); ++ of_node_put(sai->np_sync_provider); + } + + #ifdef CONFIG_PM_SLEEP diff --git a/queue-6.1/asoc-stm32-sai-use-the-devm_clk_get_optional-helper.patch b/queue-6.1/asoc-stm32-sai-use-the-devm_clk_get_optional-helper.patch new file mode 100644 index 0000000000..4e770fe380 --- /dev/null +++ b/queue-6.1/asoc-stm32-sai-use-the-devm_clk_get_optional-helper.patch @@ -0,0 +1,43 @@ +From stable+bounces-204803-greg=kroah.com@vger.kernel.org Mon Jan 5 15:06:20 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 09:06:12 -0500 +Subject: ASoC: stm32: sai: Use the devm_clk_get_optional() helper +To: stable@vger.kernel.org +Cc: Christophe JAILLET , Mark Brown , Sasha Levin +Message-ID: <20260105140613.2598547-1-sashal@kernel.org> + +From: Christophe JAILLET + +[ Upstream commit 374628fb668e50b42fe81f2a63af616182415bcd ] + +Use devm_clk_get_optional() instead of hand writing it. +This saves some LoC and improves the semantic. + +Signed-off-by: Christophe JAILLET +Link: https://lore.kernel.org/r/f7987f18dadf77bfa09969fd4c82d5a0f4e4e3b7.1684594838.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Mark Brown +Stable-dep-of: 312ec2f0d9d1 ("ASoC: stm32: sai: fix clk prepare imbalance on probe failure") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/stm/stm32_sai_sub.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +--- a/sound/soc/stm/stm32_sai_sub.c ++++ b/sound/soc/stm/stm32_sai_sub.c +@@ -1485,12 +1485,9 @@ static int stm32_sai_sub_parse_of(struct + if (ret < 0) + return ret; + } else { +- sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK"); +- if (IS_ERR(sai->sai_mclk)) { +- if (PTR_ERR(sai->sai_mclk) != -ENOENT) +- return PTR_ERR(sai->sai_mclk); +- sai->sai_mclk = NULL; +- } ++ sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); ++ if (IS_ERR(sai->sai_mclk)) ++ return PTR_ERR(sai->sai_mclk); + } + + return 0; diff --git a/queue-6.1/btrfs-don-t-log-conflicting-inode-if-it-s-a-dir-moved-in-the-current-transaction.patch b/queue-6.1/btrfs-don-t-log-conflicting-inode-if-it-s-a-dir-moved-in-the-current-transaction.patch new file mode 100644 index 0000000000..edfb0c61b6 --- /dev/null +++ b/queue-6.1/btrfs-don-t-log-conflicting-inode-if-it-s-a-dir-moved-in-the-current-transaction.patch @@ -0,0 +1,274 @@ +From stable+bounces-204368-greg=kroah.com@vger.kernel.org Wed Dec 31 17:12:11 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 11:11:55 -0500 +Subject: btrfs: don't log conflicting inode if it's a dir moved in the current transaction +To: stable@vger.kernel.org +Cc: Filipe Manana , Vyacheslav Kovalevsky , David Sterba , Sasha Levin +Message-ID: <20251231161155.3221875-1-sashal@kernel.org> + +From: Filipe Manana + +[ Upstream commit 266273eaf4d99475f1ae57f687b3e42bc71ec6f0 ] + +We can't log a conflicting inode if it's a directory and it was moved +from one parent directory to another parent directory in the current +transaction, as this can result an attempt to have a directory with +two hard links during log replay, one for the old parent directory and +another for the new parent directory. + +The following scenario triggers that issue: + +1) We have directories "dir1" and "dir2" created in a past transaction. + Directory "dir1" has inode A as its parent directory; + +2) We move "dir1" to some other directory; + +3) We create a file with the name "dir1" in directory inode A; + +4) We fsync the new file. This results in logging the inode of the new file + and the inode for the directory "dir1" that was previously moved in the + current transaction. So the log tree has the INODE_REF item for the + new location of "dir1"; + +5) We move the new file to some other directory. This results in updating + the log tree to included the new INODE_REF for the new location of the + file and removes the INODE_REF for the old location. This happens + during the rename when we call btrfs_log_new_name(); + +6) We fsync the file, and that persists the log tree changes done in the + previous step (btrfs_log_new_name() only updates the log tree in + memory); + +7) We have a power failure; + +8) Next time the fs is mounted, log replay happens and when processing + the inode for directory "dir1" we find a new INODE_REF and add that + link, but we don't remove the old link of the inode since we have + not logged the old parent directory of the directory inode "dir1". + +As a result after log replay finishes when we trigger writeback of the +subvolume tree's extent buffers, the tree check will detect that we have +a directory a hard link count of 2 and we get a mount failure. +The errors and stack traces reported in dmesg/syslog are like this: + + [ 3845.729764] BTRFS info (device dm-0): start tree-log replay + [ 3845.730304] page: refcount:3 mapcount:0 mapping:000000005c8a3027 index:0x1d00 pfn:0x11510c + [ 3845.731236] memcg:ffff9264c02f4e00 + [ 3845.731751] aops:btree_aops [btrfs] ino:1 + [ 3845.732300] flags: 0x17fffc00000400a(uptodate|private|writeback|node=0|zone=2|lastcpupid=0x1ffff) + [ 3845.733346] raw: 017fffc00000400a 0000000000000000 dead000000000122 ffff9264d978aea8 + [ 3845.734265] raw: 0000000000001d00 ffff92650e6d4738 00000003ffffffff ffff9264c02f4e00 + [ 3845.735305] page dumped because: eb page dump + [ 3845.735981] BTRFS critical (device dm-0): corrupt leaf: root=5 block=30408704 slot=6 ino=257, invalid nlink: has 2 expect no more than 1 for dir + [ 3845.737786] BTRFS info (device dm-0): leaf 30408704 gen 10 total ptrs 17 free space 14881 owner 5 + [ 3845.737789] BTRFS info (device dm-0): refs 4 lock_owner 0 current 30701 + [ 3845.737792] item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 + [ 3845.737794] inode generation 3 transid 9 size 16 nbytes 16384 + [ 3845.737795] block group 0 mode 40755 links 1 uid 0 gid 0 + [ 3845.737797] rdev 0 sequence 2 flags 0x0 + [ 3845.737798] atime 1764259517.0 + [ 3845.737800] ctime 1764259517.572889464 + [ 3845.737801] mtime 1764259517.572889464 + [ 3845.737802] otime 1764259517.0 + [ 3845.737803] item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 + [ 3845.737805] index 0 name_len 2 + [ 3845.737807] item 2 key (256 DIR_ITEM 2363071922) itemoff 16077 itemsize 34 + [ 3845.737808] location key (257 1 0) type 2 + [ 3845.737810] transid 9 data_len 0 name_len 4 + [ 3845.737811] item 3 key (256 DIR_ITEM 2676584006) itemoff 16043 itemsize 34 + [ 3845.737813] location key (258 1 0) type 2 + [ 3845.737814] transid 9 data_len 0 name_len 4 + [ 3845.737815] item 4 key (256 DIR_INDEX 2) itemoff 16009 itemsize 34 + [ 3845.737816] location key (257 1 0) type 2 + [ 3845.737818] transid 9 data_len 0 name_len 4 + [ 3845.737819] item 5 key (256 DIR_INDEX 3) itemoff 15975 itemsize 34 + [ 3845.737820] location key (258 1 0) type 2 + [ 3845.737821] transid 9 data_len 0 name_len 4 + [ 3845.737822] item 6 key (257 INODE_ITEM 0) itemoff 15815 itemsize 160 + [ 3845.737824] inode generation 9 transid 10 size 6 nbytes 0 + [ 3845.737825] block group 0 mode 40755 links 2 uid 0 gid 0 + [ 3845.737826] rdev 0 sequence 1 flags 0x0 + [ 3845.737827] atime 1764259517.572889464 + [ 3845.737828] ctime 1764259517.572889464 + [ 3845.737830] mtime 1764259517.572889464 + [ 3845.737831] otime 1764259517.572889464 + [ 3845.737832] item 7 key (257 INODE_REF 256) itemoff 15801 itemsize 14 + [ 3845.737833] index 2 name_len 4 + [ 3845.737834] item 8 key (257 INODE_REF 258) itemoff 15787 itemsize 14 + [ 3845.737836] index 2 name_len 4 + [ 3845.737837] item 9 key (257 DIR_ITEM 2507850652) itemoff 15754 itemsize 33 + [ 3845.737838] location key (259 1 0) type 1 + [ 3845.737839] transid 10 data_len 0 name_len 3 + [ 3845.737840] item 10 key (257 DIR_INDEX 2) itemoff 15721 itemsize 33 + [ 3845.737842] location key (259 1 0) type 1 + [ 3845.737843] transid 10 data_len 0 name_len 3 + [ 3845.737844] item 11 key (258 INODE_ITEM 0) itemoff 15561 itemsize 160 + [ 3845.737846] inode generation 9 transid 10 size 8 nbytes 0 + [ 3845.737847] block group 0 mode 40755 links 1 uid 0 gid 0 + [ 3845.737848] rdev 0 sequence 1 flags 0x0 + [ 3845.737849] atime 1764259517.572889464 + [ 3845.737850] ctime 1764259517.572889464 + [ 3845.737851] mtime 1764259517.572889464 + [ 3845.737852] otime 1764259517.572889464 + [ 3845.737853] item 12 key (258 INODE_REF 256) itemoff 15547 itemsize 14 + [ 3845.737855] index 3 name_len 4 + [ 3845.737856] item 13 key (258 DIR_ITEM 1843588421) itemoff 15513 itemsize 34 + [ 3845.737857] location key (257 1 0) type 2 + [ 3845.737858] transid 10 data_len 0 name_len 4 + [ 3845.737860] item 14 key (258 DIR_INDEX 2) itemoff 15479 itemsize 34 + [ 3845.737861] location key (257 1 0) type 2 + [ 3845.737862] transid 10 data_len 0 name_len 4 + [ 3845.737863] item 15 key (259 INODE_ITEM 0) itemoff 15319 itemsize 160 + [ 3845.737865] inode generation 10 transid 10 size 0 nbytes 0 + [ 3845.737866] block group 0 mode 100600 links 1 uid 0 gid 0 + [ 3845.737867] rdev 0 sequence 2 flags 0x0 + [ 3845.737868] atime 1764259517.580874966 + [ 3845.737869] ctime 1764259517.586121869 + [ 3845.737870] mtime 1764259517.580874966 + [ 3845.737872] otime 1764259517.580874966 + [ 3845.737873] item 16 key (259 INODE_REF 257) itemoff 15306 itemsize 13 + [ 3845.737874] index 2 name_len 3 + [ 3845.737875] BTRFS error (device dm-0): block=30408704 write time tree block corruption detected + [ 3845.739448] ------------[ cut here ]------------ + [ 3845.740092] WARNING: CPU: 5 PID: 30701 at fs/btrfs/disk-io.c:335 btree_csum_one_bio+0x25a/0x270 [btrfs] + [ 3845.741439] Modules linked in: btrfs dm_flakey crc32c_cryptoapi (...) + [ 3845.750626] CPU: 5 UID: 0 PID: 30701 Comm: mount Tainted: G W 6.18.0-rc6-btrfs-next-218+ #1 PREEMPT(full) + [ 3845.752414] Tainted: [W]=WARN + [ 3845.752828] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [ 3845.754499] RIP: 0010:btree_csum_one_bio+0x25a/0x270 [btrfs] + [ 3845.755460] Code: 31 f6 48 89 (...) + [ 3845.758685] RSP: 0018:ffffa8d9c5677678 EFLAGS: 00010246 + [ 3845.759450] RAX: 0000000000000000 RBX: ffff92650e6d4738 RCX: 0000000000000000 + [ 3845.760309] RDX: 0000000000000000 RSI: ffffffff9aab45b9 RDI: ffff9264c4748000 + [ 3845.761239] RBP: ffff9264d4324000 R08: 0000000000000000 R09: ffffa8d9c5677468 + [ 3845.762607] R10: ffff926bdc1fffa8 R11: 0000000000000003 R12: ffffa8d9c5677680 + [ 3845.764099] R13: 0000000000004000 R14: ffff9264dd624000 R15: ffff9264d978aba8 + [ 3845.765094] FS: 00007f751fa5a840(0000) GS:ffff926c42a82000(0000) knlGS:0000000000000000 + [ 3845.766226] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [ 3845.766970] CR2: 0000558df1815380 CR3: 000000010ed88003 CR4: 0000000000370ef0 + [ 3845.768009] Call Trace: + [ 3845.768392] + [ 3845.768714] btrfs_submit_bbio+0x6ee/0x7f0 [btrfs] + [ 3845.769640] ? write_one_eb+0x28e/0x340 [btrfs] + [ 3845.770588] btree_write_cache_pages+0x2f0/0x550 [btrfs] + [ 3845.771286] ? alloc_extent_state+0x19/0x100 [btrfs] + [ 3845.771967] ? merge_next_state+0x1a/0x90 [btrfs] + [ 3845.772586] ? set_extent_bit+0x233/0x8b0 [btrfs] + [ 3845.773198] ? xas_load+0x9/0xc0 + [ 3845.773589] ? xas_find+0x14d/0x1a0 + [ 3845.773969] do_writepages+0xc6/0x160 + [ 3845.774367] filemap_fdatawrite_wbc+0x48/0x60 + [ 3845.775003] __filemap_fdatawrite_range+0x5b/0x80 + [ 3845.775902] btrfs_write_marked_extents+0x61/0x170 [btrfs] + [ 3845.776707] btrfs_write_and_wait_transaction+0x4e/0xc0 [btrfs] + [ 3845.777379] ? _raw_spin_unlock_irqrestore+0x23/0x40 + [ 3845.777923] btrfs_commit_transaction+0x5ea/0xd20 [btrfs] + [ 3845.778551] ? _raw_spin_unlock+0x15/0x30 + [ 3845.778986] ? release_extent_buffer+0x34/0x160 [btrfs] + [ 3845.779659] btrfs_recover_log_trees+0x7a3/0x7c0 [btrfs] + [ 3845.780416] ? __pfx_replay_one_buffer+0x10/0x10 [btrfs] + [ 3845.781499] open_ctree+0x10bb/0x15f0 [btrfs] + [ 3845.782194] btrfs_get_tree.cold+0xb/0x16c [btrfs] + [ 3845.782764] ? fscontext_read+0x15c/0x180 + [ 3845.783202] ? rw_verify_area+0x50/0x180 + [ 3845.783667] vfs_get_tree+0x25/0xd0 + [ 3845.784047] vfs_cmd_create+0x59/0xe0 + [ 3845.784458] __do_sys_fsconfig+0x4f6/0x6b0 + [ 3845.784914] do_syscall_64+0x50/0x1220 + [ 3845.785340] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [ 3845.785980] RIP: 0033:0x7f751fc7f4aa + [ 3845.786759] Code: 73 01 c3 48 (...) + [ 3845.789951] RSP: 002b:00007ffcdba45dc8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af + [ 3845.791402] RAX: ffffffffffffffda RBX: 000055ccc8291c20 RCX: 00007f751fc7f4aa + [ 3845.792688] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003 + [ 3845.794308] RBP: 000055ccc8292120 R08: 0000000000000000 R09: 0000000000000000 + [ 3845.795829] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + [ 3845.797183] R13: 00007f751fe11580 R14: 00007f751fe1326c R15: 00007f751fdf8a23 + [ 3845.798633] + [ 3845.799067] ---[ end trace 0000000000000000 ]--- + [ 3845.800215] BTRFS: error (device dm-0) in btrfs_commit_transaction:2553: errno=-5 IO failure (Error while writing out transaction) + [ 3845.801860] BTRFS warning (device dm-0 state E): Skipping commit of aborted transaction. + [ 3845.802815] BTRFS error (device dm-0 state EA): Transaction aborted (error -5) + [ 3845.803728] BTRFS: error (device dm-0 state EA) in cleanup_transaction:2036: errno=-5 IO failure + [ 3845.805374] BTRFS: error (device dm-0 state EA) in btrfs_replay_log:2083: errno=-5 IO failure (Failed to recover log tree) + [ 3845.807919] BTRFS error (device dm-0 state EA): open_ctree failed: -5 + +Fix this by never logging a conflicting inode that is a directory and was +moved in the current transaction (its last_unlink_trans equals the current +transaction) and instead fallback to a transaction commit. + +A test case for fstests will follow soon. + +Reported-by: Vyacheslav Kovalevsky +Link: https://lore.kernel.org/linux-btrfs/7bbc9419-5c56-450a-b5a0-efeae7457113@gmail.com/ +CC: stable@vger.kernel.org # 6.1+ +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +[ wrapped inode parameter with BTRFS_I() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/tree-log.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -5638,6 +5638,33 @@ static int conflicting_inode_is_dir(stru + return ret; + } + ++static bool can_log_conflicting_inode(const struct btrfs_trans_handle *trans, ++ const struct btrfs_inode *inode) ++{ ++ if (!S_ISDIR(inode->vfs_inode.i_mode)) ++ return true; ++ ++ if (inode->last_unlink_trans < trans->transid) ++ return true; ++ ++ /* ++ * If this is a directory and its unlink_trans is not from a past ++ * transaction then we must fallback to a transaction commit in order ++ * to avoid getting a directory with 2 hard links after log replay. ++ * ++ * This happens if a directory A is renamed, moved from one parent ++ * directory to another one, a new file is created in the old parent ++ * directory with the old name of our directory A, the new file is ++ * fsynced, then we moved the new file to some other parent directory ++ * and fsync again the new file. This results in a log tree where we ++ * logged that directory A existed, with the INODE_REF item for the ++ * new location but without having logged its old parent inode, so ++ * that on log replay we add a new link for the new location but the ++ * old link remains, resulting in a link count of 2. ++ */ ++ return false; ++} ++ + static int add_conflicting_inode(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, +@@ -5743,6 +5770,11 @@ static int add_conflicting_inode(struct + return 0; + } + ++ if (!can_log_conflicting_inode(trans, BTRFS_I(inode))) { ++ btrfs_add_delayed_iput(inode); ++ return BTRFS_LOG_FORCE_COMMIT; ++ } ++ + btrfs_add_delayed_iput(inode); + + ino_elem = kmalloc(sizeof(*ino_elem), GFP_NOFS); +@@ -5808,6 +5840,12 @@ static int log_conflicting_inodes(struct + break; + } + ++ if (!can_log_conflicting_inode(trans, BTRFS_I(inode))) { ++ btrfs_add_delayed_iput(inode); ++ ret = BTRFS_LOG_FORCE_COMMIT; ++ break; ++ } ++ + /* + * Always log the directory, we cannot make this + * conditional on need_log_inode() because the directory diff --git a/queue-6.1/btrfs-don-t-rewrite-ret-from-inode_permission.patch b/queue-6.1/btrfs-don-t-rewrite-ret-from-inode_permission.patch new file mode 100644 index 0000000000..e34632d676 --- /dev/null +++ b/queue-6.1/btrfs-don-t-rewrite-ret-from-inode_permission.patch @@ -0,0 +1,51 @@ +From stable+bounces-204141-greg=kroah.com@vger.kernel.org Mon Dec 29 23:04:20 2025 +From: Sasha Levin +Date: Mon, 29 Dec 2025 17:03:37 -0500 +Subject: btrfs: don't rewrite ret from inode_permission +To: stable@vger.kernel.org +Cc: Josef Bacik , Johannes Thumshirn , Daniel Vacek , David Sterba , Sasha Levin +Message-ID: <20251229220337.1736680-1-sashal@kernel.org> + +From: Josef Bacik + +[ Upstream commit 0185c2292c600993199bc6b1f342ad47a9e8c678 ] + +In our user safe ino resolve ioctl we'll just turn any ret into -EACCES +from inode_permission(). This is redundant, and could potentially be +wrong if we had an ENOMEM in the security layer or some such other +error, so simply return the actual return value. + +Note: The patch was taken from v5 of fscrypt patchset +(https://lore.kernel.org/linux-btrfs/cover.1706116485.git.josef@toxicpanda.com/) +which was handled over time by various people: Omar Sandoval, Sweet Tea +Dorminy, Josef Bacik. + +Fixes: 23d0b79dfaed ("btrfs: Add unprivileged version of ino_lookup ioctl") +CC: stable@vger.kernel.org # 5.4+ +Reviewed-by: Johannes Thumshirn +Signed-off-by: Josef Bacik +Signed-off-by: Daniel Vacek +Reviewed-by: David Sterba +[ add note ] +Signed-off-by: David Sterba +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/ioctl.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -2897,10 +2897,8 @@ static int btrfs_search_path_in_tree_use + ret = inode_permission(mnt_userns, temp_inode, + MAY_READ | MAY_EXEC); + iput(temp_inode); +- if (ret) { +- ret = -EACCES; ++ if (ret) + goto out_put; +- } + + if (key.offset == upper_limit.objectid) + break; diff --git a/queue-6.1/can-gs_usb-gs_can_open-fix-error-handling.patch b/queue-6.1/can-gs_usb-gs_can_open-fix-error-handling.patch new file mode 100644 index 0000000000..02d54dff19 --- /dev/null +++ b/queue-6.1/can-gs_usb-gs_can_open-fix-error-handling.patch @@ -0,0 +1,48 @@ +From stable+bounces-203322-greg=kroah.com@vger.kernel.org Tue Dec 23 18:36:21 2025 +From: Sasha Levin +Date: Tue, 23 Dec 2025 12:33:44 -0500 +Subject: can: gs_usb: gs_can_open(): fix error handling +To: stable@vger.kernel.org +Cc: Marc Kleine-Budde , Sasha Levin +Message-ID: <20251223173344.2929930-1-sashal@kernel.org> + +From: Marc Kleine-Budde + +[ Upstream commit 3e54d3b4a8437b6783d4145c86962a2aa51022f3 ] + +Commit 2603be9e8167 ("can: gs_usb: gs_can_open(): improve error handling") +added missing error handling to the gs_can_open() function. + +The driver uses 2 USB anchors to track the allocated URBs: the TX URBs in +struct gs_can::tx_submitted for each netdev and the RX URBs in struct +gs_usb::rx_submitted for the USB device. gs_can_open() allocates the RX +URBs, while TX URBs are allocated during gs_can_start_xmit(). + +The cleanup in gs_can_open() kills all anchored dev->tx_submitted +URBs (which is not necessary since the netdev is not yet registered), but +misses the parent->rx_submitted URBs. + +Fix the problem by killing the rx_submitted instead of the tx_submitted. + +Fixes: 2603be9e8167 ("can: gs_usb: gs_can_open(): improve error handling") +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251210-gs_usb-fix-error-handling-v1-1-d6a5a03f10bb@pengutronix.de +Signed-off-by: Marc Kleine-Budde +[ adapted error handling for simpler code structure without timestamp stop functionality ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/can/usb/gs_usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/can/usb/gs_usb.c ++++ b/drivers/net/can/usb/gs_usb.c +@@ -985,7 +985,7 @@ out_usb_free_urb: + usb_free_urb(urb); + out_usb_kill_anchored_urbs: + if (!parent->active_channels) +- usb_kill_anchored_urbs(&dev->tx_submitted); ++ usb_kill_anchored_urbs(&parent->rx_submitted); + + close_candev(netdev); + diff --git a/queue-6.1/crypto-af_alg-zero-initialize-memory-allocated-via-sock_kmalloc.patch b/queue-6.1/crypto-af_alg-zero-initialize-memory-allocated-via-sock_kmalloc.patch new file mode 100644 index 0000000000..61eb344ac7 --- /dev/null +++ b/queue-6.1/crypto-af_alg-zero-initialize-memory-allocated-via-sock_kmalloc.patch @@ -0,0 +1,102 @@ +From stable+bounces-204380-greg=kroah.com@vger.kernel.org Wed Dec 31 19:35:35 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 13:35:24 -0500 +Subject: crypto: af_alg - zero initialize memory allocated via sock_kmalloc +To: stable@vger.kernel.org +Cc: Shivani Agarwal , Herbert Xu , Sasha Levin +Message-ID: <20251231183524.3368512-1-sashal@kernel.org> + +From: Shivani Agarwal + +[ Upstream commit 6f6e309328d53a10c0fe1f77dec2db73373179b6 ] + +Several crypto user API contexts and requests allocated with +sock_kmalloc() were left uninitialized, relying on callers to +set fields explicitly. This resulted in the use of uninitialized +data in certain error paths or when new fields are added in the +future. + +The ACVP patches also contain two user-space interface files: +algif_kpp.c and algif_akcipher.c. These too rely on proper +initialization of their context structures. + +A particular issue has been observed with the newly added +'inflight' variable introduced in af_alg_ctx by commit: + + 67b164a871af ("crypto: af_alg - Disallow multiple in-flight AIO requests") + +Because the context is not memset to zero after allocation, +the inflight variable has contained garbage values. As a result, +af_alg_alloc_areq() has incorrectly returned -EBUSY randomly when +the garbage value was interpreted as true: + + https://github.com/gregkh/linux/blame/master/crypto/af_alg.c#L1209 + +The check directly tests ctx->inflight without explicitly +comparing against true/false. Since inflight is only ever set to +true or false later, an uninitialized value has triggered +-EBUSY failures. Zero-initializing memory allocated with +sock_kmalloc() ensures inflight and other fields start in a known +state, removing random issues caused by uninitialized data. + +Fixes: fe869cdb89c9 ("crypto: algif_hash - User-space interface for hash operations") +Fixes: 5afdfd22e6ba ("crypto: algif_rng - add random number generator support") +Fixes: 2d97591ef43d ("crypto: af_alg - consolidation of duplicate code") +Fixes: 67b164a871af ("crypto: af_alg - Disallow multiple in-flight AIO requests") +Cc: stable@vger.kernel.org +Signed-off-by: Shivani Agarwal +Signed-off-by: Herbert Xu +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + crypto/af_alg.c | 5 ++--- + crypto/algif_hash.c | 3 +-- + crypto/algif_rng.c | 3 +-- + 3 files changed, 4 insertions(+), 7 deletions(-) + +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -1108,14 +1108,13 @@ struct af_alg_async_req *af_alg_alloc_ar + if (unlikely(!areq)) + return ERR_PTR(-ENOMEM); + ++ memset(areq, 0, areqlen); ++ + ctx->inflight = true; + + areq->areqlen = areqlen; + areq->sk = sk; +- areq->last_rsgl = NULL; + INIT_LIST_HEAD(&areq->rsgl_list); +- areq->tsgl = NULL; +- areq->tsgl_entries = 0; + + return areq; + } +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -424,9 +424,8 @@ static int hash_accept_parent_nokey(void + if (!ctx) + return -ENOMEM; + +- ctx->result = NULL; ++ memset(ctx, 0, len); + ctx->len = len; +- ctx->more = false; + crypto_init_wait(&ctx->wait); + + ask->private = ctx; +--- a/crypto/algif_rng.c ++++ b/crypto/algif_rng.c +@@ -250,9 +250,8 @@ static int rng_accept_parent(void *priva + if (!ctx) + return -ENOMEM; + ++ memset(ctx, 0, len); + ctx->len = len; +- ctx->addtl = NULL; +- ctx->addtl_len = 0; + + /* + * No seeding done at that point -- if multiple accepts are diff --git a/queue-6.1/drm-amdgpu-add-missing-lock-to-amdgpu_ttm_access_memory_sdma.patch b/queue-6.1/drm-amdgpu-add-missing-lock-to-amdgpu_ttm_access_memory_sdma.patch new file mode 100644 index 0000000000..35cd14e0d0 --- /dev/null +++ b/queue-6.1/drm-amdgpu-add-missing-lock-to-amdgpu_ttm_access_memory_sdma.patch @@ -0,0 +1,44 @@ +From stable+bounces-206134-greg=kroah.com@vger.kernel.org Wed Jan 7 13:00:17 2026 +From: Sasha Levin +Date: Wed, 7 Jan 2026 06:54:26 -0500 +Subject: drm/amdgpu: add missing lock to amdgpu_ttm_access_memory_sdma +To: stable@vger.kernel.org +Cc: "Pierre-Eric Pelloux-Prayer" , "Christian König" , "Alex Deucher" , "Sasha Levin" +Message-ID: <20260107115426.3985494-2-sashal@kernel.org> + +From: Pierre-Eric Pelloux-Prayer + +[ Upstream commit 4fa944255be521b1bbd9780383f77206303a3a5c ] + +Users of ttm entities need to hold the gtt_window_lock before using them +to guarantee proper ordering of jobs. + +Cc: stable@vger.kernel.org +Fixes: cb5cc4f573e1 ("drm/amdgpu: improve debug VRAM access performance using sdma") +Signed-off-by: Pierre-Eric Pelloux-Prayer +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -1425,6 +1425,7 @@ static int amdgpu_ttm_access_memory_sdma + if (r) + goto out; + ++ mutex_lock(&adev->mman.gtt_window_lock); + amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm); + src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + + src_mm.start; +@@ -1439,6 +1440,7 @@ static int amdgpu_ttm_access_memory_sdma + WARN_ON(job->ibs[0].length_dw > num_dw); + + fence = amdgpu_job_submit(job); ++ mutex_unlock(&adev->mman.gtt_window_lock); + + if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout)) + r = -ETIMEDOUT; diff --git a/queue-6.1/drm-amdgpu-cleanup-scheduler-job-initialization-v2.patch b/queue-6.1/drm-amdgpu-cleanup-scheduler-job-initialization-v2.patch new file mode 100644 index 0000000000..55d2e09c2c --- /dev/null +++ b/queue-6.1/drm-amdgpu-cleanup-scheduler-job-initialization-v2.patch @@ -0,0 +1,712 @@ +From stable+bounces-206133-greg=kroah.com@vger.kernel.org Wed Jan 7 12:54:40 2026 +From: Sasha Levin +Date: Wed, 7 Jan 2026 06:54:25 -0500 +Subject: drm/amdgpu: cleanup scheduler job initialization v2 +To: stable@vger.kernel.org +Cc: "Christian König" , "Luben Tuikov" , "Sasha Levin" +Message-ID: <20260107115426.3985494-1-sashal@kernel.org> + +From: Christian König + +[ Upstream commit f7d66fb2ea43a3016e78a700a2ca6c77a74579f9 ] + +Init the DRM scheduler base class while allocating the job. + +This makes the whole handling much more cleaner. + +v2: fix coding style + +Signed-off-by: Christian König +Reviewed-by: Luben Tuikov +Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-7-christian.koenig@amd.com +Stable-dep-of: 4fa944255be5 ("drm/amdgpu: add missing lock to amdgpu_ttm_access_memory_sdma") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 8 --- + drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 44 ++++++++++---------- + drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 14 +++--- + drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c | 7 +-- + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 56 +++++++++---------------- + drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 9 +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 13 +++-- + drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 22 +++++----- + drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c | 61 ++++++++++++++-------------- + drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 12 +---- + drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 8 +-- + drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 12 ++--- + drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 17 ++----- + 14 files changed, 135 insertions(+), 150 deletions(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -673,7 +673,7 @@ int amdgpu_amdkfd_submit_ib(struct amdgp + goto err; + } + +- ret = amdgpu_job_alloc(adev, 1, &job, NULL); ++ ret = amdgpu_job_alloc(adev, NULL, NULL, NULL, 1, &job); + if (ret) + goto err; + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -285,12 +285,8 @@ static int amdgpu_cs_pass1(struct amdgpu + } + + for (i = 0; i < p->gang_size; ++i) { +- ret = amdgpu_job_alloc(p->adev, num_ibs[i], &p->jobs[i], vm); +- if (ret) +- goto free_all_kdata; +- +- ret = drm_sched_job_init(&p->jobs[i]->base, p->entities[i], +- &fpriv->vm); ++ ret = amdgpu_job_alloc(p->adev, vm, p->entities[i], vm, ++ num_ibs[i], &p->jobs[i]); + if (ret) + goto free_all_kdata; + } +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +@@ -88,8 +88,9 @@ exit: + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +-int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, +- struct amdgpu_job **job, struct amdgpu_vm *vm) ++int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, ++ struct drm_sched_entity *entity, void *owner, ++ unsigned int num_ibs, struct amdgpu_job **job) + { + if (num_ibs == 0) + return -EINVAL; +@@ -110,23 +111,30 @@ int amdgpu_job_alloc(struct amdgpu_devic + (*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter); + (*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET; + +- return 0; ++ if (!entity) ++ return 0; ++ ++ return drm_sched_job_init(&(*job)->base, entity, owner); + } + +-int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, +- enum amdgpu_ib_pool_type pool_type, +- struct amdgpu_job **job) ++int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, ++ struct drm_sched_entity *entity, void *owner, ++ size_t size, enum amdgpu_ib_pool_type pool_type, ++ struct amdgpu_job **job) + { + int r; + +- r = amdgpu_job_alloc(adev, 1, job, NULL); ++ r = amdgpu_job_alloc(adev, NULL, entity, owner, 1, job); + if (r) + return r; + + (*job)->num_ibs = 1; + r = amdgpu_ib_get(adev, NULL, size, pool_type, &(*job)->ibs[0]); +- if (r) ++ if (r) { ++ if (entity) ++ drm_sched_job_cleanup(&(*job)->base); + kfree(*job); ++ } + + return r; + } +@@ -199,6 +207,9 @@ void amdgpu_job_set_gang_leader(struct a + + void amdgpu_job_free(struct amdgpu_job *job) + { ++ if (job->base.entity) ++ drm_sched_job_cleanup(&job->base); ++ + amdgpu_job_free_resources(job); + amdgpu_sync_free(&job->sync); + amdgpu_sync_free(&job->sched_sync); +@@ -211,25 +222,16 @@ void amdgpu_job_free(struct amdgpu_job * + dma_fence_put(&job->hw_fence); + } + +-int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, +- void *owner, struct dma_fence **f) ++struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job) + { +- int r; +- +- if (!f) +- return -EINVAL; +- +- r = drm_sched_job_init(&job->base, entity, owner); +- if (r) +- return r; ++ struct dma_fence *f; + + drm_sched_job_arm(&job->base); +- +- *f = dma_fence_get(&job->base.s_fence->finished); ++ f = dma_fence_get(&job->base.s_fence->finished); + amdgpu_job_free_resources(job); + drm_sched_entity_push_job(&job->base); + +- return 0; ++ return f; + } + + int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +@@ -78,18 +78,20 @@ static inline struct amdgpu_ring *amdgpu + return to_amdgpu_ring(job->base.entity->rq->sched); + } + +-int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, +- struct amdgpu_job **job, struct amdgpu_vm *vm); +-int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, +- enum amdgpu_ib_pool_type pool, struct amdgpu_job **job); ++int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, ++ struct drm_sched_entity *entity, void *owner, ++ unsigned int num_ibs, struct amdgpu_job **job); ++int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, ++ struct drm_sched_entity *entity, void *owner, ++ size_t size, enum amdgpu_ib_pool_type pool_type, ++ struct amdgpu_job **job); + void amdgpu_job_set_resources(struct amdgpu_job *job, struct amdgpu_bo *gds, + struct amdgpu_bo *gws, struct amdgpu_bo *oa); + void amdgpu_job_free_resources(struct amdgpu_job *job); + void amdgpu_job_set_gang_leader(struct amdgpu_job *job, + struct amdgpu_job *leader); + void amdgpu_job_free(struct amdgpu_job *job); +-int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, +- void *owner, struct dma_fence **f); ++struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job); + int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, + struct dma_fence **fence); + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +@@ -152,14 +152,15 @@ static int amdgpu_jpeg_dec_set_reg(struc + const unsigned ib_size_dw = 16; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, ++ AMDGPU_IB_POOL_DIRECT, &job); + if (r) + return r; + + ib = &job->ibs[0]; + +- ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0); ++ ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, ++ PACKETJ_TYPE0); + ib->ptr[1] = 0xDEADBEEF; + for (i = 2; i < 16; i += 2) { + ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -189,7 +189,6 @@ static int amdgpu_ttm_map_buffer(struct + struct amdgpu_device *adev = ring->adev; + unsigned offset, num_pages, num_dw, num_bytes; + uint64_t src_addr, dst_addr; +- struct dma_fence *fence; + struct amdgpu_job *job; + void *cpu_addr; + uint64_t flags; +@@ -229,7 +228,9 @@ static int amdgpu_ttm_map_buffer(struct + num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); + num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE; + +- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes, ++ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ num_dw * 4 + num_bytes, + AMDGPU_IB_POOL_DELAYED, &job); + if (r) + return r; +@@ -269,18 +270,8 @@ static int amdgpu_ttm_map_buffer(struct + } + } + +- r = amdgpu_job_submit(job, &adev->mman.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, &fence); +- if (r) +- goto error_free; +- +- dma_fence_put(fence); +- +- return r; +- +-error_free: +- amdgpu_job_free(job); +- return r; ++ dma_fence_put(amdgpu_job_submit(job)); ++ return 0; + } + + /** +@@ -1402,7 +1393,8 @@ static void amdgpu_ttm_vram_mm_access(st + } + + static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo, +- unsigned long offset, void *buf, int len, int write) ++ unsigned long offset, void *buf, ++ int len, int write) + { + struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); + struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); +@@ -1426,26 +1418,27 @@ static int amdgpu_ttm_access_memory_sdma + memcpy(adev->mman.sdma_access_ptr, buf, len); + + num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); +- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, AMDGPU_IB_POOL_DELAYED, &job); ++ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ num_dw * 4, AMDGPU_IB_POOL_DELAYED, ++ &job); + if (r) + goto out; + + amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm); +- src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + src_mm.start; ++ src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + ++ src_mm.start; + dst_addr = amdgpu_bo_gpu_offset(adev->mman.sdma_access_bo); + if (write) + swap(src_addr, dst_addr); + +- amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr, PAGE_SIZE, false); ++ amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr, ++ PAGE_SIZE, false); + + amdgpu_ring_pad_ib(adev->mman.buffer_funcs_ring, &job->ibs[0]); + WARN_ON(job->ibs[0].length_dw > num_dw); + +- r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &fence); +- if (r) { +- amdgpu_job_free(job); +- goto out; +- } ++ fence = amdgpu_job_submit(job); + + if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout)) + r = -ETIMEDOUT; +@@ -1994,7 +1987,9 @@ static int amdgpu_ttm_prepare_job(struct + AMDGPU_IB_POOL_DELAYED; + int r; + +- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, pool, job); ++ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ num_dw * 4, pool, job); + if (r) + return r; + +@@ -2059,8 +2054,7 @@ int amdgpu_copy_buffer(struct amdgpu_rin + if (direct_submit) + r = amdgpu_job_submit_direct(job, ring, fence); + else +- r = amdgpu_job_submit(job, &adev->mman.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, fence); ++ *fence = amdgpu_job_submit(job); + if (r) + goto error_free; + +@@ -2105,16 +2099,8 @@ static int amdgpu_ttm_fill_mem(struct am + + amdgpu_ring_pad_ib(ring, &job->ibs[0]); + WARN_ON(job->ibs[0].length_dw > num_dw); +- r = amdgpu_job_submit(job, &adev->mman.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, fence); +- if (r) +- goto error_free; +- ++ *fence = amdgpu_job_submit(job); + return 0; +- +-error_free: +- amdgpu_job_free(job); +- return r; + } + + int amdgpu_fill_buffer(struct amdgpu_bo *bo, +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -1132,7 +1132,9 @@ static int amdgpu_uvd_send_msg(struct am + unsigned offset_idx = 0; + unsigned offset[3] = { UVD_BASE_SI, 0, 0 }; + +- r = amdgpu_job_alloc_with_ib(adev, 64, direct ? AMDGPU_IB_POOL_DIRECT : ++ r = amdgpu_job_alloc_with_ib(ring->adev, &adev->uvd.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ 64, direct ? AMDGPU_IB_POOL_DIRECT : + AMDGPU_IB_POOL_DELAYED, &job); + if (r) + return r; +@@ -1181,10 +1183,7 @@ static int amdgpu_uvd_send_msg(struct am + if (r) + goto err_free; + +- r = amdgpu_job_submit(job, &adev->uvd.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, &f); +- if (r) +- goto err_free; ++ f = amdgpu_job_submit(job); + } + + amdgpu_bo_reserve(bo, true); +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +@@ -450,8 +450,10 @@ static int amdgpu_vce_get_create_msg(str + uint64_t addr; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, ++ &job); + if (r) + return r; + +@@ -538,7 +540,9 @@ static int amdgpu_vce_get_destroy_msg(st + struct dma_fence *f = NULL; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, ++ r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ ib_size_dw * 4, + direct ? AMDGPU_IB_POOL_DIRECT : + AMDGPU_IB_POOL_DELAYED, &job); + if (r) +@@ -570,8 +574,7 @@ static int amdgpu_vce_get_destroy_msg(st + if (direct) + r = amdgpu_job_submit_direct(job, ring, &f); + else +- r = amdgpu_job_submit(job, &ring->adev->vce.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, &f); ++ f = amdgpu_job_submit(job); + if (r) + goto err; + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +@@ -627,15 +627,16 @@ static int amdgpu_vcn_dec_send_msg(struc + struct amdgpu_ib *ib_msg, + struct dma_fence **fence) + { ++ u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); + struct amdgpu_device *adev = ring->adev; + struct dma_fence *f = NULL; + struct amdgpu_job *job; + struct amdgpu_ib *ib; +- uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); + int i, r; + +- r = amdgpu_job_alloc_with_ib(adev, 64, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ++ 64, AMDGPU_IB_POOL_DIRECT, ++ &job); + if (r) + goto err; + +@@ -813,8 +814,9 @@ static int amdgpu_vcn_dec_sw_send_msg(st + if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + +- r = amdgpu_job_alloc_with_ib(adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ++ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, ++ &job); + if (r) + goto err; + +@@ -942,8 +944,9 @@ static int amdgpu_vcn_enc_get_create_msg + if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ++ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, ++ &job); + if (r) + return r; + +@@ -1008,8 +1011,9 @@ static int amdgpu_vcn_enc_get_destroy_ms + if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ++ ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, ++ &job); + if (r) + return r; + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +@@ -47,6 +47,32 @@ static int amdgpu_vm_sdma_map_table(stru + return r; + } + ++/* Allocate a new job for @count PTE updates */ ++static int amdgpu_vm_sdma_alloc_job(struct amdgpu_vm_update_params *p, ++ unsigned int count) ++{ ++ enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE ++ : AMDGPU_IB_POOL_DELAYED; ++ struct drm_sched_entity *entity = p->immediate ? &p->vm->immediate ++ : &p->vm->delayed; ++ unsigned int ndw; ++ int r; ++ ++ /* estimate how many dw we need */ ++ ndw = AMDGPU_VM_SDMA_MIN_NUM_DW; ++ if (p->pages_addr) ++ ndw += count * 2; ++ ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW); ++ ++ r = amdgpu_job_alloc_with_ib(p->adev, entity, AMDGPU_FENCE_OWNER_VM, ++ ndw * 4, pool, &p->job); ++ if (r) ++ return r; ++ ++ p->num_dw_left = ndw; ++ return 0; ++} ++ + /** + * amdgpu_vm_sdma_prepare - prepare SDMA command submission + * +@@ -61,17 +87,12 @@ static int amdgpu_vm_sdma_prepare(struct + struct dma_resv *resv, + enum amdgpu_sync_mode sync_mode) + { +- enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE +- : AMDGPU_IB_POOL_DELAYED; +- unsigned int ndw = AMDGPU_VM_SDMA_MIN_NUM_DW; + int r; + +- r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool, &p->job); ++ r = amdgpu_vm_sdma_alloc_job(p, 0); + if (r) + return r; + +- p->num_dw_left = ndw; +- + if (!resv) + return 0; + +@@ -91,20 +112,16 @@ static int amdgpu_vm_sdma_commit(struct + struct dma_fence **fence) + { + struct amdgpu_ib *ib = p->job->ibs; +- struct drm_sched_entity *entity; + struct amdgpu_ring *ring; + struct dma_fence *f; +- int r; + +- entity = p->immediate ? &p->vm->immediate : &p->vm->delayed; +- ring = container_of(entity->rq->sched, struct amdgpu_ring, sched); ++ ring = container_of(p->vm->delayed.rq->sched, struct amdgpu_ring, ++ sched); + + WARN_ON(ib->length_dw == 0); + amdgpu_ring_pad_ib(ring, ib); + WARN_ON(ib->length_dw > p->num_dw_left); +- r = amdgpu_job_submit(p->job, entity, AMDGPU_FENCE_OWNER_VM, &f); +- if (r) +- goto error; ++ f = amdgpu_job_submit(p->job); + + if (p->unlocked) { + struct dma_fence *tmp = dma_fence_get(f); +@@ -127,10 +144,6 @@ static int amdgpu_vm_sdma_commit(struct + } + dma_fence_put(f); + return 0; +- +-error: +- amdgpu_job_free(p->job); +- return r; + } + + /** +@@ -210,8 +223,6 @@ static int amdgpu_vm_sdma_update(struct + uint64_t flags) + { + struct amdgpu_bo *bo = &vmbo->bo; +- enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE +- : AMDGPU_IB_POOL_DELAYED; + struct dma_resv_iter cursor; + unsigned int i, ndw, nptes; + struct dma_fence *fence; +@@ -238,19 +249,9 @@ static int amdgpu_vm_sdma_update(struct + if (r) + return r; + +- /* estimate how many dw we need */ +- ndw = 32; +- if (p->pages_addr) +- ndw += count * 2; +- ndw = max(ndw, AMDGPU_VM_SDMA_MIN_NUM_DW); +- ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW); +- +- r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool, +- &p->job); ++ r = amdgpu_vm_sdma_alloc_job(p, count); + if (r) + return r; +- +- p->num_dw_left = ndw; + } + + if (!p->pages_addr) { +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +@@ -371,7 +371,9 @@ static void gmc_v10_0_flush_gpu_tlb(stru + * translation. Avoid this by doing the invalidation from the SDMA + * itself. + */ +- r = amdgpu_job_alloc_with_ib(adev, 16 * 4, AMDGPU_IB_POOL_IMMEDIATE, ++ r = amdgpu_job_alloc_with_ib(ring->adev, &adev->mman.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ 16 * 4, AMDGPU_IB_POOL_IMMEDIATE, + &job); + if (r) + goto error_alloc; +@@ -380,10 +382,7 @@ static void gmc_v10_0_flush_gpu_tlb(stru + job->vm_needs_flush = true; + job->ibs->ptr[job->ibs->length_dw++] = ring->funcs->nop; + amdgpu_ring_pad_ib(ring, &job->ibs[0]); +- r = amdgpu_job_submit(job, &adev->mman.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, &fence); +- if (r) +- goto error_submit; ++ fence = amdgpu_job_submit(job); + + mutex_unlock(&adev->mman.gtt_window_lock); + +@@ -392,9 +391,6 @@ static void gmc_v10_0_flush_gpu_tlb(stru + + return; + +-error_submit: +- amdgpu_job_free(job); +- + error_alloc: + mutex_unlock(&adev->mman.gtt_window_lock); + DRM_ERROR("Error flushing GPU TLB using the SDMA (%d)!\n", r); +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +@@ -216,8 +216,8 @@ static int uvd_v6_0_enc_get_create_msg(s + uint64_t addr; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, ++ AMDGPU_IB_POOL_DIRECT, &job); + if (r) + return r; + +@@ -280,8 +280,8 @@ static int uvd_v6_0_enc_get_destroy_msg( + uint64_t addr; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, ++ AMDGPU_IB_POOL_DIRECT, &job); + if (r) + return r; + +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +@@ -213,7 +213,7 @@ static int uvd_v7_0_enc_ring_test_ring(s + * + * Open up a stream for HW test + */ +-static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, ++static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, u32 handle, + struct amdgpu_bo *bo, + struct dma_fence **fence) + { +@@ -224,8 +224,8 @@ static int uvd_v7_0_enc_get_create_msg(s + uint64_t addr; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, ++ AMDGPU_IB_POOL_DIRECT, &job); + if (r) + return r; + +@@ -276,7 +276,7 @@ err: + * + * Close up a stream for HW test or if userspace failed to do so + */ +-static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, ++static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, u32 handle, + struct amdgpu_bo *bo, + struct dma_fence **fence) + { +@@ -287,8 +287,8 @@ static int uvd_v7_0_enc_get_destroy_msg( + uint64_t addr; + int i, r; + +- r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, +- AMDGPU_IB_POOL_DIRECT, &job); ++ r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, ++ AMDGPU_IB_POOL_DIRECT, &job); + if (r) + return r; + +--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +@@ -65,8 +65,11 @@ svm_migrate_gart_map(struct amdgpu_ring + num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); + num_bytes = npages * 8; + +- r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes, +- AMDGPU_IB_POOL_DELAYED, &job); ++ r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, ++ AMDGPU_FENCE_OWNER_UNDEFINED, ++ num_dw * 4 + num_bytes, ++ AMDGPU_IB_POOL_DELAYED, ++ &job); + if (r) + return r; + +@@ -89,18 +92,10 @@ svm_migrate_gart_map(struct amdgpu_ring + cpu_addr = &job->ibs[0].ptr[num_dw]; + + amdgpu_gart_map(adev, 0, npages, addr, pte_flags, cpu_addr); +- r = amdgpu_job_submit(job, &adev->mman.entity, +- AMDGPU_FENCE_OWNER_UNDEFINED, &fence); +- if (r) +- goto error_free; +- ++ fence = amdgpu_job_submit(job); + dma_fence_put(fence); + + return r; +- +-error_free: +- amdgpu_job_free(job); +- return r; + } + + /** diff --git a/queue-6.1/drm-gma500-remove-unused-helper-psb_fbdev_fb_setcolreg.patch b/queue-6.1/drm-gma500-remove-unused-helper-psb_fbdev_fb_setcolreg.patch new file mode 100644 index 0000000000..436a3baf00 --- /dev/null +++ b/queue-6.1/drm-gma500-remove-unused-helper-psb_fbdev_fb_setcolreg.patch @@ -0,0 +1,101 @@ +From stable+bounces-206160-greg=kroah.com@vger.kernel.org Wed Jan 7 17:10:53 2026 +From: Sasha Levin +Date: Wed, 7 Jan 2026 10:48:24 -0500 +Subject: drm/gma500: Remove unused helper psb_fbdev_fb_setcolreg() +To: stable@vger.kernel.org +Cc: Thomas Zimmermann , Patrik Jakobsson , Stefan Christ , Daniel Vetter , dri-devel@lists.freedesktop.org, Sasha Levin +Message-ID: <20260107154824.4057632-1-sashal@kernel.org> + +From: Thomas Zimmermann + +[ Upstream commit be729f9de6c64240645dc80a24162ac4d3fe00a8 ] + +Remove psb_fbdev_fb_setcolreg(), which hasn't been called in almost +a decade. + +Gma500 commit 4d8d096e9ae8 ("gma500: introduce the framebuffer support +code") added the helper psb_fbdev_fb_setcolreg() for setting the fbdev +palette via fbdev's fb_setcolreg callback. Later +commit 3da6c2f3b730 ("drm/gma500: use DRM_FB_HELPER_DEFAULT_OPS for +fb_ops") set several default helpers for fbdev emulation, including +fb_setcmap. + +The fbdev subsystem always prefers fb_setcmap over fb_setcolreg. [1] +Hence, the gma500 code is no longer in use and gma500 has been using +drm_fb_helper_setcmap() for several years without issues. + +Fixes: 3da6c2f3b730 ("drm/gma500: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops") +Cc: Patrik Jakobsson +Cc: Stefan Christ +Cc: Daniel Vetter +Cc: dri-devel@lists.freedesktop.org +Cc: # v4.10+ +Link: https://elixir.bootlin.com/linux/v6.16.9/source/drivers/video/fbdev/core/fbcmap.c#L246 # [1] +Signed-off-by: Thomas Zimmermann +Acked-by: Patrik Jakobsson +Link: https://lore.kernel.org/r/20250929082338.18845-1-tzimmermann@suse.de +[ adapted patch from fbdev.c to framebuffer.c where the function was named psbfb_setcolreg() instead of psb_fbdev_fb_setcolreg() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/gma500/framebuffer.c | 42 ----------------------------------- + 1 file changed, 42 deletions(-) + +--- a/drivers/gpu/drm/gma500/framebuffer.c ++++ b/drivers/gpu/drm/gma500/framebuffer.c +@@ -35,47 +35,6 @@ static const struct drm_framebuffer_func + .create_handle = drm_gem_fb_create_handle, + }; + +-#define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) +- +-static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, +- unsigned blue, unsigned transp, +- struct fb_info *info) +-{ +- struct drm_fb_helper *fb_helper = info->par; +- struct drm_framebuffer *fb = fb_helper->fb; +- uint32_t v; +- +- if (!fb) +- return -ENOMEM; +- +- if (regno > 255) +- return 1; +- +- red = CMAP_TOHW(red, info->var.red.length); +- blue = CMAP_TOHW(blue, info->var.blue.length); +- green = CMAP_TOHW(green, info->var.green.length); +- transp = CMAP_TOHW(transp, info->var.transp.length); +- +- v = (red << info->var.red.offset) | +- (green << info->var.green.offset) | +- (blue << info->var.blue.offset) | +- (transp << info->var.transp.offset); +- +- if (regno < 16) { +- switch (fb->format->cpp[0] * 8) { +- case 16: +- ((uint32_t *) info->pseudo_palette)[regno] = v; +- break; +- case 24: +- case 32: +- ((uint32_t *) info->pseudo_palette)[regno] = v; +- break; +- } +- } +- +- return 0; +-} +- + static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf) + { + struct vm_area_struct *vma = vmf->vma; +@@ -146,7 +105,6 @@ static int psbfb_mmap(struct fb_info *in + static const struct fb_ops psbfb_unaccel_ops = { + .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, +- .fb_setcolreg = psbfb_setcolreg, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, diff --git a/queue-6.1/drm-mediatek-fix-probe-memory-leak.patch b/queue-6.1/drm-mediatek-fix-probe-memory-leak.patch new file mode 100644 index 0000000000..90ad7bc6a0 --- /dev/null +++ b/queue-6.1/drm-mediatek-fix-probe-memory-leak.patch @@ -0,0 +1,44 @@ +From stable+bounces-206139-greg=kroah.com@vger.kernel.org Wed Jan 7 13:19:11 2026 +From: Sasha Levin +Date: Wed, 7 Jan 2026 07:17:00 -0500 +Subject: drm/mediatek: Fix probe memory leak +To: stable@vger.kernel.org +Cc: Johan Hovold , CK Hu , AngeloGioacchino Del Regno , Chun-Kuang Hu , Sasha Levin +Message-ID: <20260107121700.3993037-1-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 5e49200593f331cd0629b5376fab9192f698e8ef ] + +The Mediatek DRM driver allocates private data for components without a +platform driver but as the lifetime is tied to each component device, +the memory is never freed. + +Tie the allocation lifetime to the DRM platform device so that the +memory is released on probe failure (e.g. probe deferral) and when the +driver is unbound. + +Fixes: c0d36de868a6 ("drm/mediatek: Move clk info from struct mtk_ddp_comp to sub driver private data") +Cc: stable@vger.kernel.org # 5.12 +Cc: CK Hu +Signed-off-by: Johan Hovold +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20250923152340.18234-3-johan@kernel.org/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -555,7 +555,7 @@ int mtk_ddp_comp_init(struct device_node + type == MTK_DSI) + return 0; + +- priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL); ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + diff --git a/queue-6.1/ext4-fix-string-copying-in-parse_apply_sb_mount_options.patch b/queue-6.1/ext4-fix-string-copying-in-parse_apply_sb_mount_options.patch new file mode 100644 index 0000000000..439aaf5a01 --- /dev/null +++ b/queue-6.1/ext4-fix-string-copying-in-parse_apply_sb_mount_options.patch @@ -0,0 +1,86 @@ +From stable+bounces-204161-greg=kroah.com@vger.kernel.org Tue Dec 30 02:01:05 2025 +From: Sasha Levin +Date: Mon, 29 Dec 2025 20:00:59 -0500 +Subject: ext4: fix string copying in parse_apply_sb_mount_options() +To: stable@vger.kernel.org +Cc: Fedor Pchelkin , Baokun Li , Jan Kara , Theodore Ts'o , Sasha Levin +Message-ID: <20251230010059.1899363-1-sashal@kernel.org> + +From: Fedor Pchelkin + +[ Upstream commit ee5a977b4e771cc181f39d504426dbd31ed701cc ] + +strscpy_pad() can't be used to copy a non-NUL-term string into a NUL-term +string of possibly bigger size. Commit 0efc5990bca5 ("string.h: Introduce +memtostr() and memtostr_pad()") provides additional information in that +regard. So if this happens, the following warning is observed: + +strnlen: detected buffer overflow: 65 byte read of buffer size 64 +WARNING: CPU: 0 PID: 28655 at lib/string_helpers.c:1032 __fortify_report+0x96/0xc0 lib/string_helpers.c:1032 +Modules linked in: +CPU: 0 UID: 0 PID: 28655 Comm: syz-executor.3 Not tainted 6.12.54-syzkaller-00144-g5f0270f1ba00 #0 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +RIP: 0010:__fortify_report+0x96/0xc0 lib/string_helpers.c:1032 +Call Trace: + + __fortify_panic+0x1f/0x30 lib/string_helpers.c:1039 + strnlen include/linux/fortify-string.h:235 [inline] + sized_strscpy include/linux/fortify-string.h:309 [inline] + parse_apply_sb_mount_options fs/ext4/super.c:2504 [inline] + __ext4_fill_super fs/ext4/super.c:5261 [inline] + ext4_fill_super+0x3c35/0xad00 fs/ext4/super.c:5706 + get_tree_bdev_flags+0x387/0x620 fs/super.c:1636 + vfs_get_tree+0x93/0x380 fs/super.c:1814 + do_new_mount fs/namespace.c:3553 [inline] + path_mount+0x6ae/0x1f70 fs/namespace.c:3880 + do_mount fs/namespace.c:3893 [inline] + __do_sys_mount fs/namespace.c:4103 [inline] + __se_sys_mount fs/namespace.c:4080 [inline] + __x64_sys_mount+0x280/0x300 fs/namespace.c:4080 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0x64/0x140 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Since userspace is expected to provide s_mount_opts field to be at most 63 +characters long with the ending byte being NUL-term, use a 64-byte buffer +which matches the size of s_mount_opts, so that strscpy_pad() does its job +properly. Return with error if the user still managed to provide a +non-NUL-term string here. + +Found by Linux Verification Center (linuxtesting.org) with Syzkaller. + +Fixes: 8ecb790ea8c3 ("ext4: avoid potential buffer over-read in parse_apply_sb_mount_options()") +Cc: stable@vger.kernel.org +Signed-off-by: Fedor Pchelkin +Reviewed-by: Baokun Li +Reviewed-by: Jan Kara +Message-ID: <20251101160430.222297-1-pchelkin@ispras.ru> +Signed-off-by: Theodore Ts'o +[ adapted 2-argument strscpy_pad() call to 3-argument form with explicit sizeof() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/super.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -2416,7 +2416,7 @@ static int parse_apply_sb_mount_options( + struct ext4_fs_context *m_ctx) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); +- char s_mount_opts[65]; ++ char s_mount_opts[64]; + struct ext4_fs_context *s_ctx = NULL; + struct fs_context *fc = NULL; + int ret = -ENOMEM; +@@ -2424,7 +2424,8 @@ static int parse_apply_sb_mount_options( + if (!sbi->s_es->s_mount_opts[0]) + return 0; + +- strscpy_pad(s_mount_opts, sbi->s_es->s_mount_opts, sizeof(s_mount_opts)); ++ if (strscpy_pad(s_mount_opts, sbi->s_es->s_mount_opts, sizeof(s_mount_opts)) < 0) ++ return -E2BIG; + + fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL); + if (!fc) diff --git a/queue-6.1/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch b/queue-6.1/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch new file mode 100644 index 0000000000..0e0bf69e00 --- /dev/null +++ b/queue-6.1/f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch @@ -0,0 +1,90 @@ +From stable+bounces-204259-greg=kroah.com@vger.kernel.org Tue Dec 30 18:20:05 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:19:57 -0500 +Subject: f2fs: drop inode from the donation list when the last file is closed +To: stable@vger.kernel.org +Cc: Jaegeuk Kim , Chao Yu , Sasha Levin +Message-ID: <20251230171958.2344337-3-sashal@kernel.org> + +From: Jaegeuk Kim + +[ Upstream commit 078cad8212ce4f4ebbafcc0936475b8215e1ca2a ] + +Let's drop the inode from the donation list when there is no other +open file. + +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 2 ++ + fs/f2fs/file.c | 8 +++++++- + fs/f2fs/inode.c | 2 +- + fs/f2fs/super.c | 1 + + 4 files changed, 11 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -824,6 +824,7 @@ struct f2fs_inode_info { + /* linked in global inode list for cache donation */ + struct list_head gdonate_list; + pgoff_t donate_start, donate_end; /* inclusive */ ++ atomic_t open_count; /* # of open files */ + + struct task_struct *atomic_write_task; /* store atomic write task */ + struct extent_tree *extent_tree[NR_EXTENT_CACHES]; +@@ -3473,6 +3474,7 @@ int f2fs_try_to_free_nats(struct f2fs_sb + void f2fs_update_inode(struct inode *inode, struct page *node_page); + void f2fs_update_inode_page(struct inode *inode); + int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc); ++void f2fs_remove_donate_inode(struct inode *inode); + void f2fs_evict_inode(struct inode *inode); + void f2fs_handle_failed_inode(struct inode *inode); + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -595,7 +595,10 @@ static int f2fs_file_open(struct inode * + if (err) + return err; + +- return finish_preallocate_blocks(inode); ++ err = finish_preallocate_blocks(inode); ++ if (!err) ++ atomic_inc(&F2FS_I(inode)->open_count); ++ return err; + } + + void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) +@@ -1923,6 +1926,9 @@ out: + + static int f2fs_release_file(struct inode *inode, struct file *filp) + { ++ if (atomic_dec_and_test(&F2FS_I(inode)->open_count)) ++ f2fs_remove_donate_inode(inode); ++ + /* + * f2fs_release_file is called at every close calls. So we should + * not drop any inmemory pages by close called by other process. +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -743,7 +743,7 @@ int f2fs_write_inode(struct inode *inode + return 0; + } + +-static void f2fs_remove_donate_inode(struct inode *inode) ++void f2fs_remove_donate_inode(struct inode *inode) + { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1425,6 +1425,7 @@ static struct inode *f2fs_alloc_inode(st + /* Initialize f2fs-specific inode info */ + atomic_set(&fi->dirty_pages, 0); + atomic_set(&fi->i_compr_blocks, 0); ++ atomic_set(&fi->open_count, 0); + init_f2fs_rwsem(&fi->i_sem); + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); diff --git a/queue-6.1/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch b/queue-6.1/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch new file mode 100644 index 0000000000..31e8088a11 --- /dev/null +++ b/queue-6.1/f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch @@ -0,0 +1,164 @@ +From stable+bounces-204260-greg=kroah.com@vger.kernel.org Tue Dec 30 18:20:06 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:19:58 -0500 +Subject: f2fs: fix to avoid updating compression context during writeback +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, "Bai, Shuangpeng" , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230171958.2344337-4-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 10b591e7fb7cdc8c1e53e9c000dc0ef7069aaa76 ] + +Bai, Shuangpeng reported a bug as below: + +Oops: divide error: 0000 [#1] SMP KASAN PTI +CPU: 0 UID: 0 PID: 11441 Comm: syz.0.46 Not tainted 6.17.0 #1 PREEMPT(full) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +RIP: 0010:f2fs_all_cluster_page_ready+0x106/0x550 fs/f2fs/compress.c:857 +Call Trace: + + f2fs_write_cache_pages fs/f2fs/data.c:3078 [inline] + __f2fs_write_data_pages fs/f2fs/data.c:3290 [inline] + f2fs_write_data_pages+0x1c19/0x3600 fs/f2fs/data.c:3317 + do_writepages+0x38e/0x640 mm/page-writeback.c:2634 + filemap_fdatawrite_wbc mm/filemap.c:386 [inline] + __filemap_fdatawrite_range mm/filemap.c:419 [inline] + file_write_and_wait_range+0x2ba/0x3e0 mm/filemap.c:794 + f2fs_do_sync_file+0x6e6/0x1b00 fs/f2fs/file.c:294 + generic_write_sync include/linux/fs.h:3043 [inline] + f2fs_file_write_iter+0x76e/0x2700 fs/f2fs/file.c:5259 + new_sync_write fs/read_write.c:593 [inline] + vfs_write+0x7e9/0xe00 fs/read_write.c:686 + ksys_write+0x19d/0x2d0 fs/read_write.c:738 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xf7/0x470 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The bug was triggered w/ below race condition: + +fsync setattr ioctl +- f2fs_do_sync_file + - file_write_and_wait_range + - f2fs_write_cache_pages + : inode is non-compressed + : cc.cluster_size = + F2FS_I(inode)->i_cluster_size = 0 + - tag_pages_for_writeback + - f2fs_setattr + - truncate_setsize + - f2fs_truncate + - f2fs_fileattr_set + - f2fs_setflags_common + - set_compress_context + : F2FS_I(inode)->i_cluster_size = 4 + : set_inode_flag(inode, FI_COMPRESSED_FILE) + - f2fs_compressed_file + : return true + - f2fs_all_cluster_page_ready + : "pgidx % cc->cluster_size" trigger dividing 0 issue + +Let's change as below to fix this issue: +- introduce a new atomic type variable .writeback in structure f2fs_inode_info +to track the number of threads which calling f2fs_write_cache_pages(). +- use .i_sem lock to protect .writeback update. +- check .writeback before update compression context in f2fs_setflags_common() +to avoid race w/ ->writepages. + +Fixes: 4c8ff7095bef ("f2fs: support data compression") +Cc: stable@kernel.org +Reported-by: Bai, Shuangpeng +Tested-by: Bai, Shuangpeng +Closes: https://lore.kernel.org/lkml/44D8F7B3-68AD-425F-9915-65D27591F93F@psu.edu +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 17 +++++++++++++++++ + fs/f2fs/f2fs.h | 3 ++- + fs/f2fs/file.c | 5 +++-- + fs/f2fs/super.c | 1 + + 4 files changed, 23 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -3262,6 +3262,19 @@ static inline bool __should_serialize_io + return false; + } + ++static inline void account_writeback(struct inode *inode, bool inc) ++{ ++ if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) ++ return; ++ ++ f2fs_down_read(&F2FS_I(inode)->i_sem); ++ if (inc) ++ atomic_inc(&F2FS_I(inode)->writeback); ++ else ++ atomic_dec(&F2FS_I(inode)->writeback); ++ f2fs_up_read(&F2FS_I(inode)->i_sem); ++} ++ + static int __f2fs_write_data_pages(struct address_space *mapping, + struct writeback_control *wbc, + enum iostat_type io_type) +@@ -3311,10 +3324,14 @@ static int __f2fs_write_data_pages(struc + locked = true; + } + ++ account_writeback(inode, true); ++ + blk_start_plug(&plug); + ret = f2fs_write_cache_pages(mapping, wbc, io_type); + blk_finish_plug(&plug); + ++ account_writeback(inode, false); ++ + if (locked) + mutex_unlock(&sbi->writepages); + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -848,6 +848,7 @@ struct f2fs_inode_info { + unsigned char i_compress_level; /* compress level (lz4hc,zstd) */ + unsigned char i_compress_flag; /* compress flag */ + unsigned int i_cluster_size; /* cluster size */ ++ atomic_t writeback; /* count # of writeback thread */ + + unsigned int atomic_write_cnt; + loff_t original_i_size; /* original i_size before atomic write */ +@@ -4375,7 +4376,7 @@ static inline bool f2fs_disable_compress + f2fs_up_write(&F2FS_I(inode)->i_sem); + return true; + } +- if (f2fs_is_mmap_file(inode) || ++ if (f2fs_is_mmap_file(inode) || atomic_read(&fi->writeback) || + (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))) { + f2fs_up_write(&F2FS_I(inode)->i_sem); + return false; +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -2002,8 +2002,9 @@ static int f2fs_setflags_common(struct i + + f2fs_down_write(&F2FS_I(inode)->i_sem); + if (!f2fs_may_compress(inode) || +- (S_ISREG(inode->i_mode) && +- F2FS_HAS_BLOCKS(inode))) { ++ atomic_read(&fi->writeback) || ++ (S_ISREG(inode->i_mode) && ++ F2FS_HAS_BLOCKS(inode))) { + f2fs_up_write(&F2FS_I(inode)->i_sem); + return -EINVAL; + } +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1426,6 +1426,7 @@ static struct inode *f2fs_alloc_inode(st + atomic_set(&fi->dirty_pages, 0); + atomic_set(&fi->i_compr_blocks, 0); + atomic_set(&fi->open_count, 0); ++ atomic_set(&fi->writeback, 0); + init_f2fs_rwsem(&fi->i_sem); + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); diff --git a/queue-6.1/f2fs-fix-to-avoid-updating-zero-sized-extent-in-extent-cache.patch b/queue-6.1/f2fs-fix-to-avoid-updating-zero-sized-extent-in-extent-cache.patch new file mode 100644 index 0000000000..a6aef5f228 --- /dev/null +++ b/queue-6.1/f2fs-fix-to-avoid-updating-zero-sized-extent-in-extent-cache.patch @@ -0,0 +1,67 @@ +From stable+bounces-204255-greg=kroah.com@vger.kernel.org Tue Dec 30 18:13:14 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:06:23 -0500 +Subject: f2fs: fix to avoid updating zero-sized extent in extent cache +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, syzbot+24124df3170c3638b35f@syzkaller.appspotmail.com, Jaegeuk Kim , Sasha Levin +Message-ID: <20251230170624.2337217-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 7c37c79510329cd951a4dedf3f7bf7e2b18dccec ] + +As syzbot reported: + +F2FS-fs (loop0): __update_extent_tree_range: extent len is zero, type: 0, extent [0, 0, 0], age [0, 0] +------------[ cut here ]------------ +kernel BUG at fs/f2fs/extent_cache.c:678! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +CPU: 0 UID: 0 PID: 5336 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 +RIP: 0010:__update_extent_tree_range+0x13bc/0x1500 fs/f2fs/extent_cache.c:678 +Call Trace: + + f2fs_update_read_extent_cache_range+0x192/0x3e0 fs/f2fs/extent_cache.c:1085 + f2fs_do_zero_range fs/f2fs/file.c:1657 [inline] + f2fs_zero_range+0x10c1/0x1580 fs/f2fs/file.c:1737 + f2fs_fallocate+0x583/0x990 fs/f2fs/file.c:2030 + vfs_fallocate+0x669/0x7e0 fs/open.c:342 + ioctl_preallocate fs/ioctl.c:289 [inline] + file_ioctl+0x611/0x780 fs/ioctl.c:-1 + do_vfs_ioctl+0xb33/0x1430 fs/ioctl.c:576 + __do_sys_ioctl fs/ioctl.c:595 [inline] + __se_sys_ioctl+0x82/0x170 fs/ioctl.c:583 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f07bc58eec9 + +In error path of f2fs_zero_range(), it may add a zero-sized extent +into extent cache, it should be avoided. + +Fixes: 6e9619499f53 ("f2fs: support in batch fzero in dnode page") +Cc: stable@kernel.org +Reported-by: syzbot+24124df3170c3638b35f@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-f2fs-devel/68e5d698.050a0220.256323.0032.GAE@google.com +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ adapted patch to only guard f2fs_update_read_extent_cache_range() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/file.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -1552,7 +1552,9 @@ static int f2fs_do_zero_range(struct dno + f2fs_set_data_blkaddr(dn, NEW_ADDR); + } + +- f2fs_update_read_extent_cache_range(dn, start, 0, index - start); ++ if (index > start) ++ f2fs_update_read_extent_cache_range(dn, start, 0, ++ index - start); + + return ret; + } diff --git a/queue-6.1/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch b/queue-6.1/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch new file mode 100644 index 0000000000..efbbaac127 --- /dev/null +++ b/queue-6.1/f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch @@ -0,0 +1,93 @@ +From stable+bounces-204284-greg=kroah.com@vger.kernel.org Tue Dec 30 20:54:36 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 14:54:31 -0500 +Subject: f2fs: fix to detect recoverable inode during dryrun of find_fsync_dnodes() +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Jaegeuk Kim , Sasha Levin +Message-ID: <20251230195431.2446807-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 68d05693f8c031257a0822464366e1c2a239a512 ] + +mkfs.f2fs -f /dev/vdd +mount /dev/vdd /mnt/f2fs +touch /mnt/f2fs/foo +sync # avoid CP_UMOUNT_FLAG in last f2fs_checkpoint.ckpt_flags +touch /mnt/f2fs/bar +f2fs_io fsync /mnt/f2fs/bar +f2fs_io shutdown 2 /mnt/f2fs +umount /mnt/f2fs +blockdev --setro /dev/vdd +mount /dev/vdd /mnt/f2fs +mount: /mnt/f2fs: WARNING: source write-protected, mounted read-only. + +For the case if we create and fsync a new inode before sudden power-cut, +without norecovery or disable_roll_forward mount option, the following +mount will succeed w/o recovering last fsynced inode. + +The problem here is that we only check inode_list list after +find_fsync_dnodes() in f2fs_recover_fsync_data() to find out whether +there is recoverable data in the iamge, but there is a missed case, if +last fsynced inode is not existing in last checkpoint, then, we will +fail to get its inode due to nat of inode node is not existing in last +checkpoint, so the inode won't be linked in inode_list. + +Let's detect such case in dyrun mode to fix this issue. + +After this change, mount will fail as expected below: +mount: /mnt/f2fs: cannot mount /dev/vdd read-only. + dmesg(1) may have more information after failed mount system call. +demsg: +F2FS-fs (vdd): Need to recover fsync data, but write access unavailable, please try mount w/ disable_roll_forward or norecovery + +Cc: stable@kernel.org +Fixes: 6781eabba1bd ("f2fs: give -EINVAL for norecovery and rw mount") +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ folio => page ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/recovery.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -360,7 +360,7 @@ static unsigned int adjust_por_ra_blocks + } + + static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, +- bool check_only) ++ bool check_only, bool *new_inode) + { + struct curseg_info *curseg; + struct page *page = NULL; +@@ -418,6 +418,8 @@ static int find_fsync_dnodes(struct f2fs + if (IS_ERR(entry)) { + err = PTR_ERR(entry); + if (err == -ENOENT) { ++ if (check_only) ++ *new_inode = true; + err = 0; + goto next; + } +@@ -834,6 +836,7 @@ int f2fs_recover_fsync_data(struct f2fs_ + unsigned long s_flags = sbi->sb->s_flags; + bool need_writecp = false; + bool fix_curseg_write_pointer = false; ++ bool new_inode = false; + #ifdef CONFIG_QUOTA + int quota_enabled; + #endif +@@ -856,8 +859,8 @@ int f2fs_recover_fsync_data(struct f2fs_ + f2fs_down_write(&sbi->cp_global_sem); + + /* step #1: find fsynced inode numbers */ +- err = find_fsync_dnodes(sbi, &inode_list, check_only); +- if (err || list_empty(&inode_list)) ++ err = find_fsync_dnodes(sbi, &inode_list, check_only, &new_inode); ++ if (err < 0 || (list_empty(&inode_list) && (!check_only || !new_inode))) + goto skip; + + if (check_only) { diff --git a/queue-6.1/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch b/queue-6.1/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch new file mode 100644 index 0000000000..65e72e2ef8 --- /dev/null +++ b/queue-6.1/f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch @@ -0,0 +1,86 @@ +From stable+bounces-204262-greg=kroah.com@vger.kernel.org Tue Dec 30 18:26:12 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:26:06 -0500 +Subject: f2fs: fix to propagate error from f2fs_enable_checkpoint() +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Jaegeuk Kim , Sasha Levin +Message-ID: <20251230172606.2349129-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit be112e7449a6e1b54aa9feac618825d154b3a5c7 ] + +In order to let userspace detect such error rather than suffering +silent failure. + +Fixes: 4354994f097d ("f2fs: checkpoint disabling") +Cc: stable@kernel.org +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ Adjust context, no rollback ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/super.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -2222,9 +2222,10 @@ restore_flag: + return err; + } + +-static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) ++static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + { + int retry = DEFAULT_RETRY_IO_COUNT; ++ int ret; + + /* we should flush all the data to keep data consistency */ + do { +@@ -2242,10 +2243,14 @@ static void f2fs_enable_checkpoint(struc + set_sbi_flag(sbi, SBI_IS_DIRTY); + f2fs_up_write(&sbi->gc_lock); + +- f2fs_sync_fs(sbi->sb, 1); ++ ret = f2fs_sync_fs(sbi->sb, 1); ++ if (ret) ++ f2fs_err(sbi, "%s sync_fs failed, ret: %d", __func__, ret); + + /* Let's ensure there's no pending checkpoint anymore */ + f2fs_flush_ckpt_thread(sbi); ++ ++ return ret; + } + + static int f2fs_remount(struct super_block *sb, int *flags, char *data) +@@ -2460,7 +2465,9 @@ static int f2fs_remount(struct super_blo + if (err) + goto restore_discard; + } else { +- f2fs_enable_checkpoint(sbi); ++ err = f2fs_enable_checkpoint(sbi); ++ if (err) ++ goto restore_discard; + } + } + +@@ -4528,13 +4535,12 @@ reset_checkpoint: + /* f2fs_recover_fsync_data() cleared this already */ + clear_sbi_flag(sbi, SBI_POR_DOING); + +- if (test_opt(sbi, DISABLE_CHECKPOINT)) { ++ if (test_opt(sbi, DISABLE_CHECKPOINT)) + err = f2fs_disable_checkpoint(sbi); +- if (err) +- goto sync_free_meta; +- } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { +- f2fs_enable_checkpoint(sbi); +- } ++ else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) ++ err = f2fs_enable_checkpoint(sbi); ++ if (err) ++ goto sync_free_meta; + + /* + * If filesystem is not mounted as read-only then diff --git a/queue-6.1/f2fs-keep-posix_fadv_noreuse-ranges.patch b/queue-6.1/f2fs-keep-posix_fadv_noreuse-ranges.patch new file mode 100644 index 0000000000..dfb64f6da8 --- /dev/null +++ b/queue-6.1/f2fs-keep-posix_fadv_noreuse-ranges.patch @@ -0,0 +1,206 @@ +From stable+bounces-204258-greg=kroah.com@vger.kernel.org Tue Dec 30 18:20:07 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:19:56 -0500 +Subject: f2fs: keep POSIX_FADV_NOREUSE ranges +To: stable@vger.kernel.org +Cc: Jaegeuk Kim , Chao Yu , Sasha Levin +Message-ID: <20251230171958.2344337-2-sashal@kernel.org> + +From: Jaegeuk Kim + +[ Upstream commit ef0c333cad8d1940f132a7ce15f15920216a3bd5 ] + +This patch records POSIX_FADV_NOREUSE ranges for users to reclaim the caches +instantly off from LRU. + +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/debug.c | 3 ++ + fs/f2fs/f2fs.h | 12 ++++++++++- + fs/f2fs/file.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++----- + fs/f2fs/inode.c | 14 +++++++++++++ + fs/f2fs/super.c | 1 + 5 files changed, 84 insertions(+), 6 deletions(-) + +--- a/fs/f2fs/debug.c ++++ b/fs/f2fs/debug.c +@@ -97,6 +97,7 @@ static void update_general_status(struct + si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA); + si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE]; + si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; ++ si->ndonate_files = sbi->donate_files; + si->nquota_files = sbi->nquota_files; + si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; + si->aw_cnt = atomic_read(&sbi->atomic_files); +@@ -402,6 +403,8 @@ static int stat_show(struct seq_file *s, + si->compr_inode, si->compr_blocks); + seq_printf(s, " - Swapfile Inode: %u\n", + si->swapfile_inode); ++ seq_printf(s, " - Donate Inode: %u\n", ++ si->ndonate_files); + seq_printf(s, " - Orphan/Append/Update Inode: %u, %u, %u\n", + si->orphans, si->append, si->update); + seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -820,6 +820,11 @@ struct f2fs_inode_info { + #endif + struct list_head dirty_list; /* dirty list for dirs and files */ + struct list_head gdirty_list; /* linked in global dirty list */ ++ ++ /* linked in global inode list for cache donation */ ++ struct list_head gdonate_list; ++ pgoff_t donate_start, donate_end; /* inclusive */ ++ + struct task_struct *atomic_write_task; /* store atomic write task */ + struct extent_tree *extent_tree[NR_EXTENT_CACHES]; + /* cached extent_tree entry */ +@@ -1236,6 +1241,7 @@ enum inode_type { + DIR_INODE, /* for dirty dir inode */ + FILE_INODE, /* for dirty regular/symlink inode */ + DIRTY_META, /* for all dirtied inode metadata */ ++ DONATE_INODE, /* for all inode to donate pages */ + NR_INODE_TYPE, + }; + +@@ -1650,6 +1656,9 @@ struct f2fs_sb_info { + /* for extent tree cache */ + struct extent_tree_info extent_tree[NR_EXTENT_CACHES]; + ++ /* control donate caches */ ++ unsigned int donate_files; ++ + /* basic filesystem units */ + unsigned int log_sectors_per_block; /* log2 sectors per block */ + unsigned int log_blocksize; /* log2 block size */ +@@ -3854,7 +3863,8 @@ struct f2fs_stat_info { + unsigned long long hit_largest; + int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta; + int ndirty_data, ndirty_qdata; +- unsigned int ndirty_dirs, ndirty_files, nquota_files, ndirty_all; ++ unsigned int ndirty_dirs, ndirty_files, ndirty_all; ++ unsigned int nquota_files, ndonate_files; + int nats, dirty_nats, sits, dirty_sits; + int free_nids, avail_nids, alloc_nids; + int total_count, utilization; +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -2367,6 +2367,52 @@ out: + return ret; + } + ++static void f2fs_keep_noreuse_range(struct inode *inode, ++ loff_t offset, loff_t len) ++{ ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); ++ u64 max_bytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode)); ++ u64 start, end; ++ ++ if (!S_ISREG(inode->i_mode)) ++ return; ++ ++ if (offset >= max_bytes || len > max_bytes || ++ (offset + len) > max_bytes) ++ return; ++ ++ start = offset >> PAGE_SHIFT; ++ end = DIV_ROUND_UP(offset + len, PAGE_SIZE); ++ ++ inode_lock(inode); ++ if (f2fs_is_atomic_file(inode)) { ++ inode_unlock(inode); ++ return; ++ } ++ ++ spin_lock(&sbi->inode_lock[DONATE_INODE]); ++ /* let's remove the range, if len = 0 */ ++ if (!len) { ++ if (!list_empty(&F2FS_I(inode)->gdonate_list)) { ++ list_del_init(&F2FS_I(inode)->gdonate_list); ++ sbi->donate_files--; ++ } ++ } else { ++ if (list_empty(&F2FS_I(inode)->gdonate_list)) { ++ list_add_tail(&F2FS_I(inode)->gdonate_list, ++ &sbi->inode_list[DONATE_INODE]); ++ sbi->donate_files++; ++ } else { ++ list_move_tail(&F2FS_I(inode)->gdonate_list, ++ &sbi->inode_list[DONATE_INODE]); ++ } ++ F2FS_I(inode)->donate_start = start; ++ F2FS_I(inode)->donate_end = end - 1; ++ } ++ spin_unlock(&sbi->inode_lock[DONATE_INODE]); ++ inode_unlock(inode); ++} ++ + static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) + { + struct inode *inode = file_inode(filp); +@@ -4901,12 +4947,16 @@ static int f2fs_file_fadvise(struct file + } + + err = generic_fadvise(filp, offset, len, advice); +- if (!err && advice == POSIX_FADV_DONTNEED && +- test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) && +- f2fs_compressed_file(inode)) +- f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); ++ if (err) ++ return err; + +- return err; ++ if (advice == POSIX_FADV_DONTNEED && ++ (test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) && ++ f2fs_compressed_file(inode))) ++ f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); ++ else if (advice == POSIX_FADV_NOREUSE) ++ f2fs_keep_noreuse_range(inode, offset, len); ++ return 0; + } + + #ifdef CONFIG_COMPAT +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -743,6 +743,19 @@ int f2fs_write_inode(struct inode *inode + return 0; + } + ++static void f2fs_remove_donate_inode(struct inode *inode) ++{ ++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); ++ ++ if (list_empty(&F2FS_I(inode)->gdonate_list)) ++ return; ++ ++ spin_lock(&sbi->inode_lock[DONATE_INODE]); ++ list_del_init(&F2FS_I(inode)->gdonate_list); ++ sbi->donate_files--; ++ spin_unlock(&sbi->inode_lock[DONATE_INODE]); ++} ++ + /* + * Called at the last iput() if i_nlink is zero + */ +@@ -775,6 +788,7 @@ void f2fs_evict_inode(struct inode *inod + + f2fs_bug_on(sbi, get_dirty_pages(inode)); + f2fs_remove_dirty_inode(inode); ++ f2fs_remove_donate_inode(inode); + + f2fs_destroy_extent_tree(inode); + +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1429,6 +1429,7 @@ static struct inode *f2fs_alloc_inode(st + spin_lock_init(&fi->i_size_lock); + INIT_LIST_HEAD(&fi->dirty_list); + INIT_LIST_HEAD(&fi->gdirty_list); ++ INIT_LIST_HEAD(&fi->gdonate_list); + init_f2fs_rwsem(&fi->i_gc_rwsem[READ]); + init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]); + init_f2fs_rwsem(&fi->i_xattr_sem); diff --git a/queue-6.1/f2fs-remove-unused-gc_failure_pin.patch b/queue-6.1/f2fs-remove-unused-gc_failure_pin.patch new file mode 100644 index 0000000000..8d5e6f0480 --- /dev/null +++ b/queue-6.1/f2fs-remove-unused-gc_failure_pin.patch @@ -0,0 +1,139 @@ +From stable+bounces-204257-greg=kroah.com@vger.kernel.org Tue Dec 30 18:20:05 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 12:19:55 -0500 +Subject: f2fs: remove unused GC_FAILURE_PIN +To: stable@vger.kernel.org +Cc: Chao Yu , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230171958.2344337-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 968c4f72b23c0c8f1e94e942eab89b8c5a3022e7 ] + +After commit 3db1de0e582c ("f2fs: change the current atomic write way"), +we removed all GC_FAILURE_ATOMIC usage, let's change i_gc_failures[] +array to i_pin_failure for cleanup. + +Meanwhile, let's define i_current_depth and i_gc_failures as union +variable due to they won't be valid at the same time. + +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 14 +++++--------- + fs/f2fs/file.c | 12 +++++------- + fs/f2fs/inode.c | 6 ++---- + fs/f2fs/recovery.c | 3 +-- + 4 files changed, 13 insertions(+), 22 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -747,11 +747,6 @@ enum { + + #define DEF_DIR_LEVEL 0 + +-enum { +- GC_FAILURE_PIN, +- MAX_GC_FAILURE +-}; +- + /* used for f2fs_inode_info->flags */ + enum { + FI_NEW_INODE, /* indicate newly allocated inode */ +@@ -797,9 +792,10 @@ struct f2fs_inode_info { + unsigned long i_flags; /* keep an inode flags for ioctl */ + unsigned char i_advise; /* use to give file attribute hints */ + unsigned char i_dir_level; /* use for dentry level for large dir */ +- unsigned int i_current_depth; /* only for directory depth */ +- /* for gc failure statistic */ +- unsigned int i_gc_failures[MAX_GC_FAILURE]; ++ union { ++ unsigned int i_current_depth; /* only for directory depth */ ++ unsigned int i_gc_failures; /* for gc failure statistic */ ++ }; + unsigned int i_pino; /* parent inode number */ + umode_t i_acl_mode; /* keep file acl mode temporarily */ + +@@ -3100,7 +3096,7 @@ static inline void f2fs_i_depth_write(st + static inline void f2fs_i_gc_failures_write(struct inode *inode, + unsigned int count) + { +- F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = count; ++ F2FS_I(inode)->i_gc_failures = count; + f2fs_mark_inode_dirty_sync(inode, true); + } + +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -3247,13 +3247,11 @@ int f2fs_pin_file_control(struct inode * + + /* Use i_gc_failures for normal file as a risk signal. */ + if (inc) +- f2fs_i_gc_failures_write(inode, +- fi->i_gc_failures[GC_FAILURE_PIN] + 1); ++ f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1); + +- if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) { ++ if (fi->i_gc_failures > sbi->gc_pin_file_threshold) { + f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials", +- __func__, inode->i_ino, +- fi->i_gc_failures[GC_FAILURE_PIN]); ++ __func__, inode->i_ino, fi->i_gc_failures); + clear_inode_flag(inode, FI_PIN_FILE); + return -EAGAIN; + } +@@ -3312,7 +3310,7 @@ static int f2fs_ioc_set_pin_file(struct + } + + set_inode_flag(inode, FI_PIN_FILE); +- ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; ++ ret = F2FS_I(inode)->i_gc_failures; + done: + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + out: +@@ -3327,7 +3325,7 @@ static int f2fs_ioc_get_pin_file(struct + __u32 pin = 0; + + if (is_inode_flag_set(inode, FI_PIN_FILE)) +- pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; ++ pin = F2FS_I(inode)->i_gc_failures; + return put_user(pin, (u32 __user *)arg); + } + +--- a/fs/f2fs/inode.c ++++ b/fs/f2fs/inode.c +@@ -362,8 +362,7 @@ static int do_read_inode(struct inode *i + if (S_ISDIR(inode->i_mode)) + fi->i_current_depth = le32_to_cpu(ri->i_current_depth); + else if (S_ISREG(inode->i_mode)) +- fi->i_gc_failures[GC_FAILURE_PIN] = +- le16_to_cpu(ri->i_gc_failures); ++ fi->i_gc_failures = le16_to_cpu(ri->i_gc_failures); + fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); + fi->i_flags = le32_to_cpu(ri->i_flags); + if (S_ISREG(inode->i_mode)) +@@ -623,8 +622,7 @@ void f2fs_update_inode(struct inode *ino + ri->i_current_depth = + cpu_to_le32(F2FS_I(inode)->i_current_depth); + else if (S_ISREG(inode->i_mode)) +- ri->i_gc_failures = +- cpu_to_le16(F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]); ++ ri->i_gc_failures = cpu_to_le16(F2FS_I(inode)->i_gc_failures); + ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); + ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); + ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -330,8 +330,7 @@ static int recover_inode(struct inode *i + F2FS_I(inode)->i_advise = raw->i_advise; + F2FS_I(inode)->i_flags = le32_to_cpu(raw->i_flags); + f2fs_set_inode_flags(inode); +- F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = +- le16_to_cpu(raw->i_gc_failures); ++ F2FS_I(inode)->i_gc_failures = le16_to_cpu(raw->i_gc_failures); + + recover_inline_flags(inode, raw); + diff --git a/queue-6.1/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch b/queue-6.1/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch new file mode 100644 index 0000000000..74ed72377a --- /dev/null +++ b/queue-6.1/f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch @@ -0,0 +1,235 @@ +From stable+bounces-204278-greg=kroah.com@vger.kernel.org Tue Dec 30 19:54:18 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 13:54:13 -0500 +Subject: f2fs: use global inline_xattr_slab instead of per-sb slab cache +To: stable@vger.kernel.org +Cc: Chao Yu , stable@kernel.org, Hong Yun , Jaegeuk Kim , Sasha Levin +Message-ID: <20251230185413.2413273-1-sashal@kernel.org> + +From: Chao Yu + +[ Upstream commit 1f27ef42bb0b7c0740c5616ec577ec188b8a1d05 ] + +As Hong Yun reported in mailing list: + +loop7: detected capacity change from 0 to 131072 +------------[ cut here ]------------ +kmem_cache of name 'f2fs_xattr_entry-7:7' already exists +WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 kmem_cache_sanity_check mm/slab_common.c:109 [inline] +WARNING: CPU: 0 PID: 24426 at mm/slab_common.c:110 __kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 +CPU: 0 UID: 0 PID: 24426 Comm: syz.7.1370 Not tainted 6.17.0-rc4 #1 PREEMPT(full) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 +RIP: 0010:kmem_cache_sanity_check mm/slab_common.c:109 [inline] +RIP: 0010:__kmem_cache_create_args+0xa6/0x320 mm/slab_common.c:307 +Call Trace: + __kmem_cache_create include/linux/slab.h:353 [inline] + f2fs_kmem_cache_create fs/f2fs/f2fs.h:2943 [inline] + f2fs_init_xattr_caches+0xa5/0xe0 fs/f2fs/xattr.c:843 + f2fs_fill_super+0x1645/0x2620 fs/f2fs/super.c:4918 + get_tree_bdev_flags+0x1fb/0x260 fs/super.c:1692 + vfs_get_tree+0x43/0x140 fs/super.c:1815 + do_new_mount+0x201/0x550 fs/namespace.c:3808 + do_mount fs/namespace.c:4136 [inline] + __do_sys_mount fs/namespace.c:4347 [inline] + __se_sys_mount+0x298/0x2f0 fs/namespace.c:4324 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x8e/0x3a0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The bug can be reproduced w/ below scripts: +- mount /dev/vdb /mnt1 +- mount /dev/vdc /mnt2 +- umount /mnt1 +- mounnt /dev/vdb /mnt1 + +The reason is if we created two slab caches, named f2fs_xattr_entry-7:3 +and f2fs_xattr_entry-7:7, and they have the same slab size. Actually, +slab system will only create one slab cache core structure which has +slab name of "f2fs_xattr_entry-7:3", and two slab caches share the same +structure and cache address. + +So, if we destroy f2fs_xattr_entry-7:3 cache w/ cache address, it will +decrease reference count of slab cache, rather than release slab cache +entirely, since there is one more user has referenced the cache. + +Then, if we try to create slab cache w/ name "f2fs_xattr_entry-7:3" again, +slab system will find that there is existed cache which has the same name +and trigger the warning. + +Let's changes to use global inline_xattr_slab instead of per-sb slab cache +for fixing. + +Fixes: a999150f4fe3 ("f2fs: use kmem_cache pool during inline xattr lookups") +Cc: stable@kernel.org +Reported-by: Hong Yun +Tested-by: Hong Yun +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ folio => page , context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 3 --- + fs/f2fs/super.c | 15 +++++++-------- + fs/f2fs/xattr.c | 30 ++++++++++-------------------- + fs/f2fs/xattr.h | 10 ++++++---- + 4 files changed, 23 insertions(+), 35 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1807,9 +1807,6 @@ struct f2fs_sb_info { + spinlock_t error_lock; /* protect errors array */ + bool error_dirty; /* errors of sb is dirty */ + +- struct kmem_cache *inline_xattr_slab; /* inline xattr entry */ +- unsigned int inline_xattr_slab_size; /* default inline xattr slab size */ +- + /* For reclaimed segs statistics per each GC mode */ + unsigned int gc_segment_mode; /* GC state for reclaimed segments */ + unsigned int gc_reclaimed_segs[MAX_GC_MODE]; /* Reclaimed segs for each mode */ +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1674,7 +1674,6 @@ static void f2fs_put_super(struct super_ + + destroy_device_list(sbi); + f2fs_destroy_page_array_cache(sbi); +- f2fs_destroy_xattr_caches(sbi); + mempool_destroy(sbi->write_io_dummy); + #ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) +@@ -4305,13 +4304,9 @@ try_onemore: + } + } + +- /* init per sbi slab cache */ +- err = f2fs_init_xattr_caches(sbi); +- if (err) +- goto free_io_dummy; + err = f2fs_init_page_array_cache(sbi); + if (err) +- goto free_xattr_cache; ++ goto free_io_dummy; + + /* get an inode for meta space */ + sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); +@@ -4624,8 +4619,6 @@ free_meta_inode: + sbi->meta_inode = NULL; + free_page_array_cache: + f2fs_destroy_page_array_cache(sbi); +-free_xattr_cache: +- f2fs_destroy_xattr_caches(sbi); + free_io_dummy: + mempool_destroy(sbi->write_io_dummy); + free_percpu: +@@ -4792,7 +4785,12 @@ static int __init init_f2fs_fs(void) + err = f2fs_create_casefold_cache(); + if (err) + goto free_compress_cache; ++ err = f2fs_init_xattr_cache(); ++ if (err) ++ goto free_casefold_cache; + return 0; ++free_casefold_cache: ++ f2fs_destroy_casefold_cache(); + free_compress_cache: + f2fs_destroy_compress_cache(); + free_compress_mempool: +@@ -4832,6 +4830,7 @@ fail: + + static void __exit exit_f2fs_fs(void) + { ++ f2fs_destroy_xattr_cache(); + f2fs_destroy_casefold_cache(); + f2fs_destroy_compress_cache(); + f2fs_destroy_compress_mempool(); +--- a/fs/f2fs/xattr.c ++++ b/fs/f2fs/xattr.c +@@ -23,11 +23,12 @@ + #include "xattr.h" + #include "segment.h" + ++static struct kmem_cache *inline_xattr_slab; + static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline) + { +- if (likely(size == sbi->inline_xattr_slab_size)) { ++ if (likely(size == DEFAULT_XATTR_SLAB_SIZE)) { + *is_inline = true; +- return f2fs_kmem_cache_alloc(sbi->inline_xattr_slab, ++ return f2fs_kmem_cache_alloc(inline_xattr_slab, + GFP_F2FS_ZERO, false, sbi); + } + *is_inline = false; +@@ -38,7 +39,7 @@ static void xattr_free(struct f2fs_sb_in + bool is_inline) + { + if (is_inline) +- kmem_cache_free(sbi->inline_xattr_slab, xattr_addr); ++ kmem_cache_free(inline_xattr_slab, xattr_addr); + else + kfree(xattr_addr); + } +@@ -830,25 +831,14 @@ int f2fs_setxattr(struct inode *inode, i + return err; + } + +-int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) ++int __init f2fs_init_xattr_cache(void) + { +- dev_t dev = sbi->sb->s_bdev->bd_dev; +- char slab_name[32]; +- +- sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev)); +- +- sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size * +- sizeof(__le32) + XATTR_PADDING_SIZE; +- +- sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name, +- sbi->inline_xattr_slab_size); +- if (!sbi->inline_xattr_slab) +- return -ENOMEM; +- +- return 0; ++ inline_xattr_slab = f2fs_kmem_cache_create("f2fs_xattr_entry", ++ DEFAULT_XATTR_SLAB_SIZE); ++ return inline_xattr_slab ? 0 : -ENOMEM; + } + +-void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) ++void f2fs_destroy_xattr_cache(void) + { +- kmem_cache_destroy(sbi->inline_xattr_slab); ++ kmem_cache_destroy(inline_xattr_slab); + } +--- a/fs/f2fs/xattr.h ++++ b/fs/f2fs/xattr.h +@@ -88,6 +88,8 @@ struct f2fs_xattr_entry { + F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \ + DEF_INLINE_RESERVED_SIZE - \ + MIN_INLINE_DENTRY_SIZE / sizeof(__le32)) ++#define DEFAULT_XATTR_SLAB_SIZE (DEFAULT_INLINE_XATTR_ADDRS * \ ++ sizeof(__le32) + XATTR_PADDING_SIZE) + + /* + * On-disk structure of f2fs_xattr +@@ -131,8 +133,8 @@ extern int f2fs_setxattr(struct inode *, + extern int f2fs_getxattr(struct inode *, int, const char *, void *, + size_t, struct page *); + extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); +-extern int f2fs_init_xattr_caches(struct f2fs_sb_info *); +-extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *); ++int __init f2fs_init_xattr_cache(void); ++void f2fs_destroy_xattr_cache(void); + #else + + #define f2fs_xattr_handlers NULL +@@ -149,8 +151,8 @@ static inline int f2fs_getxattr(struct i + { + return -EOPNOTSUPP; + } +-static inline int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; } +-static inline void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { } ++static inline int __init f2fs_init_xattr_cache(void) { return 0; } ++static inline void f2fs_destroy_xattr_cache(void) { } + #endif + + #ifdef CONFIG_F2FS_FS_SECURITY diff --git a/queue-6.1/fscache-delete-fscache_cookie_lru_timer-when-fscache-exits-to-avoid-uaf.patch b/queue-6.1/fscache-delete-fscache_cookie_lru_timer-when-fscache-exits-to-avoid-uaf.patch new file mode 100644 index 0000000000..208a37603f --- /dev/null +++ b/queue-6.1/fscache-delete-fscache_cookie_lru_timer-when-fscache-exits-to-avoid-uaf.patch @@ -0,0 +1,74 @@ +From stable+bounces-199963-greg=kroah.com@vger.kernel.org Thu Dec 4 08:00:34 2025 +From: Chen Yu +Date: Thu, 4 Dec 2025 14:57:33 +0800 +Subject: fscache: delete fscache_cookie_lru_timer when fscache exits to avoid UAF +To: libaokun1@huawei.com, dhowells@redhat.com, brauner@kernel.org, stable@vger.kernel.org +Message-ID: <20251204065733.21270-1-xnguchen@sina.cn> + +From: Baokun Li + +commit 72a6e22c604c95ddb3b10b5d3bb85b6ff4dbc34f upstream. + +The fscache_cookie_lru_timer is initialized when the fscache module +is inserted, but is not deleted when the fscache module is removed. +If timer_reduce() is called before removing the fscache module, +the fscache_cookie_lru_timer will be added to the timer list of +the current cpu. Afterwards, a use-after-free will be triggered +in the softIRQ after removing the fscache module, as follows: + +================================================================== +BUG: unable to handle page fault for address: fffffbfff803c9e9 + PF: supervisor read access in kernel mode + PF: error_code(0x0000) - not-present page +PGD 21ffea067 P4D 21ffea067 PUD 21ffe6067 PMD 110a7c067 PTE 0 +Oops: Oops: 0000 [#1] PREEMPT SMP KASAN PTI +CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Tainted: G W 6.11.0-rc3 #855 +Tainted: [W]=WARN +RIP: 0010:__run_timer_base.part.0+0x254/0x8a0 +Call Trace: + + tmigr_handle_remote_up+0x627/0x810 + __walk_groups.isra.0+0x47/0x140 + tmigr_handle_remote+0x1fa/0x2f0 + handle_softirqs+0x180/0x590 + irq_exit_rcu+0x84/0xb0 + sysvec_apic_timer_interrupt+0x6e/0x90 + + + asm_sysvec_apic_timer_interrupt+0x1a/0x20 +RIP: 0010:default_idle+0xf/0x20 + default_idle_call+0x38/0x60 + do_idle+0x2b5/0x300 + cpu_startup_entry+0x54/0x60 + start_secondary+0x20d/0x280 + common_startup_64+0x13e/0x148 + +Modules linked in: [last unloaded: netfs] +================================================================== + +Therefore delete fscache_cookie_lru_timer when removing the fscahe module. + +Fixes: 12bb21a29c19 ("fscache: Implement cookie user counting and resource pinning") +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Link: https://lore.kernel.org/r/20240826112056.2458299-1-libaokun@huaweicloud.com +Acked-by: David Howells +Signed-off-by: Christian Brauner +[ Changed the file path due to missing commit:47757ea83a54 ("netfs, +fscache: Move fs/fscache/* into fs/netfs/") ] +Signed-off-by: Chen Yu +Signed-off-by: Greg Kroah-Hartman +--- + fs/fscache/main.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/fscache/main.c ++++ b/fs/fscache/main.c +@@ -114,6 +114,7 @@ static void __exit fscache_exit(void) + + kmem_cache_destroy(fscache_cookie_jar); + fscache_proc_cleanup(); ++ timer_shutdown_sync(&fscache_cookie_lru_timer); + destroy_workqueue(fscache_wq); + pr_notice("Unloaded\n"); + } diff --git a/queue-6.1/fuse-fix-readahead-reclaim-deadlock.patch b/queue-6.1/fuse-fix-readahead-reclaim-deadlock.patch new file mode 100644 index 0000000000..cf641588c6 --- /dev/null +++ b/queue-6.1/fuse-fix-readahead-reclaim-deadlock.patch @@ -0,0 +1,120 @@ +From stable+bounces-204417-greg=kroah.com@vger.kernel.org Thu Jan 1 16:20:17 2026 +From: Sasha Levin +Date: Thu, 1 Jan 2026 10:20:12 -0500 +Subject: fuse: fix readahead reclaim deadlock +To: stable@vger.kernel.org +Cc: Joanne Koong , Omar Sandoval , Miklos Szeredi , Sasha Levin +Message-ID: <20260101152012.4110447-1-sashal@kernel.org> + +From: Joanne Koong + +[ Upstream commit bd5603eaae0aabf527bfb3ce1bb07e979ce5bd50 ] + +Commit e26ee4efbc79 ("fuse: allocate ff->release_args only if release is +needed") skips allocating ff->release_args if the server does not +implement open. However in doing so, fuse_prepare_release() now skips +grabbing the reference on the inode, which makes it possible for an +inode to be evicted from the dcache while there are inflight readahead +requests. This causes a deadlock if the server triggers reclaim while +servicing the readahead request and reclaim attempts to evict the inode +of the file being read ahead. Since the folio is locked during +readahead, when reclaim evicts the fuse inode and fuse_evict_inode() +attempts to remove all folios associated with the inode from the page +cache (truncate_inode_pages_range()), reclaim will block forever waiting +for the lock since readahead cannot relinquish the lock because it is +itself blocked in reclaim: + +>>> stack_trace(1504735) + folio_wait_bit_common (mm/filemap.c:1308:4) + folio_lock (./include/linux/pagemap.h:1052:3) + truncate_inode_pages_range (mm/truncate.c:336:10) + fuse_evict_inode (fs/fuse/inode.c:161:2) + evict (fs/inode.c:704:3) + dentry_unlink_inode (fs/dcache.c:412:3) + __dentry_kill (fs/dcache.c:615:3) + shrink_kill (fs/dcache.c:1060:12) + shrink_dentry_list (fs/dcache.c:1087:3) + prune_dcache_sb (fs/dcache.c:1168:2) + super_cache_scan (fs/super.c:221:10) + do_shrink_slab (mm/shrinker.c:435:9) + shrink_slab (mm/shrinker.c:626:10) + shrink_node (mm/vmscan.c:5951:2) + shrink_zones (mm/vmscan.c:6195:3) + do_try_to_free_pages (mm/vmscan.c:6257:3) + do_swap_page (mm/memory.c:4136:11) + handle_pte_fault (mm/memory.c:5562:10) + handle_mm_fault (mm/memory.c:5870:9) + do_user_addr_fault (arch/x86/mm/fault.c:1338:10) + handle_page_fault (arch/x86/mm/fault.c:1481:3) + exc_page_fault (arch/x86/mm/fault.c:1539:2) + asm_exc_page_fault+0x22/0x27 + +Fix this deadlock by allocating ff->release_args and grabbing the +reference on the inode when preparing the file for release even if the +server does not implement open. The inode reference will be dropped when +the last reference on the fuse file is dropped (see fuse_file_put() -> +fuse_release_end()). + +Fixes: e26ee4efbc79 ("fuse: allocate ff->release_args only if release is needed") +Cc: stable@vger.kernel.org +Signed-off-by: Joanne Koong +Reported-by: Omar Sandoval +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/file.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -112,7 +112,9 @@ static void fuse_file_put(struct fuse_fi + struct fuse_args *args = (ra ? &ra->args : NULL); + + if (!args) { +- /* Do nothing when server does not implement 'open' */ ++ /* Do nothing when server does not implement 'opendir' */ ++ } else if (args->opcode == FUSE_RELEASE && ff->fm->fc->no_open) { ++ fuse_release_end(ff->fm, args, 0); + } else if (sync) { + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); +@@ -133,8 +135,17 @@ struct fuse_file *fuse_file_open(struct + struct fuse_file *ff; + int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; + bool open = isdir ? !fc->no_opendir : !fc->no_open; ++ bool release = !isdir || open; + +- ff = fuse_file_alloc(fm, open); ++ /* ++ * ff->args->release_args still needs to be allocated (so we can hold an ++ * inode reference while there are pending inflight file operations when ++ * ->release() is called, see fuse_prepare_release()) even if ++ * fc->no_open is set else it becomes possible for reclaim to deadlock ++ * if while servicing the readahead request the server triggers reclaim ++ * and reclaim evicts the inode of the file being read ahead. ++ */ ++ ff = fuse_file_alloc(fm, release); + if (!ff) + return ERR_PTR(-ENOMEM); + +@@ -153,13 +164,14 @@ struct fuse_file *fuse_file_open(struct + fuse_file_free(ff); + return ERR_PTR(err); + } else { +- /* No release needed */ +- kfree(ff->release_args); +- ff->release_args = NULL; +- if (isdir) ++ if (isdir) { ++ /* No release needed */ ++ kfree(ff->release_args); ++ ff->release_args = NULL; + fc->no_opendir = 1; +- else ++ } else { + fc->no_open = 1; ++ } + } + } + diff --git a/queue-6.1/gfs2-fix-freeze-error-handling.patch b/queue-6.1/gfs2-fix-freeze-error-handling.patch new file mode 100644 index 0000000000..faee8ce961 --- /dev/null +++ b/queue-6.1/gfs2-fix-freeze-error-handling.patch @@ -0,0 +1,47 @@ +From stable+bounces-204150-greg=kroah.com@vger.kernel.org Tue Dec 30 00:25:13 2025 +From: Sasha Levin +Date: Mon, 29 Dec 2025 18:25:04 -0500 +Subject: gfs2: fix freeze error handling +To: stable@vger.kernel.org +Cc: Alexey Velichayshiy , Andreas Gruenbacher , Sasha Levin +Message-ID: <20251229232504.1818648-1-sashal@kernel.org> + +From: Alexey Velichayshiy + +[ Upstream commit 4cfc7d5a4a01d2133b278cdbb1371fba1b419174 ] + +After commit b77b4a4815a9 ("gfs2: Rework freeze / thaw logic"), +the freeze error handling is broken because gfs2_do_thaw() +overwrites the 'error' variable, causing incorrect processing +of the original freeze error. + +Fix this by calling gfs2_do_thaw() when gfs2_lock_fs_check_clean() +fails but ignoring its return value to preserve the original +freeze error for proper reporting. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: b77b4a4815a9 ("gfs2: Rework freeze / thaw logic") +Cc: stable@vger.kernel.org # v6.5+ +Signed-off-by: Alexey Velichayshiy +Signed-off-by: Andreas Gruenbacher +[ gfs2_do_thaw() only takes one param ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/gfs2/super.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/fs/gfs2/super.c ++++ b/fs/gfs2/super.c +@@ -771,9 +771,7 @@ static int gfs2_freeze_super(struct supe + if (!error) + break; /* success */ + +- error = gfs2_do_thaw(sdp); +- if (error) +- goto out; ++ (void)gfs2_do_thaw(sdp); + + if (error == -EBUSY) + fs_err(sdp, "waiting for recovery before freeze\n"); diff --git a/queue-6.1/iommu-arm-smmu-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/iommu-arm-smmu-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..f7d20a375b --- /dev/null +++ b/queue-6.1/iommu-arm-smmu-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,119 @@ +From stable+bounces-204841-greg=kroah.com@vger.kernel.org Mon Jan 5 16:54:54 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:44:50 -0500 +Subject: iommu/arm-smmu: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Joerg Roedel" , "Sasha Levin" +Message-ID: <20260105154453.2644685-2-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 62565a77c2323d32f2be737455729ac7d3efe6ad ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230321084125.337021-5-u.kleine-koenig@pengutronix.de +Signed-off-by: Joerg Roedel +Stable-dep-of: 6a3908ce56e6 ("iommu/qcom: fix device leak on of_xlate()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/arm/arm-smmu/arm-smmu.c | 6 ++---- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 12 ++++-------- + 2 files changed, 6 insertions(+), 12 deletions(-) + +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c +@@ -2225,7 +2225,7 @@ static void arm_smmu_device_shutdown(str + clk_bulk_unprepare(smmu->num_clks, smmu->clks); + } + +-static int arm_smmu_device_remove(struct platform_device *pdev) ++static void arm_smmu_device_remove(struct platform_device *pdev) + { + struct arm_smmu_device *smmu = platform_get_drvdata(pdev); + +@@ -2233,8 +2233,6 @@ static int arm_smmu_device_remove(struct + iommu_device_sysfs_remove(&smmu->iommu); + + arm_smmu_device_shutdown(pdev); +- +- return 0; + } + + static int __maybe_unused arm_smmu_runtime_resume(struct device *dev) +@@ -2310,7 +2308,7 @@ static struct platform_driver arm_smmu_d + .suppress_bind_attrs = true, + }, + .probe = arm_smmu_device_probe, +- .remove = arm_smmu_device_remove, ++ .remove_new = arm_smmu_device_remove, + .shutdown = arm_smmu_device_shutdown, + }; + module_platform_driver(arm_smmu_driver); +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -715,7 +715,7 @@ static int qcom_iommu_ctx_probe(struct p + return 0; + } + +-static int qcom_iommu_ctx_remove(struct platform_device *pdev) ++static void qcom_iommu_ctx_remove(struct platform_device *pdev) + { + struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(pdev->dev.parent); + struct qcom_iommu_ctx *ctx = platform_get_drvdata(pdev); +@@ -723,8 +723,6 @@ static int qcom_iommu_ctx_remove(struct + platform_set_drvdata(pdev, NULL); + + qcom_iommu->ctxs[ctx->asid - 1] = NULL; +- +- return 0; + } + + static const struct of_device_id ctx_of_match[] = { +@@ -739,7 +737,7 @@ static struct platform_driver qcom_iommu + .of_match_table = ctx_of_match, + }, + .probe = qcom_iommu_ctx_probe, +- .remove = qcom_iommu_ctx_remove, ++ .remove_new = qcom_iommu_ctx_remove, + }; + + static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu) +@@ -857,7 +855,7 @@ err_pm_disable: + return ret; + } + +-static int qcom_iommu_device_remove(struct platform_device *pdev) ++static void qcom_iommu_device_remove(struct platform_device *pdev) + { + struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev); + +@@ -865,8 +863,6 @@ static int qcom_iommu_device_remove(stru + platform_set_drvdata(pdev, NULL); + iommu_device_sysfs_remove(&qcom_iommu->iommu); + iommu_device_unregister(&qcom_iommu->iommu); +- +- return 0; + } + + static int __maybe_unused qcom_iommu_resume(struct device *dev) +@@ -903,7 +899,7 @@ static struct platform_driver qcom_iommu + .pm = &qcom_iommu_pm_ops, + }, + .probe = qcom_iommu_device_probe, +- .remove = qcom_iommu_device_remove, ++ .remove_new = qcom_iommu_device_remove, + }; + + static int __init qcom_iommu_init(void) diff --git a/queue-6.1/iommu-arm-smmu-drop-if-with-an-always-false-condition.patch b/queue-6.1/iommu-arm-smmu-drop-if-with-an-always-false-condition.patch new file mode 100644 index 0000000000..b8e262f11c --- /dev/null +++ b/queue-6.1/iommu-arm-smmu-drop-if-with-an-always-false-condition.patch @@ -0,0 +1,56 @@ +From stable+bounces-204840-greg=kroah.com@vger.kernel.org Mon Jan 5 16:52:41 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:44:49 -0500 +Subject: iommu/arm-smmu: Drop if with an always false condition +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Robin Murphy" , "Joerg Roedel" , "Sasha Levin" +Message-ID: <20260105154453.2644685-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit a2972cb89935160bfe515b15d28a77694723ac06 ] + +The remove and shutdown callback are only called after probe completed +successfully. In this case platform_set_drvdata() was called with a +non-NULL argument and so smmu is never NULL. Other functions in this +driver also don't check for smmu being non-NULL before using it. + +Also note that returning an error code from a remove callback doesn't +result in the device staying bound. It's still removed and devm allocated +resources are freed (among others *smmu and the register mapping). So +after an early exit to iommu device stayed around and using it probably +oopses. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: Robin Murphy +Link: https://lore.kernel.org/r/20230321084125.337021-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Joerg Roedel +Stable-dep-of: 6a3908ce56e6 ("iommu/qcom: fix device leak on of_xlate()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/arm/arm-smmu/arm-smmu.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c +@@ -2209,9 +2209,6 @@ static void arm_smmu_device_shutdown(str + { + struct arm_smmu_device *smmu = platform_get_drvdata(pdev); + +- if (!smmu) +- return; +- + if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS)) + dev_notice(&pdev->dev, "disabling translation\n"); + +@@ -2232,9 +2229,6 @@ static int arm_smmu_device_remove(struct + { + struct arm_smmu_device *smmu = platform_get_drvdata(pdev); + +- if (!smmu) +- return -ENODEV; +- + iommu_device_unregister(&smmu->iommu); + iommu_device_sysfs_remove(&smmu->iommu); + diff --git a/queue-6.1/iommu-mediatek-fix-use-after-free-on-probe-deferral.patch b/queue-6.1/iommu-mediatek-fix-use-after-free-on-probe-deferral.patch new file mode 100644 index 0000000000..e8dba5c443 --- /dev/null +++ b/queue-6.1/iommu-mediatek-fix-use-after-free-on-probe-deferral.patch @@ -0,0 +1,95 @@ +From stable+bounces-204400-greg=kroah.com@vger.kernel.org Thu Jan 1 00:39:05 2026 +From: Sasha Levin +Date: Wed, 31 Dec 2025 18:38:58 -0500 +Subject: iommu/mediatek: fix use-after-free on probe deferral +To: stable@vger.kernel.org +Cc: Johan Hovold , Yong Wu , Robin Murphy , AngeloGioacchino Del Regno , Joerg Roedel , Sasha Levin +Message-ID: <20251231233858.3696664-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit de83d4617f9fe059623e97acf7e1e10d209625b5 ] + +The driver is dropping the references taken to the larb devices during +probe after successful lookup as well as on errors. This can +potentially lead to a use-after-free in case a larb device has not yet +been bound to its driver so that the iommu driver probe defers. + +Fix this by keeping the references as expected while the iommu driver is +bound. + +Fixes: 26593928564c ("iommu/mediatek: Add error path for loop of mm_dts_parse") +Cc: stable@vger.kernel.org +Cc: Yong Wu +Acked-by: Robin Murphy +Signed-off-by: Johan Hovold +Reviewed-by: Yong Wu +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/mtk_iommu.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -1134,16 +1134,19 @@ static int mtk_iommu_mm_dts_parse(struct + } + + component_match_add(dev, match, component_compare_dev, &plarbdev->dev); +- platform_device_put(plarbdev); + } + +- if (!frst_avail_smicomm_node) +- return -EINVAL; ++ if (!frst_avail_smicomm_node) { ++ ret = -EINVAL; ++ goto err_larbdev_put; ++ } + + pcommdev = of_find_device_by_node(frst_avail_smicomm_node); + of_node_put(frst_avail_smicomm_node); +- if (!pcommdev) +- return -ENODEV; ++ if (!pcommdev) { ++ ret = -ENODEV; ++ goto err_larbdev_put; ++ } + data->smicomm_dev = &pcommdev->dev; + + link = device_link_add(data->smicomm_dev, dev, +@@ -1151,7 +1154,8 @@ static int mtk_iommu_mm_dts_parse(struct + platform_device_put(pcommdev); + if (!link) { + dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev)); +- return -EINVAL; ++ ret = -EINVAL; ++ goto err_larbdev_put; + } + return 0; + +@@ -1322,8 +1326,12 @@ out_sysfs_remove: + iommu_device_sysfs_remove(&data->iommu); + out_list_del: + list_del(&data->list); +- if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) ++ if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { + device_link_remove(data->smicomm_dev, dev); ++ ++ for (i = 0; i < MTK_LARB_NR_MAX; i++) ++ put_device(data->larb_imu[i].dev); ++ } + out_runtime_disable: + pm_runtime_disable(dev); + return ret; +@@ -1343,6 +1351,9 @@ static int mtk_iommu_remove(struct platf + if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { + device_link_remove(data->smicomm_dev, &pdev->dev); + component_master_del(&pdev->dev, &mtk_iommu_com_ops); ++ ++ for (i = 0; i < MTK_LARB_NR_MAX; i++) ++ put_device(data->larb_imu[i].dev); + } + pm_runtime_disable(&pdev->dev); + for (i = 0; i < data->plat_data->banks_num; i++) { diff --git a/queue-6.1/iommu-mediatek-improve-safety-for-mediatek-smi-property-in-larb-nodes.patch b/queue-6.1/iommu-mediatek-improve-safety-for-mediatek-smi-property-in-larb-nodes.patch new file mode 100644 index 0000000000..00ad8aaf37 --- /dev/null +++ b/queue-6.1/iommu-mediatek-improve-safety-for-mediatek-smi-property-in-larb-nodes.patch @@ -0,0 +1,114 @@ +From stable+bounces-204399-greg=kroah.com@vger.kernel.org Thu Jan 1 00:39:05 2026 +From: Sasha Levin +Date: Wed, 31 Dec 2025 18:38:57 -0500 +Subject: iommu/mediatek: Improve safety for mediatek,smi property in larb nodes +To: stable@vger.kernel.org +Cc: Yong Wu , Guenter Roeck , AngeloGioacchino Del Regno , Matthias Brugger , Joerg Roedel , Sasha Levin +Message-ID: <20251231233858.3696664-1-sashal@kernel.org> + +From: Yong Wu + +[ Upstream commit 6cde583d5352818a51985b32a960cdde85ab3821 ] + +No functional change. Just improve safety from dts. + +All the larbs that connect to one IOMMU must connect with the same +smi-common. This patch checks all the mediatek,smi property for each +larb, If their mediatek,smi are different, it will return fails. +Also avoid there is no available smi-larb nodes. + +Suggested-by: Guenter Roeck +Signed-off-by: Yong Wu +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Matthias Brugger +Link: https://lore.kernel.org/r/20221018024258.19073-6-yong.wu@mediatek.com +Signed-off-by: Joerg Roedel +Stable-dep-of: de83d4617f9f ("iommu/mediatek: fix use-after-free on probe deferral") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/mtk_iommu.c | 53 ++++++++++++++++++++++++++++++++-------------- + 1 file changed, 37 insertions(+), 16 deletions(-) + +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -1048,7 +1048,7 @@ static const struct component_master_ops + static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **match, + struct mtk_iommu_data *data) + { +- struct device_node *larbnode, *smicomm_node, *smi_subcomm_node; ++ struct device_node *larbnode, *frst_avail_smicomm_node = NULL; + struct platform_device *plarbdev, *pcommdev; + struct device_link *link; + int i, larb_nr, ret; +@@ -1060,6 +1060,7 @@ static int mtk_iommu_mm_dts_parse(struct + return -EINVAL; + + for (i = 0; i < larb_nr; i++) { ++ struct device_node *smicomm_node, *smi_subcomm_node; + u32 id; + + larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i); +@@ -1100,27 +1101,47 @@ static int mtk_iommu_mm_dts_parse(struct + goto err_larbdev_put; + } + ++ /* Get smi-(sub)-common dev from the last larb. */ ++ smi_subcomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0); ++ if (!smi_subcomm_node) { ++ ret = -EINVAL; ++ goto err_larbdev_put; ++ } ++ ++ /* ++ * It may have two level smi-common. the node is smi-sub-common if it ++ * has a new mediatek,smi property. otherwise it is smi-commmon. ++ */ ++ smicomm_node = of_parse_phandle(smi_subcomm_node, "mediatek,smi", 0); ++ if (smicomm_node) ++ of_node_put(smi_subcomm_node); ++ else ++ smicomm_node = smi_subcomm_node; ++ ++ /* ++ * All the larbs that connect to one IOMMU must connect with the same ++ * smi-common. ++ */ ++ if (!frst_avail_smicomm_node) { ++ frst_avail_smicomm_node = smicomm_node; ++ } else if (frst_avail_smicomm_node != smicomm_node) { ++ dev_err(dev, "mediatek,smi property is not right @larb%d.", id); ++ of_node_put(smicomm_node); ++ ret = -EINVAL; ++ goto err_larbdev_put; ++ } else { ++ of_node_put(smicomm_node); ++ } ++ + component_match_add(dev, match, component_compare_dev, &plarbdev->dev); + platform_device_put(plarbdev); + } + +- /* Get smi-(sub)-common dev from the last larb. */ +- smi_subcomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0); +- if (!smi_subcomm_node) ++ if (!frst_avail_smicomm_node) + return -EINVAL; + +- /* +- * It may have two level smi-common. the node is smi-sub-common if it +- * has a new mediatek,smi property. otherwise it is smi-commmon. +- */ +- smicomm_node = of_parse_phandle(smi_subcomm_node, "mediatek,smi", 0); +- if (smicomm_node) +- of_node_put(smi_subcomm_node); +- else +- smicomm_node = smi_subcomm_node; +- +- pcommdev = of_find_device_by_node(smicomm_node); +- of_node_put(smicomm_node); ++ pcommdev = of_find_device_by_node(frst_avail_smicomm_node); ++ of_node_put(frst_avail_smicomm_node); + if (!pcommdev) + return -ENODEV; + data->smicomm_dev = &pcommdev->dev; diff --git a/queue-6.1/iommu-mediatek-v1-fix-device-leaks-on-probe.patch b/queue-6.1/iommu-mediatek-v1-fix-device-leaks-on-probe.patch new file mode 100644 index 0000000000..9f22caf4b0 --- /dev/null +++ b/queue-6.1/iommu-mediatek-v1-fix-device-leaks-on-probe.patch @@ -0,0 +1,97 @@ +From stable+bounces-204838-greg=kroah.com@vger.kernel.org Mon Jan 5 16:45:21 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:32:20 -0500 +Subject: iommu/mediatek-v1: fix device leaks on probe() +To: stable@vger.kernel.org +Cc: Johan Hovold , Honghui Zhang , Robin Murphy , AngeloGioacchino Del Regno , Joerg Roedel , Sasha Levin +Message-ID: <20260105153220.2637603-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 46207625c9f33da0e43bb4ae1e91f0791b6ed633 ] + +Make sure to drop the references taken to the larb devices during +probe on probe failure (e.g. probe deferral) and on driver unbind. + +Fixes: b17336c55d89 ("iommu/mediatek: add support for mtk iommu generation one HW") +Cc: stable@vger.kernel.org # 4.8 +Cc: Honghui Zhang +Acked-by: Robin Murphy +Signed-off-by: Johan Hovold +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/mtk_iommu_v1.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +--- a/drivers/iommu/mtk_iommu_v1.c ++++ b/drivers/iommu/mtk_iommu_v1.c +@@ -656,8 +656,10 @@ static int mtk_iommu_v1_probe(struct pla + struct platform_device *plarbdev; + + larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i); +- if (!larbnode) +- return -EINVAL; ++ if (!larbnode) { ++ ret = -EINVAL; ++ goto out_put_larbs; ++ } + + if (!of_device_is_available(larbnode)) { + of_node_put(larbnode); +@@ -667,11 +669,14 @@ static int mtk_iommu_v1_probe(struct pla + plarbdev = of_find_device_by_node(larbnode); + if (!plarbdev) { + of_node_put(larbnode); +- return -ENODEV; ++ ret = -ENODEV; ++ goto out_put_larbs; + } + if (!plarbdev->dev.driver) { + of_node_put(larbnode); +- return -EPROBE_DEFER; ++ put_device(&plarbdev->dev); ++ ret = -EPROBE_DEFER; ++ goto out_put_larbs; + } + data->larb_imu[i].dev = &plarbdev->dev; + +@@ -683,7 +688,7 @@ static int mtk_iommu_v1_probe(struct pla + + ret = mtk_iommu_v1_hw_init(data); + if (ret) +- return ret; ++ goto out_put_larbs; + + ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, + dev_name(&pdev->dev)); +@@ -705,12 +710,17 @@ out_sysfs_remove: + iommu_device_sysfs_remove(&data->iommu); + out_clk_unprepare: + clk_disable_unprepare(data->bclk); ++out_put_larbs: ++ for (i = 0; i < MTK_LARB_NR_MAX; i++) ++ put_device(data->larb_imu[i].dev); ++ + return ret; + } + + static void mtk_iommu_v1_remove(struct platform_device *pdev) + { + struct mtk_iommu_v1_data *data = platform_get_drvdata(pdev); ++ int i; + + iommu_device_sysfs_remove(&data->iommu); + iommu_device_unregister(&data->iommu); +@@ -718,6 +728,9 @@ static void mtk_iommu_v1_remove(struct p + clk_disable_unprepare(data->bclk); + devm_free_irq(&pdev->dev, data->irq, data); + component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops); ++ ++ for (i = 0; i < MTK_LARB_NR_MAX; i++) ++ put_device(data->larb_imu[i].dev); + } + + static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev) diff --git a/queue-6.1/iommu-mtk_iommu_v1-convert-to-platform-remove-callback-returning-void.patch b/queue-6.1/iommu-mtk_iommu_v1-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..7b03b5c252 --- /dev/null +++ b/queue-6.1/iommu-mtk_iommu_v1-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,62 @@ +From stable+bounces-204837-greg=kroah.com@vger.kernel.org Mon Jan 5 16:48:58 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:32:19 -0500 +Subject: iommu/mtk_iommu_v1: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "AngeloGioacchino Del Regno" , "Joerg Roedel" , "Sasha Levin" +Message-ID: <20260105153220.2637603-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 85e1049e50da9409678fc247ebad4c019d68041f ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20230321084125.337021-9-u.kleine-koenig@pengutronix.de +Signed-off-by: Joerg Roedel +Stable-dep-of: 46207625c9f3 ("iommu/mediatek-v1: fix device leaks on probe()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/mtk_iommu_v1.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/iommu/mtk_iommu_v1.c ++++ b/drivers/iommu/mtk_iommu_v1.c +@@ -708,7 +708,7 @@ out_clk_unprepare: + return ret; + } + +-static int mtk_iommu_v1_remove(struct platform_device *pdev) ++static void mtk_iommu_v1_remove(struct platform_device *pdev) + { + struct mtk_iommu_v1_data *data = platform_get_drvdata(pdev); + +@@ -718,7 +718,6 @@ static int mtk_iommu_v1_remove(struct pl + clk_disable_unprepare(data->bclk); + devm_free_irq(&pdev->dev, data->irq, data); + component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops); +- return 0; + } + + static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev) +@@ -757,7 +756,7 @@ static const struct dev_pm_ops mtk_iommu + + static struct platform_driver mtk_iommu_v1_driver = { + .probe = mtk_iommu_v1_probe, +- .remove = mtk_iommu_v1_remove, ++ .remove_new = mtk_iommu_v1_remove, + .driver = { + .name = "mtk-iommu-v1", + .of_match_table = mtk_iommu_v1_of_ids, diff --git a/queue-6.1/iommu-qcom-fix-device-leak-on-of_xlate.patch b/queue-6.1/iommu-qcom-fix-device-leak-on-of_xlate.patch new file mode 100644 index 0000000000..f81646335e --- /dev/null +++ b/queue-6.1/iommu-qcom-fix-device-leak-on-of_xlate.patch @@ -0,0 +1,64 @@ +From stable+bounces-204844-greg=kroah.com@vger.kernel.org Mon Jan 5 16:46:59 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:44:53 -0500 +Subject: iommu/qcom: fix device leak on of_xlate() +To: stable@vger.kernel.org +Cc: Johan Hovold , Rob Clark , Yu Kuai , Robin Murphy , Joerg Roedel , Sasha Levin +Message-ID: <20260105154453.2644685-5-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 6a3908ce56e6879920b44ef136252b2f0c954194 ] + +Make sure to drop the reference taken to the iommu platform device when +looking up its driver data during of_xlate(). + +Note that commit e2eae09939a8 ("iommu/qcom: add missing put_device() +call in qcom_iommu_of_xlate()") fixed the leak in a couple of error +paths, but the reference is still leaking on success and late failures. + +Fixes: 0ae349a0f33f ("iommu/qcom: Add qcom_iommu") +Cc: stable@vger.kernel.org # 4.14: e2eae09939a8 +Cc: Rob Clark +Cc: Yu Kuai +Acked-by: Robin Murphy +Signed-off-by: Johan Hovold +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -558,14 +558,14 @@ static int qcom_iommu_of_xlate(struct de + + qcom_iommu = platform_get_drvdata(iommu_pdev); + ++ put_device(&iommu_pdev->dev); ++ + /* make sure the asid specified in dt is valid, so we don't have + * to sanity check this elsewhere: + */ + if (WARN_ON(asid > qcom_iommu->max_asid) || +- WARN_ON(qcom_iommu->ctxs[asid] == NULL)) { +- put_device(&iommu_pdev->dev); ++ WARN_ON(qcom_iommu->ctxs[asid] == NULL)) + return -EINVAL; +- } + + if (!dev_iommu_priv_get(dev)) { + dev_iommu_priv_set(dev, qcom_iommu); +@@ -574,10 +574,8 @@ static int qcom_iommu_of_xlate(struct de + * multiple different iommu devices. Multiple context + * banks are ok, but multiple devices are not: + */ +- if (WARN_ON(qcom_iommu != dev_iommu_priv_get(dev))) { +- put_device(&iommu_pdev->dev); ++ if (WARN_ON(qcom_iommu != dev_iommu_priv_get(dev))) + return -EINVAL; +- } + } + + return iommu_fwspec_add_ids(dev, &asid, 1); diff --git a/queue-6.1/iommu-qcom-index-contexts-by-asid-number-to-allow-asid-0.patch b/queue-6.1/iommu-qcom-index-contexts-by-asid-number-to-allow-asid-0.patch new file mode 100644 index 0000000000..d7f0510604 --- /dev/null +++ b/queue-6.1/iommu-qcom-index-contexts-by-asid-number-to-allow-asid-0.patch @@ -0,0 +1,103 @@ +From stable+bounces-204843-greg=kroah.com@vger.kernel.org Mon Jan 5 16:47:00 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:44:52 -0500 +Subject: iommu/qcom: Index contexts by asid number to allow asid 0 +To: stable@vger.kernel.org +Cc: AngeloGioacchino Del Regno , Konrad Dybcio , Will Deacon , Sasha Levin +Message-ID: <20260105154453.2644685-4-sashal@kernel.org> + +From: AngeloGioacchino Del Regno + +[ Upstream commit ec5601661bfcdc206e6ceba1b97837e763dab1ba ] + +This driver was indexing the contexts by asid-1, which is probably +done under the assumption that the first ASID is always 1. +Unfortunately this is not always true: at least for MSM8956 and +MSM8976's GPU IOMMU, the gpu_user context's ASID number is zero. +To allow using a zero asid number, index the contexts by `asid` +instead of by `asid - 1`. + +While at it, also enhance human readability by renaming the +`num_ctxs` member of struct qcom_iommu_dev to `max_asid`. + +Signed-off-by: AngeloGioacchino Del Regno +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20230622092742.74819-5-angelogioacchino.delregno@collabora.com +Signed-off-by: Will Deacon +Stable-dep-of: 6a3908ce56e6 ("iommu/qcom: fix device leak on of_xlate()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -51,8 +51,8 @@ struct qcom_iommu_dev { + struct clk_bulk_data clks[CLK_NUM]; + void __iomem *local_base; + u32 sec_id; +- u8 num_ctxs; +- struct qcom_iommu_ctx *ctxs[]; /* indexed by asid-1 */ ++ u8 max_asid; ++ struct qcom_iommu_ctx *ctxs[]; /* indexed by asid */ + }; + + struct qcom_iommu_ctx { +@@ -94,7 +94,7 @@ static struct qcom_iommu_ctx * to_ctx(st + struct qcom_iommu_dev *qcom_iommu = d->iommu; + if (!qcom_iommu) + return NULL; +- return qcom_iommu->ctxs[asid - 1]; ++ return qcom_iommu->ctxs[asid]; + } + + static inline void +@@ -559,12 +559,10 @@ static int qcom_iommu_of_xlate(struct de + qcom_iommu = platform_get_drvdata(iommu_pdev); + + /* make sure the asid specified in dt is valid, so we don't have +- * to sanity check this elsewhere, since 'asid - 1' is used to +- * index into qcom_iommu->ctxs: ++ * to sanity check this elsewhere: + */ +- if (WARN_ON(asid < 1) || +- WARN_ON(asid > qcom_iommu->num_ctxs) || +- WARN_ON(qcom_iommu->ctxs[asid - 1] == NULL)) { ++ if (WARN_ON(asid > qcom_iommu->max_asid) || ++ WARN_ON(qcom_iommu->ctxs[asid] == NULL)) { + put_device(&iommu_pdev->dev); + return -EINVAL; + } +@@ -722,7 +720,7 @@ static int qcom_iommu_ctx_probe(struct p + + dev_dbg(dev, "found asid %u\n", ctx->asid); + +- qcom_iommu->ctxs[ctx->asid - 1] = ctx; ++ qcom_iommu->ctxs[ctx->asid] = ctx; + + return 0; + } +@@ -734,7 +732,7 @@ static void qcom_iommu_ctx_remove(struct + + platform_set_drvdata(pdev, NULL); + +- qcom_iommu->ctxs[ctx->asid - 1] = NULL; ++ qcom_iommu->ctxs[ctx->asid] = NULL; + } + + static const struct of_device_id ctx_of_match[] = { +@@ -781,11 +779,11 @@ static int qcom_iommu_device_probe(struc + for_each_child_of_node(dev->of_node, child) + max_asid = max(max_asid, get_asid(child)); + +- qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid), ++ qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid + 1), + GFP_KERNEL); + if (!qcom_iommu) + return -ENOMEM; +- qcom_iommu->num_ctxs = max_asid; ++ qcom_iommu->max_asid = max_asid; + qcom_iommu->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/queue-6.1/iommu-qcom-use-the-asid-read-from-device-tree-if-specified.patch b/queue-6.1/iommu-qcom-use-the-asid-read-from-device-tree-if-specified.patch new file mode 100644 index 0000000000..b3f64b78e2 --- /dev/null +++ b/queue-6.1/iommu-qcom-use-the-asid-read-from-device-tree-if-specified.patch @@ -0,0 +1,82 @@ +From stable+bounces-204842-greg=kroah.com@vger.kernel.org Mon Jan 5 16:55:01 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 10:44:51 -0500 +Subject: iommu/qcom: Use the asid read from device-tree if specified +To: stable@vger.kernel.org +Cc: AngeloGioacchino Del Regno , Marijn Suijten , Konrad Dybcio , Will Deacon , Sasha Levin +Message-ID: <20260105154453.2644685-3-sashal@kernel.org> + +From: AngeloGioacchino Del Regno + +[ Upstream commit fcf226f1f7083cba76af47bf8dd764b68b149cd2 ] + +As specified in this driver, the context banks are 0x1000 apart but +on some SoCs the context number does not necessarily match this +logic, hence we end up using the wrong ASID: keeping in mind that +this IOMMU implementation relies heavily on SCM (TZ) calls, it is +mandatory that we communicate the right context number. + +Since this is all about how context banks are mapped in firmware, +which may be board dependent (as a different firmware version may +eventually change the expected context bank numbers), introduce a +new property "qcom,ctx-asid": when found, the ASID will be forced +as read from the devicetree. + +When "qcom,ctx-asid" is not found, this driver retains the previous +behavior as to avoid breaking older devicetrees or systems that do +not require forcing ASID numbers. + +Signed-off-by: Marijn Suijten +[Marijn: Rebased over next-20221111] +Signed-off-by: AngeloGioacchino Del Regno +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20230622092742.74819-3-angelogioacchino.delregno@collabora.com +Signed-off-by: Will Deacon +Stable-dep-of: 6a3908ce56e6 ("iommu/qcom: fix device leak on of_xlate()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -563,7 +563,8 @@ static int qcom_iommu_of_xlate(struct de + * index into qcom_iommu->ctxs: + */ + if (WARN_ON(asid < 1) || +- WARN_ON(asid > qcom_iommu->num_ctxs)) { ++ WARN_ON(asid > qcom_iommu->num_ctxs) || ++ WARN_ON(qcom_iommu->ctxs[asid - 1] == NULL)) { + put_device(&iommu_pdev->dev); + return -EINVAL; + } +@@ -650,7 +651,8 @@ free_mem: + + static int get_asid(const struct device_node *np) + { +- u32 reg; ++ u32 reg, val; ++ int asid; + + /* read the "reg" property directly to get the relative address + * of the context bank, and calculate the asid from that: +@@ -658,7 +660,17 @@ static int get_asid(const struct device_ + if (of_property_read_u32_index(np, "reg", 0, ®)) + return -ENODEV; + +- return reg / 0x1000; /* context banks are 0x1000 apart */ ++ /* ++ * Context banks are 0x1000 apart but, in some cases, the ASID ++ * number doesn't match to this logic and needs to be passed ++ * from the DT configuration explicitly. ++ */ ++ if (!of_property_read_u32(np, "qcom,ctx-asid", &val)) ++ asid = val; ++ else ++ asid = reg / 0x1000; ++ ++ return asid; + } + + static int qcom_iommu_ctx_probe(struct platform_device *pdev) diff --git a/queue-6.1/jbd2-fix-the-inconsistency-between-checksum-and-data-in-memory-for-journal-sb.patch b/queue-6.1/jbd2-fix-the-inconsistency-between-checksum-and-data-in-memory-for-journal-sb.patch new file mode 100644 index 0000000000..f75120da41 --- /dev/null +++ b/queue-6.1/jbd2-fix-the-inconsistency-between-checksum-and-data-in-memory-for-journal-sb.patch @@ -0,0 +1,94 @@ +From stable+bounces-204159-greg=kroah.com@vger.kernel.org Tue Dec 30 01:47:21 2025 +From: Sasha Levin +Date: Mon, 29 Dec 2025 19:46:45 -0500 +Subject: jbd2: fix the inconsistency between checksum and data in memory for journal sb +To: stable@vger.kernel.org +Cc: Ye Bin , Baokun Li , "Darrick J. Wong" , Jan Kara , Theodore Ts'o , stable@kernel.org, Sasha Levin +Message-ID: <20251230004645.1895239-1-sashal@kernel.org> + +From: Ye Bin + +[ Upstream commit 6abfe107894af7e8ce3a2e120c619d81ee764ad5 ] + +Copying the file system while it is mounted as read-only results in +a mount failure: +[~]# mkfs.ext4 -F /dev/sdc +[~]# mount /dev/sdc -o ro /mnt/test +[~]# dd if=/dev/sdc of=/dev/sda bs=1M +[~]# mount /dev/sda /mnt/test1 +[ 1094.849826] JBD2: journal checksum error +[ 1094.850927] EXT4-fs (sda): Could not load journal inode +mount: mount /dev/sda on /mnt/test1 failed: Bad message + +The process described above is just an abstracted way I came up with to +reproduce the issue. In the actual scenario, the file system was mounted +read-only and then copied while it was still mounted. It was found that +the mount operation failed. The user intended to verify the data or use +it as a backup, and this action was performed during a version upgrade. +Above issue may happen as follows: +ext4_fill_super + set_journal_csum_feature_set(sb) + if (ext4_has_metadata_csum(sb)) + incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3; + if (test_opt(sb, JOURNAL_CHECKSUM) + jbd2_journal_set_features(sbi->s_journal, compat, 0, incompat); + lock_buffer(journal->j_sb_buffer); + sb->s_feature_incompat |= cpu_to_be32(incompat); + //The data in the journal sb was modified, but the checksum was not + updated, so the data remaining in memory has a mismatch between the + data and the checksum. + unlock_buffer(journal->j_sb_buffer); + +In this case, the journal sb copied over is in a state where the checksum +and data are inconsistent, so mounting fails. +To solve the above issue, update the checksum in memory after modifying +the journal sb. + +Fixes: 4fd5ea43bc11 ("jbd2: checksum journal superblock") +Signed-off-by: Ye Bin +Reviewed-by: Baokun Li +Reviewed-by: Darrick J. Wong +Reviewed-by: Jan Kara +Message-ID: <20251103010123.3753631-1-yebin@huaweicloud.com> +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +[ Changed jbd2_superblock_csum(sb) to jbd2_superblock_csum(journal, sb) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/jbd2/journal.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -2393,6 +2393,12 @@ int jbd2_journal_set_features(journal_t + sb->s_feature_compat |= cpu_to_be32(compat); + sb->s_feature_ro_compat |= cpu_to_be32(ro); + sb->s_feature_incompat |= cpu_to_be32(incompat); ++ /* ++ * Update the checksum now so that it is valid even for read-only ++ * filesystems where jbd2_write_superblock() doesn't get called. ++ */ ++ if (jbd2_journal_has_csum_v2or3(journal)) ++ sb->s_checksum = jbd2_superblock_csum(journal, sb); + unlock_buffer(journal->j_sb_buffer); + journal->j_revoke_records_per_block = + journal_revoke_records_per_block(journal); +@@ -2423,9 +2429,17 @@ void jbd2_journal_clear_features(journal + + sb = journal->j_superblock; + ++ lock_buffer(journal->j_sb_buffer); + sb->s_feature_compat &= ~cpu_to_be32(compat); + sb->s_feature_ro_compat &= ~cpu_to_be32(ro); + sb->s_feature_incompat &= ~cpu_to_be32(incompat); ++ /* ++ * Update the checksum now so that it is valid even for read-only ++ * filesystems where jbd2_write_superblock() doesn't get called. ++ */ ++ if (jbd2_journal_has_csum_v2or3(journal)) ++ sb->s_checksum = jbd2_superblock_csum(journal, sb); ++ unlock_buffer(journal->j_sb_buffer); + journal->j_revoke_records_per_block = + journal_revoke_records_per_block(journal); + } diff --git a/queue-6.1/kbuild-use-crc32-and-a-1mib-dictionary-for-xz-compressed-modules.patch b/queue-6.1/kbuild-use-crc32-and-a-1mib-dictionary-for-xz-compressed-modules.patch new file mode 100644 index 0000000000..8dee1f64bc --- /dev/null +++ b/queue-6.1/kbuild-use-crc32-and-a-1mib-dictionary-for-xz-compressed-modules.patch @@ -0,0 +1,39 @@ +From fbf5892df21a8ccfcb2fda0fd65bc3169c89ed28 Mon Sep 17 00:00:00 2001 +From: Martin Nybo Andersen +Date: Fri, 15 Sep 2023 12:15:39 +0200 +Subject: kbuild: Use CRC32 and a 1MiB dictionary for XZ compressed modules + +From: Martin Nybo Andersen + +commit fbf5892df21a8ccfcb2fda0fd65bc3169c89ed28 upstream. + +Kmod is now (since kmod commit 09c9f8c5df04 ("libkmod: Use kernel +decompression when available")) using the kernel decompressor, when +loading compressed modules. + +However, the kernel XZ decompressor is XZ Embedded, which doesn't +handle CRC64 and dictionaries larger than 1MiB. + +Use CRC32 and 1MiB dictionary when XZ compressing and installing +kernel modules. + +Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050582 +Signed-off-by: Martin Nybo Andersen +Signed-off-by: Masahiro Yamada +Cc: Christoph Biedl +Signed-off-by: Greg Kroah-Hartman +--- + scripts/Makefile.modinst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/scripts/Makefile.modinst ++++ b/scripts/Makefile.modinst +@@ -99,7 +99,7 @@ endif + quiet_cmd_gzip = GZIP $@ + cmd_gzip = $(KGZIP) -n -f $< + quiet_cmd_xz = XZ $@ +- cmd_xz = $(XZ) --lzma2=dict=2MiB -f $< ++ cmd_xz = $(XZ) --check=crc32 --lzma2=dict=1MiB -f $< + quiet_cmd_zstd = ZSTD $@ + cmd_zstd = $(ZSTD) -T0 --rm -f -q $< + diff --git a/queue-6.1/ksmbd-fix-out-of-bounds-in-parse_sec_desc.patch b/queue-6.1/ksmbd-fix-out-of-bounds-in-parse_sec_desc.patch new file mode 100644 index 0000000000..ac189fce53 --- /dev/null +++ b/queue-6.1/ksmbd-fix-out-of-bounds-in-parse_sec_desc.patch @@ -0,0 +1,73 @@ +From stable+bounces-200127-greg=kroah.com@vger.kernel.org Fri Dec 5 09:24:29 2025 +From: Rajani Kantha <681739313@139.com> +Date: Fri, 5 Dec 2025 15:35:08 +0800 +Subject: ksmbd: fix out-of-bounds in parse_sec_desc() +To: norbert@doyensec.com, linkinjeon@kernel.org, stfrench@microsoft.com +Cc: stable@vger.kernel.org +Message-ID: <20251205073508.4650-1-681739313@139.com> + +From: Namjae Jeon + +commit d6e13e19063db24f94b690159d0633aaf72a0f03 upstream. + +If osidoffset, gsidoffset and dacloffset could be greater than smb_ntsd +struct size. If it is smaller, It could cause slab-out-of-bounds. +And when validating sid, It need to check it included subauth array size. + +Cc: stable@vger.kernel.org +Reported-by: Norbert Szetei +Tested-by: Norbert Szetei +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Rajani Kantha <681739313@139.com> +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -815,6 +815,13 @@ static int parse_sid(struct smb_sid *psi + return -EINVAL; + } + ++ if (!psid->num_subauth) ++ return 0; ++ ++ if (psid->num_subauth > SID_MAX_SUB_AUTHORITIES || ++ end_of_acl < (char *)psid + 8 + sizeof(__le32) * psid->num_subauth) ++ return -EINVAL; ++ + return 0; + } + +@@ -856,6 +863,9 @@ int parse_sec_desc(struct user_namespace + pntsd->type = cpu_to_le16(DACL_PRESENT); + + if (pntsd->osidoffset) { ++ if (le32_to_cpu(pntsd->osidoffset) < sizeof(struct smb_ntsd)) ++ return -EINVAL; ++ + rc = parse_sid(owner_sid_ptr, end_of_acl); + if (rc) { + pr_err("%s: Error %d parsing Owner SID\n", __func__, rc); +@@ -871,6 +881,9 @@ int parse_sec_desc(struct user_namespace + } + + if (pntsd->gsidoffset) { ++ if (le32_to_cpu(pntsd->gsidoffset) < sizeof(struct smb_ntsd)) ++ return -EINVAL; ++ + rc = parse_sid(group_sid_ptr, end_of_acl); + if (rc) { + pr_err("%s: Error %d mapping Owner SID to gid\n", +@@ -892,6 +905,9 @@ int parse_sec_desc(struct user_namespace + pntsd->type |= cpu_to_le16(DACL_PROTECTED); + + if (dacloffset) { ++ if (dacloffset < sizeof(struct smb_ntsd)) ++ return -EINVAL; ++ + parse_dacl(user_ns, dacl_ptr, end_of_acl, + owner_sid_ptr, group_sid_ptr, fattr); + } diff --git a/queue-6.1/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch b/queue-6.1/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch new file mode 100644 index 0000000000..a04ab054d3 --- /dev/null +++ b/queue-6.1/kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch @@ -0,0 +1,93 @@ +From stable+bounces-204363-greg=kroah.com@vger.kernel.org Wed Dec 31 16:12:00 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 10:11:53 -0500 +Subject: KVM: nVMX: Immediately refresh APICv controls as needed on nested VM-Exit +To: stable@vger.kernel.org +Cc: Dongli Zhang , Chao Gao , Sean Christopherson , Sasha Levin +Message-ID: <20251231151153.3146021-1-sashal@kernel.org> + +From: Dongli Zhang + +[ Upstream commit 29763138830916f46daaa50e83e7f4f907a3236b ] + +If an APICv status updated was pended while L2 was active, immediately +refresh vmcs01's controls instead of pending KVM_REQ_APICV_UPDATE as +kvm_vcpu_update_apicv() only calls into vendor code if a change is +necessary. + +E.g. if APICv is inhibited, and then activated while L2 is running: + + kvm_vcpu_update_apicv() + | + -> __kvm_vcpu_update_apicv() + | + -> apic->apicv_active = true + | + -> vmx_refresh_apicv_exec_ctrl() + | + -> vmx->nested.update_vmcs01_apicv_status = true + | + -> return + +Then L2 exits to L1: + + __nested_vmx_vmexit() + | + -> kvm_make_request(KVM_REQ_APICV_UPDATE) + + vcpu_enter_guest(): KVM_REQ_APICV_UPDATE + -> kvm_vcpu_update_apicv() + | + -> __kvm_vcpu_update_apicv() + | + -> return // because if (apic->apicv_active == activate) + +Reported-by: Chao Gao +Closes: https://lore.kernel.org/all/aQ2jmnN8wUYVEawF@intel.com +Fixes: 7c69661e225c ("KVM: nVMX: Defer APICv updates while L2 is active until L1 is active") +Cc: stable@vger.kernel.org +Signed-off-by: Dongli Zhang +[sean: write changelog] +Link: https://patch.msgid.link/20251205231913.441872-3-seanjc@google.com +Signed-off-by: Sean Christopherson +[ exported vmx_refresh_apicv_exec_ctrl() and added declaration in vmx.h ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/vmx/nested.c | 2 +- + arch/x86/kvm/vmx/vmx.c | 2 +- + arch/x86/kvm/vmx/vmx.h | 1 + + 3 files changed, 3 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -4847,7 +4847,7 @@ void nested_vmx_vmexit(struct kvm_vcpu * + + if (vmx->nested.update_vmcs01_apicv_status) { + vmx->nested.update_vmcs01_apicv_status = false; +- kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); ++ vmx_refresh_apicv_exec_ctrl(vcpu); + } + + if (vmx->nested.update_vmcs01_hwapic_isr) { +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -4387,7 +4387,7 @@ static u32 vmx_vmexit_ctrl(void) + ~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER); + } + +-static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) ++void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); + +--- a/arch/x86/kvm/vmx/vmx.h ++++ b/arch/x86/kvm/vmx/vmx.h +@@ -408,6 +408,7 @@ void __vmx_set_segment(struct kvm_vcpu * + u64 construct_eptp(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); + + bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu); ++void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu); + void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu); + bool vmx_nmi_blocked(struct kvm_vcpu *vcpu); + bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu); diff --git a/queue-6.1/kvm-svm-don-t-skip-unrelated-instruction-if-int3-into-is-replaced.patch b/queue-6.1/kvm-svm-don-t-skip-unrelated-instruction-if-int3-into-is-replaced.patch new file mode 100644 index 0000000000..db3879cd7d --- /dev/null +++ b/queue-6.1/kvm-svm-don-t-skip-unrelated-instruction-if-int3-into-is-replaced.patch @@ -0,0 +1,202 @@ +From stable+bounces-200323-greg=kroah.com@vger.kernel.org Mon Dec 8 07:17:34 2025 +From: Sasha Levin +Date: Mon, 8 Dec 2025 01:17:27 -0500 +Subject: KVM: SVM: Don't skip unrelated instruction if INT3/INTO is replaced +To: stable@vger.kernel.org +Cc: Omar Sandoval , Sean Christopherson , Sasha Levin +Message-ID: <20251208061727.249698-2-sashal@kernel.org> + +From: Omar Sandoval + +[ Upstream commit 4da3768e1820cf15cced390242d8789aed34f54d ] + +When re-injecting a soft interrupt from an INT3, INT0, or (select) INTn +instruction, discard the exception and retry the instruction if the code +stream is changed (e.g. by a different vCPU) between when the CPU +executes the instruction and when KVM decodes the instruction to get the +next RIP. + +As effectively predicted by commit 6ef88d6e36c2 ("KVM: SVM: Re-inject +INT3/INTO instead of retrying the instruction"), failure to verify that +the correct INTn instruction was decoded can effectively clobber guest +state due to decoding the wrong instruction and thus specifying the +wrong next RIP. + +The bug most often manifests as "Oops: int3" panics on static branch +checks in Linux guests. Enabling or disabling a static branch in Linux +uses the kernel's "text poke" code patching mechanism. To modify code +while other CPUs may be executing that code, Linux (temporarily) +replaces the first byte of the original instruction with an int3 (opcode +0xcc), then patches in the new code stream except for the first byte, +and finally replaces the int3 with the first byte of the new code +stream. If a CPU hits the int3, i.e. executes the code while it's being +modified, then the guest kernel must look up the RIP to determine how to +handle the #BP, e.g. by emulating the new instruction. If the RIP is +incorrect, then this lookup fails and the guest kernel panics. + +The bug reproduces almost instantly by hacking the guest kernel to +repeatedly check a static branch[1] while running a drgn script[2] on +the host to constantly swap out the memory containing the guest's TSS. + +[1]: https://gist.github.com/osandov/44d17c51c28c0ac998ea0334edf90b5a +[2]: https://gist.github.com/osandov/10e45e45afa29b11e0c7209247afc00b + +Fixes: 6ef88d6e36c2 ("KVM: SVM: Re-inject INT3/INTO instead of retrying the instruction") +Cc: stable@vger.kernel.org +Co-developed-by: Sean Christopherson +Signed-off-by: Omar Sandoval +Link: https://patch.msgid.link/1cc6dcdf36e3add7ee7c8d90ad58414eeb6c3d34.1762278762.git.osandov@fb.com +Signed-off-by: Sean Christopherson +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/kvm_host.h | 9 +++++++++ + arch/x86/kvm/svm/svm.c | 24 +++++++++++++----------- + arch/x86/kvm/x86.c | 21 +++++++++++++++++++++ + 3 files changed, 43 insertions(+), 11 deletions(-) + +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -1827,6 +1827,11 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); + * the gfn, i.e. retrying the instruction will hit a + * !PRESENT fault, which results in a new shadow page + * and sends KVM back to square one. ++ * ++ * EMULTYPE_SKIP_SOFT_INT - Set in combination with EMULTYPE_SKIP to only skip ++ * an instruction if it could generate a given software ++ * interrupt, which must be encoded via ++ * EMULTYPE_SET_SOFT_INT_VECTOR(). + */ + #define EMULTYPE_NO_DECODE (1 << 0) + #define EMULTYPE_TRAP_UD (1 << 1) +@@ -1837,6 +1842,10 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); + #define EMULTYPE_PF (1 << 6) + #define EMULTYPE_COMPLETE_USER_EXIT (1 << 7) + #define EMULTYPE_WRITE_PF_TO_SP (1 << 8) ++#define EMULTYPE_SKIP_SOFT_INT (1 << 9) ++ ++#define EMULTYPE_SET_SOFT_INT_VECTOR(v) ((u32)((v) & 0xff) << 16) ++#define EMULTYPE_GET_SOFT_INT_VECTOR(e) (((e) >> 16) & 0xff) + + int kvm_emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type); + int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu, +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -370,6 +370,7 @@ static bool svm_can_emulate_instruction( + void *insn, int insn_len); + + static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, ++ int emul_type, + bool commit_side_effects) + { + struct vcpu_svm *svm = to_svm(vcpu); +@@ -399,7 +400,7 @@ static int __svm_skip_emulated_instructi + if (unlikely(!commit_side_effects)) + old_rflags = svm->vmcb->save.rflags; + +- if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) ++ if (!kvm_emulate_instruction(vcpu, emul_type)) + return 0; + + if (unlikely(!commit_side_effects)) +@@ -417,11 +418,13 @@ done: + + static int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) + { +- return __svm_skip_emulated_instruction(vcpu, true); ++ return __svm_skip_emulated_instruction(vcpu, EMULTYPE_SKIP, true); + } + +-static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu) ++static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu, u8 vector) + { ++ const int emul_type = EMULTYPE_SKIP | EMULTYPE_SKIP_SOFT_INT | ++ EMULTYPE_SET_SOFT_INT_VECTOR(vector); + unsigned long rip, old_rip = kvm_rip_read(vcpu); + struct vcpu_svm *svm = to_svm(vcpu); + +@@ -437,7 +440,7 @@ static int svm_update_soft_interrupt_rip + * in use, the skip must not commit any side effects such as clearing + * the interrupt shadow or RFLAGS.RF. + */ +- if (!__svm_skip_emulated_instruction(vcpu, !nrips)) ++ if (!__svm_skip_emulated_instruction(vcpu, emul_type, !nrips)) + return -EIO; + + rip = kvm_rip_read(vcpu); +@@ -473,7 +476,7 @@ static void svm_inject_exception(struct + kvm_deliver_exception_payload(vcpu, ex); + + if (kvm_exception_is_soft(ex->vector) && +- svm_update_soft_interrupt_rip(vcpu)) ++ svm_update_soft_interrupt_rip(vcpu, ex->vector)) + return; + + svm->vmcb->control.event_inj = ex->vector +@@ -3524,11 +3527,12 @@ static void svm_inject_nmi(struct kvm_vc + + static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) + { ++ struct kvm_queued_interrupt *intr = &vcpu->arch.interrupt; + struct vcpu_svm *svm = to_svm(vcpu); + u32 type; + +- if (vcpu->arch.interrupt.soft) { +- if (svm_update_soft_interrupt_rip(vcpu)) ++ if (intr->soft) { ++ if (svm_update_soft_interrupt_rip(vcpu, intr->nr)) + return; + + type = SVM_EVTINJ_TYPE_SOFT; +@@ -3536,12 +3540,10 @@ static void svm_inject_irq(struct kvm_vc + type = SVM_EVTINJ_TYPE_INTR; + } + +- trace_kvm_inj_virq(vcpu->arch.interrupt.nr, +- vcpu->arch.interrupt.soft, reinjected); ++ trace_kvm_inj_virq(intr->nr, intr->soft, reinjected); + ++vcpu->stat.irq_injections; + +- svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | +- SVM_EVTINJ_VALID | type; ++ svm->vmcb->control.event_inj = intr->nr | SVM_EVTINJ_VALID | type; + } + + void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -8840,6 +8840,23 @@ static bool is_vmware_backdoor_opcode(st + return false; + } + ++static bool is_soft_int_instruction(struct x86_emulate_ctxt *ctxt, ++ int emulation_type) ++{ ++ u8 vector = EMULTYPE_GET_SOFT_INT_VECTOR(emulation_type); ++ ++ switch (ctxt->b) { ++ case 0xcc: ++ return vector == BP_VECTOR; ++ case 0xcd: ++ return vector == ctxt->src.val; ++ case 0xce: ++ return vector == OF_VECTOR; ++ default: ++ return false; ++ } ++} ++ + /* + * Decode an instruction for emulation. The caller is responsible for handling + * code breakpoints. Note, manually detecting code breakpoints is unnecessary +@@ -8930,6 +8947,10 @@ int x86_emulate_instruction(struct kvm_v + * injecting single-step #DBs. + */ + if (emulation_type & EMULTYPE_SKIP) { ++ if (emulation_type & EMULTYPE_SKIP_SOFT_INT && ++ !is_soft_int_instruction(ctxt, emulation_type)) ++ return 0; ++ + if (ctxt->mode != X86EMUL_MODE_PROT64) + ctxt->eip = (u32)ctxt->_eip; + else diff --git a/queue-6.1/kvm-x86-mmu-use-emultype-flag-to-track-write-pfs-to-shadow-pages.patch b/queue-6.1/kvm-x86-mmu-use-emultype-flag-to-track-write-pfs-to-shadow-pages.patch new file mode 100644 index 0000000000..81e13524de --- /dev/null +++ b/queue-6.1/kvm-x86-mmu-use-emultype-flag-to-track-write-pfs-to-shadow-pages.patch @@ -0,0 +1,230 @@ +From stable+bounces-200322-greg=kroah.com@vger.kernel.org Mon Dec 8 07:17:38 2025 +From: Sasha Levin +Date: Mon, 8 Dec 2025 01:17:26 -0500 +Subject: KVM: x86/mmu: Use EMULTYPE flag to track write #PFs to shadow pages +To: stable@vger.kernel.org +Cc: Sean Christopherson , Paolo Bonzini , Sasha Levin +Message-ID: <20251208061727.249698-1-sashal@kernel.org> + +From: Sean Christopherson + +[ Upstream commit 258d985f6eb360c9c7aacd025d0dbc080a59423f ] + +Use a new EMULTYPE flag, EMULTYPE_WRITE_PF_TO_SP, to track page faults +on self-changing writes to shadowed page tables instead of propagating +that information to the emulator via a semi-persistent vCPU flag. Using +a flag in "struct kvm_vcpu_arch" is confusing, especially as implemented, +as it's not at all obvious that clearing the flag only when emulation +actually occurs is correct. + +E.g. if KVM sets the flag and then retries the fault without ever getting +to the emulator, the flag will be left set for future calls into the +emulator. But because the flag is consumed if and only if both +EMULTYPE_PF and EMULTYPE_ALLOW_RETRY_PF are set, and because +EMULTYPE_ALLOW_RETRY_PF is deliberately not set for direct MMUs, emulated +MMIO, or while L2 is active, KVM avoids false positives on a stale flag +since FNAME(page_fault) is guaranteed to be run and refresh the flag +before it's ultimately consumed by the tail end of reexecute_instruction(). + +Signed-off-by: Sean Christopherson +Message-Id: <20230202182817.407394-2-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Stable-dep-of: 4da3768e1820 ("KVM: SVM: Don't skip unrelated instruction if INT3/INTO is replaced") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/kvm_host.h | 37 ++++++++++++++++++++----------------- + arch/x86/kvm/mmu/mmu.c | 5 +++-- + arch/x86/kvm/mmu/mmu_internal.h | 12 +++++++++++- + arch/x86/kvm/mmu/paging_tmpl.h | 4 +--- + arch/x86/kvm/x86.c | 15 ++------------- + 5 files changed, 37 insertions(+), 36 deletions(-) + +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -890,23 +890,6 @@ struct kvm_vcpu_arch { + + u64 msr_kvm_poll_control; + +- /* +- * Indicates the guest is trying to write a gfn that contains one or +- * more of the PTEs used to translate the write itself, i.e. the access +- * is changing its own translation in the guest page tables. KVM exits +- * to userspace if emulation of the faulting instruction fails and this +- * flag is set, as KVM cannot make forward progress. +- * +- * If emulation fails for a write to guest page tables, KVM unprotects +- * (zaps) the shadow page for the target gfn and resumes the guest to +- * retry the non-emulatable instruction (on hardware). Unprotecting the +- * gfn doesn't allow forward progress for a self-changing access because +- * doing so also zaps the translation for the gfn, i.e. retrying the +- * instruction will hit a !PRESENT fault, which results in a new shadow +- * page and sends KVM back to square one. +- */ +- bool write_fault_to_shadow_pgtable; +- + /* set at EPT violation at this point */ + unsigned long exit_qualification; + +@@ -1825,6 +1808,25 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); + * EMULTYPE_COMPLETE_USER_EXIT - Set when the emulator should update interruptibility + * state and inject single-step #DBs after skipping + * an instruction (after completing userspace I/O). ++ * ++ * EMULTYPE_WRITE_PF_TO_SP - Set when emulating an intercepted page fault that ++ * is attempting to write a gfn that contains one or ++ * more of the PTEs used to translate the write itself, ++ * and the owning page table is being shadowed by KVM. ++ * If emulation of the faulting instruction fails and ++ * this flag is set, KVM will exit to userspace instead ++ * of retrying emulation as KVM cannot make forward ++ * progress. ++ * ++ * If emulation fails for a write to guest page tables, ++ * KVM unprotects (zaps) the shadow page for the target ++ * gfn and resumes the guest to retry the non-emulatable ++ * instruction (on hardware). Unprotecting the gfn ++ * doesn't allow forward progress for a self-changing ++ * access because doing so also zaps the translation for ++ * the gfn, i.e. retrying the instruction will hit a ++ * !PRESENT fault, which results in a new shadow page ++ * and sends KVM back to square one. + */ + #define EMULTYPE_NO_DECODE (1 << 0) + #define EMULTYPE_TRAP_UD (1 << 1) +@@ -1834,6 +1836,7 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); + #define EMULTYPE_VMWARE_GP (1 << 5) + #define EMULTYPE_PF (1 << 6) + #define EMULTYPE_COMPLETE_USER_EXIT (1 << 7) ++#define EMULTYPE_WRITE_PF_TO_SP (1 << 8) + + int kvm_emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type); + int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu, +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -4152,7 +4152,7 @@ void kvm_arch_async_page_ready(struct kv + work->arch.cr3 != kvm_mmu_get_guest_pgd(vcpu, vcpu->arch.mmu)) + return; + +- kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true); ++ kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true, NULL); + } + + static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) +@@ -5580,7 +5580,8 @@ int noinline kvm_mmu_page_fault(struct k + + if (r == RET_PF_INVALID) { + r = kvm_mmu_do_page_fault(vcpu, cr2_or_gpa, +- lower_32_bits(error_code), false); ++ lower_32_bits(error_code), false, ++ &emulation_type); + if (KVM_BUG_ON(r == RET_PF_INVALID, vcpu->kvm)) + return -EIO; + } +--- a/arch/x86/kvm/mmu/mmu_internal.h ++++ b/arch/x86/kvm/mmu/mmu_internal.h +@@ -223,6 +223,13 @@ struct kvm_page_fault { + kvm_pfn_t pfn; + hva_t hva; + bool map_writable; ++ ++ /* ++ * Indicates the guest is trying to write a gfn that contains one or ++ * more of the PTEs used to translate the write itself, i.e. the access ++ * is changing its own translation in the guest page tables. ++ */ ++ bool write_fault_to_shadow_pgtable; + }; + + int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); +@@ -256,7 +263,7 @@ enum { + }; + + static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, +- u32 err, bool prefetch) ++ u32 err, bool prefetch, int *emulation_type) + { + struct kvm_page_fault fault = { + .addr = cr2_or_gpa, +@@ -290,6 +297,9 @@ static inline int kvm_mmu_do_page_fault( + else + r = vcpu->arch.mmu->page_fault(vcpu, &fault); + ++ if (fault.write_fault_to_shadow_pgtable && emulation_type) ++ *emulation_type |= EMULTYPE_WRITE_PF_TO_SP; ++ + /* + * Similar to above, prefetch faults aren't truly spurious, and the + * async #PF path doesn't do emulation. Do count faults that are fixed +--- a/arch/x86/kvm/mmu/paging_tmpl.h ++++ b/arch/x86/kvm/mmu/paging_tmpl.h +@@ -829,10 +829,8 @@ static int FNAME(page_fault)(struct kvm_ + if (r) + return r; + +- vcpu->arch.write_fault_to_shadow_pgtable = false; +- + is_self_change_mapping = FNAME(is_self_change_mapping)(vcpu, +- &walker, fault->user, &vcpu->arch.write_fault_to_shadow_pgtable); ++ &walker, fault->user, &fault->write_fault_to_shadow_pgtable); + + if (is_self_change_mapping) + fault->max_level = PG_LEVEL_4K; +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -8532,7 +8532,6 @@ static int handle_emulation_failure(stru + } + + static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, +- bool write_fault_to_shadow_pgtable, + int emulation_type) + { + gpa_t gpa = cr2_or_gpa; +@@ -8603,7 +8602,7 @@ static bool reexecute_instruction(struct + * be fixed by unprotecting shadow page and it should + * be reported to userspace. + */ +- return !write_fault_to_shadow_pgtable; ++ return !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); + } + + static bool retry_instruction(struct x86_emulate_ctxt *ctxt, +@@ -8874,20 +8873,12 @@ int x86_emulate_instruction(struct kvm_v + int r; + struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; + bool writeback = true; +- bool write_fault_to_spt; + + if (unlikely(!kvm_can_emulate_insn(vcpu, emulation_type, insn, insn_len))) + return 1; + + vcpu->arch.l1tf_flush_l1d = true; + +- /* +- * Clear write_fault_to_shadow_pgtable here to ensure it is +- * never reused. +- */ +- write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable; +- vcpu->arch.write_fault_to_shadow_pgtable = false; +- + if (!(emulation_type & EMULTYPE_NO_DECODE)) { + kvm_clear_exception_queue(vcpu); + +@@ -8908,7 +8899,6 @@ int x86_emulate_instruction(struct kvm_v + return 1; + } + if (reexecute_instruction(vcpu, cr2_or_gpa, +- write_fault_to_spt, + emulation_type)) + return 1; + +@@ -8994,8 +8984,7 @@ restart: + return 1; + + if (r == EMULATION_FAILED) { +- if (reexecute_instruction(vcpu, cr2_or_gpa, write_fault_to_spt, +- emulation_type)) ++ if (reexecute_instruction(vcpu, cr2_or_gpa, emulation_type)) + return 1; + + return handle_emulation_failure(vcpu, emulation_type); diff --git a/queue-6.1/lockd-fix-vfs_test_lock-calls.patch b/queue-6.1/lockd-fix-vfs_test_lock-calls.patch new file mode 100644 index 0000000000..f8f3f67818 --- /dev/null +++ b/queue-6.1/lockd-fix-vfs_test_lock-calls.patch @@ -0,0 +1,182 @@ +From stable+bounces-206049-greg=kroah.com@vger.kernel.org Wed Jan 7 00:08:23 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 18:08:16 -0500 +Subject: lockd: fix vfs_test_lock() calls +To: stable@vger.kernel.org +Cc: NeilBrown , Olga Kornievskaia , Jeff Layton , Chuck Lever , Sasha Levin +Message-ID: <20260106230816.3448854-1-sashal@kernel.org> + +From: NeilBrown + +[ Upstream commit a49a2a1baa0c553c3548a1c414b6a3c005a8deba ] + +Usage of vfs_test_lock() is somewhat confused. Documentation suggests +it is given a "lock" but this is not the case. It is given a struct +file_lock which contains some details of the sort of lock it should be +looking for. + +In particular passing a "file_lock" containing fl_lmops or fl_ops is +meaningless and possibly confusing. + +This is particularly problematic in lockd. nlmsvc_testlock() receives +an initialised "file_lock" from xdr-decode, including manager ops and an +owner. It then mistakenly passes this to vfs_test_lock() which might +replace the owner and the ops. This can lead to confusion when freeing +the lock. + +The primary role of the 'struct file_lock' passed to vfs_test_lock() is +to report a conflicting lock that was found, so it makes more sense for +nlmsvc_testlock() to pass "conflock", which it uses for returning the +conflicting lock. + +With this change, freeing of the lock is not confused and code in +__nlm4svc_proc_test() and __nlmsvc_proc_test() can be simplified. + +Documentation for vfs_test_lock() is improved to reflect its real +purpose, and a WARN_ON_ONCE() is added to avoid a similar problem in the +future. + +Reported-by: Olga Kornievskaia +Closes: https://lore.kernel.org/all/20251021130506.45065-1-okorniev@redhat.com +Signed-off-by: NeilBrown +Fixes: 20fa19027286 ("nfs: add export operations") +Cc: stable@vger.kernel.org +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +[ adapted c.flc_* field accesses to direct fl_* fields ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/lockd/svc4proc.c | 4 +--- + fs/lockd/svclock.c | 21 ++++++++++++--------- + fs/lockd/svcproc.c | 5 +---- + fs/locks.c | 13 +++++++++++-- + 4 files changed, 25 insertions(+), 18 deletions(-) + +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -96,7 +96,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqs + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_host *host; + struct nlm_file *file; +- struct nlm_lockowner *test_owner; + __be32 rc = rpc_success; + + dprintk("lockd: TEST4 called\n"); +@@ -106,7 +105,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqs + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + +- test_owner = argp->lock.fl.fl_owner; + /* Now check for conflicting locks */ + resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie); + if (resp->status == nlm_drop_reply) +@@ -114,7 +112,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqs + else + dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); + +- nlmsvc_put_lockowner(test_owner); ++ nlmsvc_release_lockowner(&argp->lock); + nlmsvc_release_host(host); + nlm_release_file(file); + return rc; +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -604,7 +604,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, + } + + mode = lock_to_openmode(&lock->fl); +- error = vfs_test_lock(file->f_file[mode], &lock->fl); ++ locks_init_lock(&conflock->fl); ++ /* vfs_test_lock only uses start, end, and owner, but tests fl_file */ ++ conflock->fl.fl_file = lock->fl.fl_file; ++ conflock->fl.fl_start = lock->fl.fl_start; ++ conflock->fl.fl_end = lock->fl.fl_end; ++ conflock->fl.fl_owner = lock->fl.fl_owner; ++ error = vfs_test_lock(file->f_file[mode], &conflock->fl); + if (error) { + /* We can't currently deal with deferred test requests */ + if (error == FILE_LOCK_DEFERRED) +@@ -614,22 +620,19 @@ nlmsvc_testlock(struct svc_rqst *rqstp, + goto out; + } + +- if (lock->fl.fl_type == F_UNLCK) { ++ if (conflock->fl.fl_type == F_UNLCK) { + ret = nlm_granted; + goto out; + } + + dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", +- lock->fl.fl_type, (long long)lock->fl.fl_start, +- (long long)lock->fl.fl_end); ++ conflock->fl.fl_type, (long long)conflock->fl.fl_start, ++ (long long)conflock->fl.fl_end); + conflock->caller = "somehost"; /* FIXME */ + conflock->len = strlen(conflock->caller); + conflock->oh.len = 0; /* don't return OH info */ +- conflock->svid = lock->fl.fl_pid; +- conflock->fl.fl_type = lock->fl.fl_type; +- conflock->fl.fl_start = lock->fl.fl_start; +- conflock->fl.fl_end = lock->fl.fl_end; +- locks_release_private(&lock->fl); ++ conflock->svid = conflock->fl.fl_pid; ++ locks_release_private(&conflock->fl); + + ret = nlm_lck_denied; + out: +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -117,7 +117,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqst + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_host *host; + struct nlm_file *file; +- struct nlm_lockowner *test_owner; + __be32 rc = rpc_success; + + dprintk("lockd: TEST called\n"); +@@ -127,8 +126,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqst + if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + +- test_owner = argp->lock.fl.fl_owner; +- + /* Now check for conflicting locks */ + resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie)); + if (resp->status == nlm_drop_reply) +@@ -137,7 +134,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqst + dprintk("lockd: TEST status %d vers %d\n", + ntohl(resp->status), rqstp->rq_vers); + +- nlmsvc_put_lockowner(test_owner); ++ nlmsvc_release_lockowner(&argp->lock); + nlmsvc_release_host(host); + nlm_release_file(file); + return rc; +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2140,13 +2140,22 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, + /** + * vfs_test_lock - test file byte range lock + * @filp: The file to test lock for +- * @fl: The lock to test; also used to hold result ++ * @fl: The byte-range in the file to test; also used to hold result + * ++ * On entry, @fl does not contain a lock, but identifies a range (fl_start, fl_end) ++ * in the file (c.flc_file), and an owner (c.flc_owner) for whom existing locks ++ * should be ignored. c.flc_type and c.flc_flags are ignored. ++ * Both fl_lmops and fl_ops in @fl must be NULL. + * Returns -ERRNO on failure. Indicates presence of conflicting lock by +- * setting conf->fl_type to something other than F_UNLCK. ++ * setting fl->fl_type to something other than F_UNLCK. ++ * ++ * If vfs_test_lock() does find a lock and return it, the caller must ++ * use locks_free_lock() or locks_release_private() on the returned lock. + */ + int vfs_test_lock(struct file *filp, struct file_lock *fl) + { ++ WARN_ON_ONCE(fl->fl_ops || fl->fl_lmops); ++ WARN_ON_ONCE(filp != fl->fl_file); + if (filp->f_op->lock) + return filp->f_op->lock(filp, F_GETLK, fl); + posix_test_lock(filp, fl); diff --git a/queue-6.1/media-amphion-add-a-frame-flush-mode-for-decoder.patch b/queue-6.1/media-amphion-add-a-frame-flush-mode-for-decoder.patch new file mode 100644 index 0000000000..6511338f8c --- /dev/null +++ b/queue-6.1/media-amphion-add-a-frame-flush-mode-for-decoder.patch @@ -0,0 +1,64 @@ +From stable+bounces-204943-greg=kroah.com@vger.kernel.org Mon Jan 5 22:33:57 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:32:22 -0500 +Subject: media: amphion: Add a frame flush mode for decoder +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Sebastian Fricke , Hans Verkuil , Sasha Levin +Message-ID: <20260105213224.2805653-1-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 9ea16ba6eaf93f25f61855751f71e2e701709ddf ] + +By default the amphion decoder will pre-parse 3 frames before starting +to decode the first frame. Alternatively, a block of flush padding data +can be appended to the frame, which will ensure that the decoder can +start decoding immediately after parsing the flush padding data, thus +potentially reducing decoding latency. + +This mode was previously only enabled, when the display delay was set to +0. Allow the user to manually toggle the use of that mode via a module +parameter called low_latency, which enables the mode without +changing the display order. + +Signed-off-by: Ming Qian +Reviewed-by: Nicolas Dufresne +Signed-off-by: Sebastian Fricke +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -27,6 +27,10 @@ + #include "vpu_imx8q.h" + #include "vpu_malone.h" + ++static bool low_latency; ++module_param(low_latency, bool, 0644); ++MODULE_PARM_DESC(low_latency, "Set low latency frame flush mode: 0 (disable) or 1 (enable)"); ++ + #define CMD_SIZE 25600 + #define MSG_SIZE 25600 + #define CODEC_SIZE 0x1000 +@@ -1527,7 +1531,15 @@ static int vpu_malone_input_frame_data(s + + vpu_malone_update_wptr(str_buf, wptr); + +- if (disp_imm && !vpu_vb_is_codecconfig(vbuf)) { ++ /* ++ * Enable the low latency flush mode if display delay is set to 0 ++ * or the low latency frame flush mode if it is set to 1. ++ * The low latency flush mode requires some padding data to be appended to each frame, ++ * but there must not be any padding data between the sequence header and the frame. ++ * This module is currently only supported for the H264 and HEVC formats, ++ * for other formats, vpu_malone_add_scode() will return 0. ++ */ ++ if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, diff --git a/queue-6.1/media-amphion-make-some-vpu_v4l2-functions-static.patch b/queue-6.1/media-amphion-make-some-vpu_v4l2-functions-static.patch new file mode 100644 index 0000000000..f2cefed81e --- /dev/null +++ b/queue-6.1/media-amphion-make-some-vpu_v4l2-functions-static.patch @@ -0,0 +1,98 @@ +From stable+bounces-204944-greg=kroah.com@vger.kernel.org Mon Jan 5 22:34:00 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:32:23 -0500 +Subject: media: amphion: Make some vpu_v4l2 functions static +To: stable@vger.kernel.org +Cc: Laurent Pinchart , Ming Qian , Hans Verkuil , Sasha Levin +Message-ID: <20260105213224.2805653-2-sashal@kernel.org> + +From: Laurent Pinchart + +[ Upstream commit 5d1e54bb4dc6741284a3ed587e994308ddee2f16 ] + +Some functions defined in vpu_v4l2.c are never used outside of that +compilation unit. Make them static. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Ming Qian +Signed-off-by: Hans Verkuil +Stable-dep-of: 634c2cd17bd0 ("media: amphion: Remove vpu_vb_is_codecconfig") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_v4l2.c | 12 +++++++++--- + drivers/media/platform/amphion/vpu_v4l2.h | 8 -------- + 2 files changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -24,6 +24,11 @@ + #include "vpu_msgs.h" + #include "vpu_helpers.h" + ++static char *vpu_type_name(u32 type) ++{ ++ return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; ++} ++ + void vpu_inst_lock(struct vpu_inst *inst) + { + mutex_lock(&inst->lock); +@@ -42,7 +47,7 @@ dma_addr_t vpu_get_vb_phy_addr(struct vb + vb->planes[plane_no].data_offset; + } + +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) ++static unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) + { + if (plane_no >= vb->num_planes) + return 0; +@@ -74,7 +79,7 @@ void vpu_v4l2_set_error(struct vpu_inst + vpu_inst_unlock(inst); + } + +-int vpu_notify_eos(struct vpu_inst *inst) ++static int vpu_notify_eos(struct vpu_inst *inst) + { + static const struct v4l2_event ev = { + .id = 0, +@@ -461,7 +466,8 @@ static void vpu_vb2_buf_finish(struct vb + call_void_vop(inst, on_queue_empty, q->type); + } + +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state) ++static void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, ++ enum vb2_buffer_state state) + { + struct vb2_v4l2_buffer *buf; + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -24,15 +24,12 @@ void vpu_skip_frame(struct vpu_inst *ins + struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); + struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); + void vpu_v4l2_set_error(struct vpu_inst *inst); +-int vpu_notify_eos(struct vpu_inst *inst); + int vpu_notify_source_change(struct vpu_inst *inst); + int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos); +-void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); + int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); + bool vpu_is_source_empty(struct vpu_inst *inst); + + dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); +-unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); + static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) + { + if (V4L2_TYPE_IS_OUTPUT(type)) +@@ -41,11 +38,6 @@ static inline struct vpu_format *vpu_get + return &inst->cap_format; + } + +-static inline char *vpu_type_name(u32 type) +-{ +- return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; +-} +- + static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) + { + #ifdef V4L2_BUF_FLAG_CODECCONFIG diff --git a/queue-6.1/media-amphion-remove-vpu_vb_is_codecconfig.patch b/queue-6.1/media-amphion-remove-vpu_vb_is_codecconfig.patch new file mode 100644 index 0000000000..2c78d83e3c --- /dev/null +++ b/queue-6.1/media-amphion-remove-vpu_vb_is_codecconfig.patch @@ -0,0 +1,142 @@ +From stable+bounces-204945-greg=kroah.com@vger.kernel.org Mon Jan 5 22:34:06 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 16:32:24 -0500 +Subject: media: amphion: Remove vpu_vb_is_codecconfig +To: stable@vger.kernel.org +Cc: Ming Qian , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260105213224.2805653-3-sashal@kernel.org> + +From: Ming Qian + +[ Upstream commit 634c2cd17bd021487c57b95973bddb14be8002ff ] + +Currently the function vpu_vb_is_codecconfig() always returns 0. +Delete it and its related code. + +Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") +Cc: stable@vger.kernel.org +Signed-off-by: Ming Qian +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/amphion/vpu_malone.c | 23 +++-------------------- + drivers/media/platform/amphion/vpu_v4l2.c | 10 ---------- + drivers/media/platform/amphion/vpu_v4l2.h | 10 ---------- + 3 files changed, 3 insertions(+), 40 deletions(-) + +--- a/drivers/media/platform/amphion/vpu_malone.c ++++ b/drivers/media/platform/amphion/vpu_malone.c +@@ -1295,22 +1295,18 @@ static int vpu_malone_insert_scode_vc1_g + { + if (!scode->inst->total_input_count) + return 0; +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + return 0; + } + + static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) + { +- struct vb2_v4l2_buffer *vbuf; + u8 nal_hdr[MALONE_VC1_NAL_HEADER_LEN]; + u32 *data = NULL; + int ret; + +- vbuf = to_vb2_v4l2_buffer(scode->vb); + data = vb2_plane_vaddr(scode->vb, 0); + +- if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (scode->inst->total_input_count == 0) + return 0; + if (MALONE_VC1_CONTAIN_NAL(*data)) + return 0; +@@ -1331,8 +1327,6 @@ static int vpu_malone_insert_scode_vc1_l + int size = 0; + u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; + +- if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) +- scode->need_data = 0; + if (scode->inst->total_input_count) + return 0; + scode->need_data = 0; +@@ -1503,7 +1497,7 @@ static int vpu_malone_input_frame_data(s + scode.vb = vb; + scode.wptr = wptr; + scode.need_data = 1; +- if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) ++ if (vbuf->sequence == 0) + ret = vpu_malone_insert_scode(&scode, SCODE_SEQUENCE); + + if (ret < 0) +@@ -1539,7 +1533,7 @@ static int vpu_malone_input_frame_data(s + * This module is currently only supported for the H264 and HEVC formats, + * for other formats, vpu_malone_add_scode() will return 0. + */ +- if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { ++ if (disp_imm || low_latency) { + ret = vpu_malone_add_scode(inst->core->iface, + inst->id, + &inst->stream_buffer, +@@ -1586,7 +1580,6 @@ int vpu_malone_input_frame(struct vpu_sh + struct vpu_inst *inst, struct vb2_buffer *vb) + { + struct vpu_dec_ctrl *hc = shared->priv; +- struct vb2_v4l2_buffer *vbuf; + struct vpu_malone_str_buffer __iomem *str_buf = hc->str_buf[inst->id]; + u32 disp_imm = hc->codec_param[inst->id].disp_imm; + u32 size; +@@ -1600,16 +1593,6 @@ int vpu_malone_input_frame(struct vpu_sh + return ret; + size = ret; + +- /* +- * if buffer only contain codec data, and the timestamp is invalid, +- * don't put the invalid timestamp to resync +- * merge the data to next frame +- */ +- vbuf = to_vb2_v4l2_buffer(vb); +- if (vpu_vb_is_codecconfig(vbuf)) { +- inst->extra_size += size; +- return 0; +- } + if (inst->extra_size) { + size += inst->extra_size; + inst->extra_size = 0; +--- a/drivers/media/platform/amphion/vpu_v4l2.c ++++ b/drivers/media/platform/amphion/vpu_v4l2.c +@@ -257,16 +257,6 @@ struct vb2_v4l2_buffer *vpu_next_src_buf + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + +- while (vpu_vb_is_codecconfig(src_buf)) { +- v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); +- vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); +- v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); +- +- src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); +- if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) +- return NULL; +- } +- + return src_buf; + } + +--- a/drivers/media/platform/amphion/vpu_v4l2.h ++++ b/drivers/media/platform/amphion/vpu_v4l2.h +@@ -37,14 +37,4 @@ static inline struct vpu_format *vpu_get + else + return &inst->cap_format; + } +- +-static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) +-{ +-#ifdef V4L2_BUF_FLAG_CODECCONFIG +- return (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) ? 1 : 0; +-#else +- return 0; +-#endif +-} +- + #endif diff --git a/queue-6.1/media-mediatek-vcodec-fix-a-reference-leak-in-mtk_vcodec_fw_vpu_init.patch b/queue-6.1/media-mediatek-vcodec-fix-a-reference-leak-in-mtk_vcodec_fw_vpu_init.patch new file mode 100644 index 0000000000..0b33296566 --- /dev/null +++ b/queue-6.1/media-mediatek-vcodec-fix-a-reference-leak-in-mtk_vcodec_fw_vpu_init.patch @@ -0,0 +1,47 @@ +From stable+bounces-204956-greg=kroah.com@vger.kernel.org Tue Jan 6 00:32:09 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 18:31:38 -0500 +Subject: media: mediatek: vcodec: Fix a reference leak in mtk_vcodec_fw_vpu_init() +To: stable@vger.kernel.org +Cc: Haoxiang Li , AngeloGioacchino Del Regno , Tzung-Bi Shih , Nicolas Dufresne , Hans Verkuil , Sasha Levin +Message-ID: <20260105233138.2845766-1-sashal@kernel.org> + +From: Haoxiang Li + +[ Upstream commit cdd0f118ef87db8a664fb5ea366fd1766d2df1cd ] + +vpu_get_plat_device() increases the reference count of the returned +platform device. However, when devm_kzalloc() fails, the reference +is not released, causing a reference leak. + +Fix this by calling put_device() on fw_pdev->dev before returning +on the error path. + +Fixes: e25a89f743b1 ("media: mtk-vcodec: potential dereference of null pointer") +Cc: stable@vger.kernel.org +Signed-off-by: Haoxiang Li +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Tzung-Bi Shih +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +[ adapted file path from common/ subdirectory and adjusted devm_kzalloc target from plat_dev->dev to dev->plat_dev->dev ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw_vpu.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw_vpu.c ++++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw_vpu.c +@@ -94,8 +94,10 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_ + vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id); + + fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); +- if (!fw) ++ if (!fw) { ++ put_device(&fw_pdev->dev); + return ERR_PTR(-ENOMEM); ++ } + fw->type = VPU; + fw->ops = &mtk_vcodec_vpu_msg; + fw->pdev = fw_pdev; diff --git a/queue-6.1/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch b/queue-6.1/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch new file mode 100644 index 0000000000..88ba344f17 --- /dev/null +++ b/queue-6.1/media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch @@ -0,0 +1,236 @@ +From stable+bounces-204883-greg=kroah.com@vger.kernel.org Mon Jan 5 18:53:26 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 12:53:07 -0500 +Subject: media: verisilicon: Fix CPU stalls on G2 bus error +To: stable@vger.kernel.org +Cc: Nicolas Dufresne , Benjamin Gaignard , Hans Verkuil , Sasha Levin +Message-ID: <20260105175307.2700019-1-sashal@kernel.org> + +From: Nicolas Dufresne + +[ Upstream commit 19c286b755072a22a063052f530a6b1fac8a1f63 ] + +In some seek stress tests, we are getting IRQ from the G2 decoder where +the dec_bus_int and the dec_e bits are high, meaning the decoder is +still running despite the error. + +Fix this by reworking the IRQ handler to only finish the job once we +have reached completion and move the software reset to when our software +watchdog triggers. + +This way, we let the hardware continue on errors when it did not self +reset and in worse case scenario the hardware timeout will +automatically stop it. The actual error will be fixed in a follow up +patch. + +Fixes: 3385c514ecc5a ("media: hantro: Convert imx8m_vpu_g2_irq to helper") +Cc: stable@vger.kernel.org +Reviewed-by: Benjamin Gaignard +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/verisilicon/hantro_g2.c | 84 ++++++++++++---- + drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 2 + drivers/media/platform/verisilicon/hantro_g2_regs.h | 13 ++ + drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 2 + drivers/media/platform/verisilicon/hantro_hw.h | 1 + drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 2 + 6 files changed, 83 insertions(+), 21 deletions(-) + +--- a/drivers/media/platform/verisilicon/hantro_g2.c ++++ b/drivers/media/platform/verisilicon/hantro_g2.c +@@ -5,40 +5,90 @@ + * Copyright (C) 2021 Collabora Ltd, Andrzej Pietrasiewicz + */ + ++#include + #include "hantro_hw.h" + #include "hantro_g2_regs.h" + +-void hantro_g2_check_idle(struct hantro_dev *vpu) ++static bool hantro_g2_active(struct hantro_ctx *ctx) + { +- int i; ++ struct hantro_dev *vpu = ctx->dev; ++ u32 status; ++ ++ status = vdpu_read(vpu, G2_REG_INTERRUPT); ++ ++ return (status & G2_REG_INTERRUPT_DEC_E); ++} + +- for (i = 0; i < 3; i++) { +- u32 status; ++/** ++ * hantro_g2_reset: ++ * @ctx: the hantro context ++ * ++ * Emulates a reset using Hantro abort function. Failing this procedure would ++ * results in programming a running IP which leads to CPU hang. ++ * ++ * Using a hard reset procedure instead is prefferred. ++ */ ++void hantro_g2_reset(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ u32 status; + +- /* Make sure the VPU is idle */ +- status = vdpu_read(vpu, G2_REG_INTERRUPT); +- if (status & G2_REG_INTERRUPT_DEC_E) { +- dev_warn(vpu->dev, "device still running, aborting"); +- status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; +- vdpu_write(vpu, status, G2_REG_INTERRUPT); +- } ++ status = vdpu_read(vpu, G2_REG_INTERRUPT); ++ if (status & G2_REG_INTERRUPT_DEC_E) { ++ dev_warn_ratelimited(vpu->dev, "device still running, aborting"); ++ status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; ++ vdpu_write(vpu, status, G2_REG_INTERRUPT); ++ ++ do { ++ mdelay(1); ++ } while (hantro_g2_active(ctx)); + } + } + + irqreturn_t hantro_g2_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; +- enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); +- state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ? +- VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + +- vdpu_write(vpu, 0, G2_REG_INTERRUPT); +- vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG); ++ if (!(status & G2_REG_INTERRUPT_DEC_IRQ)) ++ return IRQ_NONE; ++ ++ hantro_reg_write(vpu, &g2_dec_irq, 0); ++ hantro_reg_write(vpu, &g2_dec_int_stat, 0); ++ hantro_reg_write(vpu, &g2_clk_gate_e, 1); ++ ++ if (status & G2_REG_INTERRUPT_DEC_RDY_INT) { ++ hantro_irq_done(vpu, VB2_BUF_STATE_DONE); ++ return IRQ_HANDLED; ++ } ++ ++ if (status & G2_REG_INTERRUPT_DEC_ABORT_INT) { ++ /* disabled on abort, though lets be safe and handle it */ ++ dev_warn_ratelimited(vpu->dev, "decode operation aborted."); ++ return IRQ_HANDLED; ++ } ++ ++ if (status & G2_REG_INTERRUPT_DEC_LAST_SLICE_INT) ++ dev_warn_ratelimited(vpu->dev, "not all macroblocks were decoded."); ++ ++ if (status & G2_REG_INTERRUPT_DEC_BUS_INT) ++ dev_warn_ratelimited(vpu->dev, "bus error detected."); ++ ++ if (status & G2_REG_INTERRUPT_DEC_ERROR_INT) ++ dev_warn_ratelimited(vpu->dev, "decode error detected."); + +- hantro_irq_done(vpu, state); ++ if (status & G2_REG_INTERRUPT_DEC_TIMEOUT) ++ dev_warn_ratelimited(vpu->dev, "frame decode timed out."); ++ ++ /** ++ * If the decoding haven't stopped, let it continue. The hardware timeout ++ * will trigger if it is trully stuck. ++ */ ++ if (status & G2_REG_INTERRUPT_DEC_E) ++ return IRQ_HANDLED; + ++ hantro_irq_done(vpu, VB2_BUF_STATE_ERROR); + return IRQ_HANDLED; + } +--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +@@ -592,8 +592,6 @@ int hantro_g2_hevc_dec_run(struct hantro + struct hantro_dev *vpu = ctx->dev; + int ret; + +- hantro_g2_check_idle(vpu); +- + /* Prepare HEVC decoder context. */ + ret = hantro_hevc_dec_prepare_run(ctx); + if (ret) +--- a/drivers/media/platform/verisilicon/hantro_g2_regs.h ++++ b/drivers/media/platform/verisilicon/hantro_g2_regs.h +@@ -22,7 +22,14 @@ + #define G2_REG_VERSION G2_SWREG(0) + + #define G2_REG_INTERRUPT G2_SWREG(1) ++#define G2_REG_INTERRUPT_DEC_LAST_SLICE_INT BIT(19) ++#define G2_REG_INTERRUPT_DEC_TIMEOUT BIT(18) ++#define G2_REG_INTERRUPT_DEC_ERROR_INT BIT(16) ++#define G2_REG_INTERRUPT_DEC_BUF_INT BIT(14) ++#define G2_REG_INTERRUPT_DEC_BUS_INT BIT(13) + #define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12) ++#define G2_REG_INTERRUPT_DEC_ABORT_INT BIT(11) ++#define G2_REG_INTERRUPT_DEC_IRQ BIT(8) + #define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5) + #define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) + #define G2_REG_INTERRUPT_DEC_E BIT(0) +@@ -35,6 +42,9 @@ + #define BUS_WIDTH_128 2 + #define BUS_WIDTH_256 3 + ++#define g2_dec_int_stat G2_DEC_REG(1, 11, 0xf) ++#define g2_dec_irq G2_DEC_REG(1, 8, 0x1) ++ + #define g2_strm_swap G2_DEC_REG(2, 28, 0xf) + #define g2_strm_swap_old G2_DEC_REG(2, 27, 0x1f) + #define g2_pic_swap G2_DEC_REG(2, 22, 0x1f) +@@ -225,6 +235,9 @@ + #define vp9_filt_level_seg5 G2_DEC_REG(19, 8, 0x3f) + #define vp9_quant_seg5 G2_DEC_REG(19, 0, 0xff) + ++#define g2_timemout_override_e G2_DEC_REG(45, 31, 0x1) ++#define g2_timemout_cycles G2_DEC_REG(45, 0, 0x7fffffff) ++ + #define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) + #define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) + #define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) +--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c ++++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +@@ -909,8 +909,6 @@ int hantro_g2_vp9_dec_run(struct hantro_ + struct vb2_v4l2_buffer *dst; + int ret; + +- hantro_g2_check_idle(ctx->dev); +- + ret = start_prepare_run(ctx, &decode_params); + if (ret) { + hantro_end_prepare_run(ctx); +--- a/drivers/media/platform/verisilicon/hantro_hw.h ++++ b/drivers/media/platform/verisilicon/hantro_hw.h +@@ -436,6 +436,7 @@ void hantro_g2_vp9_dec_done(struct hantr + int hantro_vp9_dec_init(struct hantro_ctx *ctx); + void hantro_vp9_dec_exit(struct hantro_ctx *ctx); + void hantro_g2_check_idle(struct hantro_dev *vpu); ++void hantro_g2_reset(struct hantro_ctx *ctx); + irqreturn_t hantro_g2_irq(int irq, void *dev_id); + + #endif /* HANTRO_HW_H_ */ +--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c ++++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +@@ -310,11 +310,13 @@ static const struct hantro_codec_ops imx + static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { + [HANTRO_MODE_HEVC_DEC] = { + .run = hantro_g2_hevc_dec_run, ++ .reset = hantro_g2_reset, + .init = hantro_hevc_dec_init, + .exit = hantro_hevc_dec_exit, + }, + [HANTRO_MODE_VP9_DEC] = { + .run = hantro_g2_vp9_dec_run, ++ .reset = hantro_g2_reset, + .done = hantro_g2_vp9_dec_done, + .init = hantro_vp9_dec_init, + .exit = hantro_vp9_dec_exit, diff --git a/queue-6.1/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch b/queue-6.1/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch new file mode 100644 index 0000000000..e19aff19e4 --- /dev/null +++ b/queue-6.1/mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch @@ -0,0 +1,225 @@ +From stable+bounces-204887-greg=kroah.com@vger.kernel.org Mon Jan 5 19:21:09 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 13:18:48 -0500 +Subject: mm/balloon_compaction: convert balloon_page_delete() to balloon_page_finalize() +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Harry Yoo" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Zi Yan" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105181849.2717306-2-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 15504b1163007bbfbd9a63460d5c14737c16e96d ] + +Let's move the removal of the page from the balloon list into the single +caller, to remove the dependency on the PG_isolated flag and clarify +locking requirements. + +Note that for now, balloon_page_delete() was used on two paths: + +(1) Removing a page from the balloon for deflation through + balloon_page_list_dequeue() +(2) Removing an isolated page from the balloon for migration in the + per-driver migration handlers. Isolated pages were already removed from + the balloon list during isolation. + +So instead of relying on the flag, we can just distinguish both cases +directly and handle it accordingly in the caller. + +We'll shuffle the operations a bit such that they logically make more +sense (e.g., remove from the list before clearing flags). + +In balloon migration functions we can now move the balloon_page_finalize() +out of the balloon lock and perform the finalization just before dropping +the balloon reference. + +Document that the page lock is currently required when modifying the +movability aspects of a page; hopefully we can soon decouple this from the +page lock. + +Link: https://lkml.kernel.org/r/20250704102524.326966-3-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: Harry Yoo +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Zi Yan +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 2 - + drivers/misc/vmw_balloon.c | 3 -- + drivers/virtio/virtio_balloon.c | 4 --- + include/linux/balloon_compaction.h | 43 +++++++++++++---------------------- + mm/balloon_compaction.c | 3 +- + 5 files changed, 21 insertions(+), 34 deletions(-) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,7 +532,6 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); +- balloon_page_delete(page); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + +@@ -542,6 +541,7 @@ static int cmm_migratepage(struct balloo + */ + plpar_page_set_active(page); + ++ balloon_page_finalize(page); + /* balloon page list reference */ + put_page(page); + +--- a/drivers/misc/vmw_balloon.c ++++ b/drivers/misc/vmw_balloon.c +@@ -1789,8 +1789,7 @@ static int vmballoon_migratepage(struct + * @pages_lock . We keep holding @comm_lock since we will need it in a + * second. + */ +- balloon_page_delete(page); +- ++ balloon_page_finalize(page); + put_page(page); + + /* Inflate */ +--- a/drivers/virtio/virtio_balloon.c ++++ b/drivers/virtio/virtio_balloon.c +@@ -789,15 +789,13 @@ static int virtballoon_migratepage(struc + tell_host(vb, vb->inflate_vq); + + /* balloon's page migration 2nd step -- deflate "page" */ +- spin_lock_irqsave(&vb_dev_info->pages_lock, flags); +- balloon_page_delete(page); +- spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); + vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; + set_page_pfns(vb, vb->pfns, page); + tell_host(vb, vb->deflate_vq); + + mutex_unlock(&vb->balloon_lock); + ++ balloon_page_finalize(page); + put_page(page); /* balloon reference */ + + return MIGRATEPAGE_SUCCESS; +--- a/include/linux/balloon_compaction.h ++++ b/include/linux/balloon_compaction.h +@@ -98,27 +98,6 @@ static inline void balloon_page_insert(s + } + + /* +- * balloon_page_delete - delete a page from balloon's page list and clear +- * the page->private assignement accordingly. +- * @page : page to be released from balloon's page list +- * +- * Caller must ensure the page is locked and the spin_lock protecting balloon +- * pages list is held before deleting a page from the balloon device. +- */ +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- __ClearPageMovable(page); +- set_page_private(page, 0); +- /* +- * No touch page.lru field once @page has been isolated +- * because VM is using the field. +- */ +- if (!PageIsolated(page)) +- list_del(&page->lru); +-} +- +-/* + * balloon_page_device - get the b_dev_info descriptor for the balloon device + * that enqueues the given page. + */ +@@ -141,12 +120,6 @@ static inline void balloon_page_insert(s + list_add(&page->lru, &balloon->pages); + } + +-static inline void balloon_page_delete(struct page *page) +-{ +- __ClearPageOffline(page); +- list_del(&page->lru); +-} +- + static inline gfp_t balloon_mapping_gfp_mask(void) + { + return GFP_HIGHUSER; +@@ -155,6 +128,22 @@ static inline gfp_t balloon_mapping_gfp_ + #endif /* CONFIG_BALLOON_COMPACTION */ + + /* ++ * balloon_page_finalize - prepare a balloon page that was removed from the ++ * balloon list for release to the page allocator ++ * @page: page to be released to the page allocator ++ * ++ * Caller must ensure that the page is locked. ++ */ ++static inline void balloon_page_finalize(struct page *page) ++{ ++ if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) { ++ __ClearPageMovable(page); ++ set_page_private(page, 0); ++ } ++ __ClearPageOffline(page); ++} ++ ++/* + * balloon_page_push - insert a page into a page list. + * @head : pointer to list + * @page : page to be added +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,7 +93,8 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- balloon_page_delete(page); ++ list_del(&page->lru); ++ balloon_page_finalize(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); + unlock_page(page); diff --git a/queue-6.1/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch b/queue-6.1/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch new file mode 100644 index 0000000000..d9dafd3835 --- /dev/null +++ b/queue-6.1/mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch @@ -0,0 +1,109 @@ +From stable+bounces-204886-greg=kroah.com@vger.kernel.org Mon Jan 5 19:21:01 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 13:18:47 -0500 +Subject: mm/balloon_compaction: we cannot have isolated pages in the balloon list +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Zi Yan" , "Lorenzo Stoakes" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Harry Yoo" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260105181849.2717306-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit fb05f992b6bbb4702307d96f00703ee637b24dbf ] + +Patch series "mm/migration: rework movable_ops page migration (part 1)", +v2. + +In the future, as we decouple "struct page" from "struct folio", pages +that support "non-lru page migration" -- movable_ops page migration such +as memory balloons and zsmalloc -- will no longer be folios. They will +not have ->mapping, ->lru, and likely no refcount and no page lock. But +they will have a type and flags 🙂 + +This is the first part (other parts not written yet) of decoupling +movable_ops page migration from folio migration. + +In this series, we get rid of the ->mapping usage, and start cleaning up +the code + separating it from folio migration. + +Migration core will have to be further reworked to not treat movable_ops +pages like folios. This is the first step into that direction. + +This patch (of 29): + +The core will set PG_isolated only after mops->isolate_page() was called. +In case of the balloon, that is where we will remove it from the balloon +list. So we cannot have isolated pages in the balloon list. + +Let's drop this unnecessary check. + +Link: https://lkml.kernel.org/r/20250704102524.326966-2-david@redhat.com +Signed-off-by: David Hildenbrand +Acked-by: Zi Yan +Reviewed-by: Lorenzo Stoakes +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Cc: Harry Yoo +Signed-off-by: Andrew Morton +Stable-dep-of: 0da2ba35c0d5 ("powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/balloon_compaction.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/mm/balloon_compaction.c ++++ b/mm/balloon_compaction.c +@@ -93,12 +93,6 @@ size_t balloon_page_list_dequeue(struct + if (!trylock_page(page)) + continue; + +- if (IS_ENABLED(CONFIG_BALLOON_COMPACTION) && +- PageIsolated(page)) { +- /* raced with isolation */ +- unlock_page(page); +- continue; +- } + balloon_page_delete(page); + __count_vm_event(BALLOON_DEFLATE); + list_add(&page->lru, pages); diff --git a/queue-6.1/mm-consider-non-anon-swap-cache-folios-in-folio_expected_ref_count.patch b/queue-6.1/mm-consider-non-anon-swap-cache-folios-in-folio_expected_ref_count.patch new file mode 100644 index 0000000000..478266a2bc --- /dev/null +++ b/queue-6.1/mm-consider-non-anon-swap-cache-folios-in-folio_expected_ref_count.patch @@ -0,0 +1,120 @@ +From stable+bounces-206070-greg=kroah.com@vger.kernel.org Wed Jan 7 01:36:38 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 19:36:27 -0500 +Subject: mm: consider non-anon swap cache folios in folio_expected_ref_count() +To: stable@vger.kernel.org +Cc: Bijan Tabatabai , "David Hildenbrand (Red Hat)" , Zi Yan , Baolin Wang , Liam Howlett , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Shivank Garg , Suren Baghdasaryan , Vlastimil Babka , Kairui Song , Andrew Morton , Sasha Levin +Message-ID: <20260107003627.3469728-2-sashal@kernel.org> + +From: Bijan Tabatabai + +[ Upstream commit f183663901f21fe0fba8bd31ae894bc529709ee0 ] + +Currently, folio_expected_ref_count() only adds references for the swap +cache if the folio is anonymous. However, according to the comment above +the definition of PG_swapcache in enum pageflags, shmem folios can also +have PG_swapcache set. This patch makes sure references for the swap +cache are added if folio_test_swapcache(folio) is true. + +This issue was found when trying to hot-unplug memory in a QEMU/KVM +virtual machine. When initiating hot-unplug when most of the guest memory +is allocated, hot-unplug hangs partway through removal due to migration +failures. The following message would be printed several times, and would +be printed again about every five seconds: + +[ 49.641309] migrating pfn b12f25 failed ret:7 +[ 49.641310] page: refcount:2 mapcount:0 mapping:0000000033bd8fe2 index:0x7f404d925 pfn:0xb12f25 +[ 49.641311] aops:swap_aops +[ 49.641313] flags: 0x300000000030508(uptodate|active|owner_priv_1|reclaim|swapbacked|node=0|zone=3) +[ 49.641314] raw: 0300000000030508 ffffed312c4bc908 ffffed312c4bc9c8 0000000000000000 +[ 49.641315] raw: 00000007f404d925 00000000000c823b 00000002ffffffff 0000000000000000 +[ 49.641315] page dumped because: migration failure + +When debugging this, I found that these migration failures were due to +__migrate_folio() returning -EAGAIN for a small set of folios because the +expected reference count it calculates via folio_expected_ref_count() is +one less than the actual reference count of the folios. Furthermore, all +of the affected folios were not anonymous, but had the PG_swapcache flag +set, inspiring this patch. After applying this patch, the memory +hot-unplug behaves as expected. + +I tested this on a machine running Ubuntu 24.04 with kernel version +6.8.0-90-generic and 64GB of memory. The guest VM is managed by libvirt +and runs Ubuntu 24.04 with kernel version 6.18 (though the head of the +mm-unstable branch as a Dec 16, 2025 was also tested and behaves the same) +and 48GB of memory. The libvirt XML definition for the VM can be found at +[1]. CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is set in the guest +kernel so the hot-pluggable memory is automatically onlined. + +Below are the steps to reproduce this behavior: + +1) Define and start and virtual machine + host$ virsh -c qemu:///system define ./test_vm.xml # test_vm.xml from [1] + host$ virsh -c qemu:///system start test_vm + +2) Setup swap in the guest + guest$ sudo fallocate -l 32G /swapfile + guest$ sudo chmod 0600 /swapfile + guest$ sudo mkswap /swapfile + guest$ sudo swapon /swapfile + +3) Use alloc_data [2] to allocate most of the remaining guest memory + guest$ ./alloc_data 45 + +4) In a separate guest terminal, monitor the amount of used memory + guest$ watch -n1 free -h + +5) When alloc_data has finished allocating, initiate the memory +hot-unplug using the provided xml file [3] + host$ virsh -c qemu:///system detach-device test_vm ./remove.xml --live + +After initiating the memory hot-unplug, you should see the amount of +available memory in the guest decrease, and the amount of used swap data +increase. If everything works as expected, when all of the memory is +unplugged, there should be around 8.5-9GB of data in swap. If the +unplugging is unsuccessful, the amount of used swap data will settle below +that. If that happens, you should be able to see log messages in dmesg +similar to the one posted above. + +Link: https://lkml.kernel.org/r/20251216200727.2360228-1-bijan311@gmail.com +Link: https://github.com/BijanT/linux_patch_files/blob/main/test_vm.xml [1] +Link: https://github.com/BijanT/linux_patch_files/blob/main/alloc_data.c [2] +Link: https://github.com/BijanT/linux_patch_files/blob/main/remove.xml [3] +Fixes: 86ebd50224c0 ("mm: add folio_expected_ref_count() for reference count calculation") +Signed-off-by: Bijan Tabatabai +Acked-by: David Hildenbrand (Red Hat) +Acked-by: Zi Yan +Reviewed-by: Baolin Wang +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shivank Garg +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Kairui Song +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mm.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1823,10 +1823,10 @@ static inline int folio_expected_ref_cou + if (WARN_ON_ONCE(page_has_type(&folio->page) && !folio_test_hugetlb(folio))) + return 0; + +- if (folio_test_anon(folio)) { +- /* One reference per page from the swapcache. */ +- ref_count += folio_test_swapcache(folio) << order; +- } else { ++ /* One reference per page from the swapcache. */ ++ ref_count += folio_test_swapcache(folio) << order; ++ ++ if (!folio_test_anon(folio)) { + /* One reference per page from the pagecache. */ + ref_count += !!folio->mapping << order; + /* One reference from PG_private. */ diff --git a/queue-6.1/mm-simplify-folio_expected_ref_count.patch b/queue-6.1/mm-simplify-folio_expected_ref_count.patch new file mode 100644 index 0000000000..d42df6e711 --- /dev/null +++ b/queue-6.1/mm-simplify-folio_expected_ref_count.patch @@ -0,0 +1,100 @@ +From stable+bounces-206069-greg=kroah.com@vger.kernel.org Wed Jan 7 01:36:36 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 19:36:26 -0500 +Subject: mm: simplify folio_expected_ref_count() +To: stable@vger.kernel.org +Cc: "David Hildenbrand" , "Zi Yan" , "Lorenzo Stoakes" , "Harry Yoo" , "Alistair Popple" , "Al Viro" , "Arnd Bergmann" , "Brendan Jackman" , "Byungchul Park" , "Chengming Zhou" , "Christian Brauner" , "Christophe Leroy" , "Eugenio Pé rez" , "Greg Kroah-Hartman" , "Gregory Price" , "Huang, Ying" , "Jan Kara" , "Jason Gunthorpe" , "Jason Wang" , "Jerrin Shaji George" , "Johannes Weiner" , "John Hubbard" , "Jonathan Corbet" , "Joshua Hahn" , "Liam Howlett" , "Madhavan Srinivasan" , "Mathew Brost" , "Matthew Wilcox (Oracle)" , "Miaohe Lin" , "Michael Ellerman" , "Michael S. Tsirkin" , "Michal Hocko" , "Mike Rapoport" , "Minchan Kim" , "Naoya Horiguchi" , "Nicholas Piggin" , "Oscar Salvador" , "Peter Xu" , "Qi Zheng" , "Rakie Kim" , "Rik van Riel" , "Sergey Senozhatsky" , "Shakeel Butt" , "Suren Baghdasaryan" , "Vlastimil Babka" , "Xuan Zhuo" , "xu xin" , "Andrew Morton" , "Sasha Levin" +Message-ID: <20260107003627.3469728-1-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 78cb1a13c42a6d843e21389f74d1edb90ed07288 ] + +Now that PAGE_MAPPING_MOVABLE is gone, we can simplify and rely on the +folio_test_anon() test only. + +... but staring at the users, this function should never even have been +called on movable_ops pages. E.g., +* __buffer_migrate_folio() does not make sense for them +* folio_migrate_mapping() does not make sense for them +* migrate_huge_page_move_mapping() does not make sense for them +* __migrate_folio() does not make sense for them +* ... and khugepaged should never stumble over them + +Let's simply refuse typed pages (which includes slab) except hugetlb, and +WARN. + +Link: https://lkml.kernel.org/r/20250704102524.326966-26-david@redhat.com +Signed-off-by: David Hildenbrand +Reviewed-by: Zi Yan +Reviewed-by: Lorenzo Stoakes +Reviewed-by: Harry Yoo +Cc: Alistair Popple +Cc: Al Viro +Cc: Arnd Bergmann +Cc: Brendan Jackman +Cc: Byungchul Park +Cc: Chengming Zhou +Cc: Christian Brauner +Cc: Christophe Leroy +Cc: Eugenio Pé rez +Cc: Greg Kroah-Hartman +Cc: Gregory Price +Cc: "Huang, Ying" +Cc: Jan Kara +Cc: Jason Gunthorpe +Cc: Jason Wang +Cc: Jerrin Shaji George +Cc: Johannes Weiner +Cc: John Hubbard +Cc: Jonathan Corbet +Cc: Joshua Hahn +Cc: Liam Howlett +Cc: Madhavan Srinivasan +Cc: Mathew Brost +Cc: Matthew Wilcox (Oracle) +Cc: Miaohe Lin +Cc: Michael Ellerman +Cc: "Michael S. Tsirkin" +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Minchan Kim +Cc: Naoya Horiguchi +Cc: Nicholas Piggin +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Qi Zheng +Cc: Rakie Kim +Cc: Rik van Riel +Cc: Sergey Senozhatsky +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Xuan Zhuo +Cc: xu xin +Signed-off-by: Andrew Morton +Stable-dep-of: f183663901f2 ("mm: consider non-anon swap cache folios in folio_expected_ref_count()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mm.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1820,13 +1820,13 @@ static inline int folio_expected_ref_cou + const int order = folio_order(folio); + int ref_count = 0; + +- if (WARN_ON_ONCE(folio_test_slab(folio))) ++ if (WARN_ON_ONCE(page_has_type(&folio->page) && !folio_test_hugetlb(folio))) + return 0; + + if (folio_test_anon(folio)) { + /* One reference per page from the swapcache. */ + ref_count += folio_test_swapcache(folio) << order; +- } else if (!((unsigned long)folio->mapping & PAGE_MAPPING_FLAGS)) { ++ } else { + /* One reference per page from the pagecache. */ + ref_count += !!folio->mapping << order; + /* One reference from PG_private. */ diff --git a/queue-6.1/mptcp-avoid-deadlock-on-fallback-while-reinjecting.patch b/queue-6.1/mptcp-avoid-deadlock-on-fallback-while-reinjecting.patch new file mode 100644 index 0000000000..9c76d3087d --- /dev/null +++ b/queue-6.1/mptcp-avoid-deadlock-on-fallback-while-reinjecting.patch @@ -0,0 +1,117 @@ +From stable+bounces-204204-greg=kroah.com@vger.kernel.org Tue Dec 30 14:20:10 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 08:20:05 -0500 +Subject: mptcp: avoid deadlock on fallback while reinjecting +To: stable@vger.kernel.org +Cc: Paolo Abeni , Jakub Kicinski , "Matthieu Baerts (NGI0)" , Sasha Levin +Message-ID: <20251230132005.2177978-1-sashal@kernel.org> + +From: Paolo Abeni + +[ Upstream commit ffb8c27b0539dd90262d1021488e7817fae57c42 ] + +Jakub reported an MPTCP deadlock at fallback time: + + WARNING: possible recursive locking detected + 6.18.0-rc7-virtme #1 Not tainted + -------------------------------------------- + mptcp_connect/20858 is trying to acquire lock: + ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_try_fallback+0xd8/0x280 + + but task is already holding lock: + ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_retrans+0x352/0xaa0 + + other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(&msk->fallback_lock); + lock(&msk->fallback_lock); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + + 3 locks held by mptcp_connect/20858: + #0: ff1100001da18290 (sk_lock-AF_INET){+.+.}-{0:0}, at: mptcp_sendmsg+0x114/0x1bc0 + #1: ff1100001db40fd0 (k-sk_lock-AF_INET#2){+.+.}-{0:0}, at: __mptcp_retrans+0x2cb/0xaa0 + #2: ff1100001da18b60 (&msk->fallback_lock){+.-.}-{3:3}, at: __mptcp_retrans+0x352/0xaa0 + + stack backtrace: + CPU: 0 UID: 0 PID: 20858 Comm: mptcp_connect Not tainted 6.18.0-rc7-virtme #1 PREEMPT(full) + Hardware name: Bochs, BIOS Bochs 01/01/2011 + Call Trace: + + dump_stack_lvl+0x6f/0xa0 + print_deadlock_bug.cold+0xc0/0xcd + validate_chain+0x2ff/0x5f0 + __lock_acquire+0x34c/0x740 + lock_acquire.part.0+0xbc/0x260 + _raw_spin_lock_bh+0x38/0x50 + __mptcp_try_fallback+0xd8/0x280 + mptcp_sendmsg_frag+0x16c2/0x3050 + __mptcp_retrans+0x421/0xaa0 + mptcp_release_cb+0x5aa/0xa70 + release_sock+0xab/0x1d0 + mptcp_sendmsg+0xd5b/0x1bc0 + sock_write_iter+0x281/0x4d0 + new_sync_write+0x3c5/0x6f0 + vfs_write+0x65e/0xbb0 + ksys_write+0x17e/0x200 + do_syscall_64+0xbb/0xfd0 + entry_SYSCALL_64_after_hwframe+0x4b/0x53 + RIP: 0033:0x7fa5627cbc5e + Code: 4d 89 d8 e8 14 bd 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 c3 83 e2 39 83 fa 08 75 e7 e8 13 ff ff ff 0f 1f 00 f3 0f 1e fa + RSP: 002b:00007fff1fe14700 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 + RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 00007fa5627cbc5e + RDX: 0000000000001f9c RSI: 00007fff1fe16984 RDI: 0000000000000005 + RBP: 00007fff1fe14710 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000000202 R12: 00007fff1fe16920 + R13: 0000000000002000 R14: 0000000000001f9c R15: 0000000000001f9c + +The packet scheduler could attempt a reinjection after receiving an +MP_FAIL and before the infinite map has been transmitted, causing a +deadlock since MPTCP needs to do the reinjection atomically from WRT +fallback. + +Address the issue explicitly avoiding the reinjection in the critical +scenario. Note that this is the only fallback critical section that +could potentially send packets and hit the double-lock. + +Reported-by: Jakub Kicinski +Closes: https://netdev-ctrl.bots.linux.dev/logs/vmksft/mptcp-dbg/results/412720/1-mptcp-join-sh/stderr +Fixes: f8a1d9b18c5e ("mptcp: make fallback action and fallback decision atomic") +Cc: stable@vger.kernel.org +Signed-off-by: Paolo Abeni +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-4-9e4781a6c1b8@kernel.org +Signed-off-by: Jakub Kicinski +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/protocol.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2715,9 +2715,15 @@ static void __mptcp_retrans(struct sock + info.sent = 0; + info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len : dfrag->already_sent; + +- /* make the whole retrans decision, xmit, disallow fallback atomic */ ++ /* ++ * make the whole retrans decision, xmit, disallow ++ * fallback atomic, note that we can't retrans even ++ * when an infinite fallback is in progress, i.e. new ++ * subflows are disallowed. ++ */ + spin_lock_bh(&msk->fallback_lock); +- if (__mptcp_check_fallback(msk)) { ++ if (__mptcp_check_fallback(msk) || ++ !msk->allow_subflows) { + spin_unlock_bh(&msk->fallback_lock); + release_sock(ssk); + return; diff --git a/queue-6.1/mptcp-fallback-earlier-on-simult-connection.patch b/queue-6.1/mptcp-fallback-earlier-on-simult-connection.patch new file mode 100644 index 0000000000..99f0aecda6 --- /dev/null +++ b/queue-6.1/mptcp-fallback-earlier-on-simult-connection.patch @@ -0,0 +1,149 @@ +From stable+bounces-205929-greg=kroah.com@vger.kernel.org Tue Jan 6 19:51:20 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:58:52 -0500 +Subject: mptcp: fallback earlier on simult connection +To: stable@vger.kernel.org +Cc: Paolo Abeni , syzbot+0ff6b771b4f7a5bce83b@syzkaller.appspotmail.com, "Matthieu Baerts (NGI0)" , Sasha Levin +Message-ID: <20260106175852.3105095-1-sashal@kernel.org> + +From: Paolo Abeni + +[ Upstream commit 71154bbe49423128c1c8577b6576de1ed6836830 ] + +Syzkaller reports a simult-connect race leading to inconsistent fallback +status: + + WARNING: CPU: 3 PID: 33 at net/mptcp/subflow.c:1515 subflow_data_ready+0x40b/0x7c0 net/mptcp/subflow.c:1515 + Modules linked in: + CPU: 3 UID: 0 PID: 33 Comm: ksoftirqd/3 Not tainted syzkaller #0 PREEMPT(full) + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 + RIP: 0010:subflow_data_ready+0x40b/0x7c0 net/mptcp/subflow.c:1515 + Code: 89 ee e8 78 61 3c f6 40 84 ed 75 21 e8 8e 66 3c f6 44 89 fe bf 07 00 00 00 e8 c1 61 3c f6 41 83 ff 07 74 09 e8 76 66 3c f6 90 <0f> 0b 90 e8 6d 66 3c f6 48 89 df e8 e5 ad ff ff 31 ff 89 c5 89 c6 + RSP: 0018:ffffc900006cf338 EFLAGS: 00010246 + RAX: 0000000000000000 RBX: ffff888031acd100 RCX: ffffffff8b7f2abf + RDX: ffff88801e6ea440 RSI: ffffffff8b7f2aca RDI: 0000000000000005 + RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000007 + R10: 0000000000000004 R11: 0000000000002c10 R12: ffff88802ba69900 + R13: 1ffff920000d9e67 R14: ffff888046f81800 R15: 0000000000000004 + FS: 0000000000000000(0000) GS:ffff8880d69bc000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 0000560fc0ca1670 CR3: 0000000032c3a000 CR4: 0000000000352ef0 + Call Trace: + + tcp_data_queue+0x13b0/0x4f90 net/ipv4/tcp_input.c:5197 + tcp_rcv_state_process+0xfdf/0x4ec0 net/ipv4/tcp_input.c:6922 + tcp_v6_do_rcv+0x492/0x1740 net/ipv6/tcp_ipv6.c:1672 + tcp_v6_rcv+0x2976/0x41e0 net/ipv6/tcp_ipv6.c:1918 + ip6_protocol_deliver_rcu+0x188/0x1520 net/ipv6/ip6_input.c:438 + ip6_input_finish+0x1e4/0x4b0 net/ipv6/ip6_input.c:489 + NF_HOOK include/linux/netfilter.h:318 [inline] + NF_HOOK include/linux/netfilter.h:312 [inline] + ip6_input+0x105/0x2f0 net/ipv6/ip6_input.c:500 + dst_input include/net/dst.h:471 [inline] + ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline] + NF_HOOK include/linux/netfilter.h:318 [inline] + NF_HOOK include/linux/netfilter.h:312 [inline] + ipv6_rcv+0x264/0x650 net/ipv6/ip6_input.c:311 + __netif_receive_skb_one_core+0x12d/0x1e0 net/core/dev.c:5979 + __netif_receive_skb+0x1d/0x160 net/core/dev.c:6092 + process_backlog+0x442/0x15e0 net/core/dev.c:6444 + __napi_poll.constprop.0+0xba/0x550 net/core/dev.c:7494 + napi_poll net/core/dev.c:7557 [inline] + net_rx_action+0xa9f/0xfe0 net/core/dev.c:7684 + handle_softirqs+0x216/0x8e0 kernel/softirq.c:579 + run_ksoftirqd kernel/softirq.c:968 [inline] + run_ksoftirqd+0x3a/0x60 kernel/softirq.c:960 + smpboot_thread_fn+0x3f7/0xae0 kernel/smpboot.c:160 + kthread+0x3c2/0x780 kernel/kthread.c:463 + ret_from_fork+0x5d7/0x6f0 arch/x86/kernel/process.c:148 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + +The TCP subflow can process the simult-connect syn-ack packet after +transitioning to TCP_FIN1 state, bypassing the MPTCP fallback check, +as the sk_state_change() callback is not invoked for * -> FIN_WAIT1 +transitions. + +That will move the msk socket to an inconsistent status and the next +incoming data will hit the reported splat. + +Close the race moving the simult-fallback check at the earliest possible +stage - that is at syn-ack generation time. + +About the fixes tags: [2] was supposed to also fix this issue introduced +by [3]. [1] is required as a dependence: it was not explicitly marked as +a fix, but it is one and it has already been backported before [3]. In +other words, this commit should be backported up to [3], including [2] +and [1] if that's not already there. + +Fixes: 23e89e8ee7be ("tcp: Don't drop SYN+ACK for simultaneous connect().") [1] +Fixes: 4fd19a307016 ("mptcp: fix inconsistent state on fastopen race") [2] +Fixes: 1e777f39b4d7 ("mptcp: add MSG_FASTOPEN sendmsg flag support") [3] +Cc: stable@vger.kernel.org +Reported-by: syzbot+0ff6b771b4f7a5bce83b@syzkaller.appspotmail.com +Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/586 +Signed-off-by: Paolo Abeni +Reviewed-by: Matthieu Baerts (NGI0) +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20251212-net-mptcp-subflow_data_ready-warn-v1-1-d1f9fd1c36c8@kernel.org +Signed-off-by: Paolo Abeni +[ adapted mptcp_try_fallback() call from two arguments to one argument ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/options.c | 10 ++++++++++ + net/mptcp/protocol.h | 5 ++--- + net/mptcp/subflow.c | 9 --------- + 3 files changed, 12 insertions(+), 12 deletions(-) + +--- a/net/mptcp/options.c ++++ b/net/mptcp/options.c +@@ -403,6 +403,16 @@ bool mptcp_syn_options(struct sock *sk, + */ + subflow->snd_isn = TCP_SKB_CB(skb)->end_seq; + if (subflow->request_mptcp) { ++ if (unlikely(subflow_simultaneous_connect(sk))) { ++ WARN_ON_ONCE(!mptcp_try_fallback(sk)); ++ ++ /* Ensure mptcp_finish_connect() will not process the ++ * MPC handshake. ++ */ ++ subflow->request_mptcp = 0; ++ return false; ++ } ++ + opts->suboptions = OPTION_MPTCP_MPC_SYN; + opts->csum_reqd = mptcp_is_checksum_enabled(sock_net(sk)); + opts->allow_join_id0 = mptcp_allow_join_id0(sock_net(sk)); +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -1053,9 +1053,8 @@ static inline bool subflow_simultaneous_ + { + struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); + +- return sk->sk_state == TCP_ESTABLISHED && +- is_active_ssk(subflow) && +- !subflow->conn_finished; ++ /* Note that the sk state implies !subflow->conn_finished. */ ++ return sk->sk_state == TCP_SYN_RECV && is_active_ssk(subflow); + } + + #ifdef CONFIG_SYN_COOKIES +--- a/net/mptcp/subflow.c ++++ b/net/mptcp/subflow.c +@@ -1700,15 +1700,6 @@ static void subflow_state_change(struct + __subflow_state_change(sk); + + msk = mptcp_sk(parent); +- if (subflow_simultaneous_connect(sk)) { +- mptcp_propagate_sndbuf(parent, sk); +- WARN_ON_ONCE(!mptcp_try_fallback(sk)); +- mptcp_rcv_space_init(msk, sk); +- pr_fallback(msk); +- subflow->conn_finished = 1; +- mptcp_set_connected(parent); +- } +- + /* as recvmsg() does not acquire the subflow socket for ssk selection + * a fin packet carrying a DSS can be unnoticed if we don't trigger + * the data available machinery here. diff --git a/queue-6.1/mptcp-initialise-rcv_mss-before-calling-tcp_send_active_reset-in-mptcp_do_fastclose.patch b/queue-6.1/mptcp-initialise-rcv_mss-before-calling-tcp_send_active_reset-in-mptcp_do_fastclose.patch new file mode 100644 index 0000000000..7e13250dab --- /dev/null +++ b/queue-6.1/mptcp-initialise-rcv_mss-before-calling-tcp_send_active_reset-in-mptcp_do_fastclose.patch @@ -0,0 +1,95 @@ +From stable+bounces-200348-greg=kroah.com@vger.kernel.org Mon Dec 8 14:01:04 2025 +From: Sasha Levin +Date: Mon, 8 Dec 2025 08:00:54 -0500 +Subject: mptcp: Initialise rcv_mss before calling tcp_send_active_reset() in mptcp_do_fastclose(). +To: stable@vger.kernel.org +Cc: Kuniyuki Iwashima , syzbot+3a92d359bc2ec6255a33@syzkaller.appspotmail.com, "Matthieu Baerts (NGI0)" , Paolo Abeni , Sasha Levin +Message-ID: <20251208130054.296171-1-sashal@kernel.org> + +From: Kuniyuki Iwashima + +[ Upstream commit f07f4ea53e22429c84b20832fa098b5ecc0d4e35 ] + +syzbot reported divide-by-zero in __tcp_select_window() by +MPTCP socket. [0] + +We had a similar issue for the bare TCP and fixed in commit +499350a5a6e7 ("tcp: initialize rcv_mss to TCP_MIN_MSS instead +of 0"). + +Let's apply the same fix to mptcp_do_fastclose(). + +[0]: +Oops: divide error: 0000 [#1] SMP KASAN PTI +CPU: 0 UID: 0 PID: 6068 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 +RIP: 0010:__tcp_select_window+0x824/0x1320 net/ipv4/tcp_output.c:3336 +Code: ff ff ff 44 89 f1 d3 e0 89 c1 f7 d1 41 01 cc 41 21 c4 e9 a9 00 00 00 e8 ca 49 01 f8 e9 9c 00 00 00 e8 c0 49 01 f8 44 89 e0 99 7c 24 1c 41 29 d4 48 bb 00 00 00 00 00 fc ff df e9 80 00 00 00 +RSP: 0018:ffffc90003017640 EFLAGS: 00010293 +RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff88807b469e40 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: ffffc90003017730 R08: ffff888033268143 R09: 1ffff1100664d028 +R10: dffffc0000000000 R11: ffffed100664d029 R12: 0000000000000000 +R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 +FS: 000055557faa0500(0000) GS:ffff888126135000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f64a1912ff8 CR3: 0000000072122000 CR4: 00000000003526f0 +Call Trace: + + tcp_select_window net/ipv4/tcp_output.c:281 [inline] + __tcp_transmit_skb+0xbc7/0x3aa0 net/ipv4/tcp_output.c:1568 + tcp_transmit_skb net/ipv4/tcp_output.c:1649 [inline] + tcp_send_active_reset+0x2d1/0x5b0 net/ipv4/tcp_output.c:3836 + mptcp_do_fastclose+0x27e/0x380 net/mptcp/protocol.c:2793 + mptcp_disconnect+0x238/0x710 net/mptcp/protocol.c:3253 + mptcp_sendmsg_fastopen+0x2f8/0x580 net/mptcp/protocol.c:1776 + mptcp_sendmsg+0x1774/0x1980 net/mptcp/protocol.c:1855 + sock_sendmsg_nosec net/socket.c:727 [inline] + __sock_sendmsg+0xe5/0x270 net/socket.c:742 + __sys_sendto+0x3bd/0x520 net/socket.c:2244 + __do_sys_sendto net/socket.c:2251 [inline] + __se_sys_sendto net/socket.c:2247 [inline] + __x64_sys_sendto+0xde/0x100 net/socket.c:2247 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xfa/0xfa0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f66e998f749 +Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007ffff9acedb8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c +RAX: ffffffffffffffda RBX: 00007f66e9be5fa0 RCX: 00007f66e998f749 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 00007ffff9acee10 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001 +R13: 00007f66e9be5fa0 R14: 00007f66e9be5fa0 R15: 0000000000000006 + + +Fixes: ae155060247b ("mptcp: fix duplicate reset on fastclose") +Reported-by: syzbot+3a92d359bc2ec6255a33@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/69260882.a70a0220.d98e3.00b4.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Matthieu Baerts (NGI0) +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251125195331.309558-1-kuniyu@google.com +Signed-off-by: Paolo Abeni +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/protocol.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2806,6 +2806,12 @@ static void mptcp_do_fastclose(struct so + goto unlock; + + subflow->send_fastclose = 1; ++ ++ /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 ++ * issue in __tcp_select_window(), see tcp_disconnect(). ++ */ ++ inet_csk(ssk)->icsk_ack.rcv_mss = TCP_MIN_MSS; ++ + tcp_send_active_reset(ssk, ssk->sk_allocation); + unlock: + release_sock(ssk); diff --git a/queue-6.1/mptcp-pm-ignore-unknown-endpoint-flags.patch b/queue-6.1/mptcp-pm-ignore-unknown-endpoint-flags.patch new file mode 100644 index 0000000000..7d7baa6821 --- /dev/null +++ b/queue-6.1/mptcp-pm-ignore-unknown-endpoint-flags.patch @@ -0,0 +1,68 @@ +From stable+bounces-204220-greg=kroah.com@vger.kernel.org Tue Dec 30 14:48:47 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 08:48:42 -0500 +Subject: mptcp: pm: ignore unknown endpoint flags +To: stable@vger.kernel.org +Cc: "Matthieu Baerts (NGI0)" , Mat Martineau , Jakub Kicinski , Sasha Levin +Message-ID: <20251230134842.2212007-1-sashal@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +[ Upstream commit 0ace3297a7301911e52d8195cb1006414897c859 ] + +Before this patch, the kernel was saving any flags set by the userspace, +even unknown ones. This doesn't cause critical issues because the kernel +is only looking at specific ones. But on the other hand, endpoints dumps +could tell the userspace some recent flags seem to be supported on older +kernel versions. + +Instead, ignore all unknown flags when parsing them. By doing that, the +userspace can continue to set unsupported flags, but it has a way to +verify what is supported by the kernel. + +Note that it sounds better to continue accepting unsupported flags not +to change the behaviour, but also that eases things on the userspace +side by adding "optional" endpoint types only supported by newer kernel +versions without having to deal with the different kernel versions. + +A note for the backports: there will be conflicts in mptcp.h on older +versions not having the mentioned flags, the new line should still be +added last, and the '5' needs to be adapted to have the same value as +the last entry. + +Fixes: 01cacb00b35c ("mptcp: add netlink-based PM") +Cc: stable@vger.kernel.org +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20251205-net-mptcp-misc-fixes-6-19-rc1-v1-1-9e4781a6c1b8@kernel.org +Signed-off-by: Jakub Kicinski +[ GENMASK(5, 0) => GENMASK(4, 0) + context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/uapi/linux/mptcp.h | 1 + + net/mptcp/pm_netlink.c | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/include/uapi/linux/mptcp.h ++++ b/include/uapi/linux/mptcp.h +@@ -88,6 +88,7 @@ enum { + #define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) + #define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) + #define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) ++#define MPTCP_PM_ADDR_FLAGS_MASK GENMASK(4, 0) + + enum { + MPTCP_PM_CMD_UNSPEC, +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -1424,7 +1424,8 @@ int mptcp_pm_parse_entry(struct nlattr * + } + + if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) +- entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]); ++ entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]) & ++ MPTCP_PM_ADDR_FLAGS_MASK; + + if (tb[MPTCP_PM_ADDR_ATTR_PORT]) + entry->addr.port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT])); diff --git a/queue-6.1/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch b/queue-6.1/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch new file mode 100644 index 0000000000..91a4ef3e45 --- /dev/null +++ b/queue-6.1/net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch @@ -0,0 +1,49 @@ +From stable+bounces-200123-greg=kroah.com@vger.kernel.org Fri Dec 5 06:56:07 2025 +From: Chen Yu +Date: Fri, 5 Dec 2025 13:54:48 +0800 +Subject: net: dsa: sja1105: fix kasan out-of-bounds warning in sja1105_table_delete_entry() +To: vladimir.oltean@nxp.com, horms@kernel.org, kuba@kernel.org +Cc: stable@vger.kernel.org +Message-ID: <20251205055448.3030-1-xnguchen@sina.cn> + +From: Vladimir Oltean + +[ Upstream commit 5f2b28b79d2d1946ee36ad8b3dc0066f73c90481 ] + +There are actually 2 problems: +- deleting the last element doesn't require the memmove of elements + [i + 1, end) over it. Actually, element i+1 is out of bounds. +- The memmove itself should move size - i - 1 elements, because the last + element is out of bounds. + +The out-of-bounds element still remains out of bounds after being +accessed, so the problem is only that we touch it, not that it becomes +in active use. But I suppose it can lead to issues if the out-of-bounds +element is part of an unmapped page. + +Fixes: 6666cebc5e30 ("net: dsa: sja1105: Add support for VLAN operations") +Signed-off-by: Vladimir Oltean +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250318115716.2124395-4-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Chen Yu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/sja1105/sja1105_static_config.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/sja1105/sja1105_static_config.c ++++ b/drivers/net/dsa/sja1105/sja1105_static_config.c +@@ -1921,8 +1921,10 @@ int sja1105_table_delete_entry(struct sj + if (i > table->entry_count) + return -ERANGE; + +- memmove(entries + i * entry_size, entries + (i + 1) * entry_size, +- (table->entry_count - i) * entry_size); ++ if (i + 1 < table->entry_count) { ++ memmove(entries + i * entry_size, entries + (i + 1) * entry_size, ++ (table->entry_count - i - 1) * entry_size); ++ } + + table->entry_count--; + diff --git a/queue-6.1/net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch b/queue-6.1/net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch new file mode 100644 index 0000000000..c929482154 --- /dev/null +++ b/queue-6.1/net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch @@ -0,0 +1,300 @@ +From stable+bounces-206190-greg=kroah.com@vger.kernel.org Wed Jan 7 18:48:09 2026 +From: Thadeu Lima de Souza Cascardo +Date: Wed, 7 Jan 2026 14:21:16 -0300 +Subject: net: Remove RTNL dance for SIOCBRADDIF and SIOCBRDELIF. +To: stable@vger.kernel.org +Cc: Thadeu Lima de Souza Cascardo , syzkaller , yan kang , yue sun , Kuniyuki Iwashima , Stanislav Fomichev , Ido Schimmel , Nikolay Aleksandrov , Paolo Abeni +Message-ID: <20260107172116.2488542-1-cascardo@igalia.com> + +From: Thadeu Lima de Souza Cascardo + +commit ed3ba9b6e280e14cc3148c1b226ba453f02fa76c upstream. + +SIOCBRDELIF is passed to dev_ioctl() first and later forwarded to +br_ioctl_call(), which causes unnecessary RTNL dance and the splat +below [0] under RTNL pressure. + +Let's say Thread A is trying to detach a device from a bridge and +Thread B is trying to remove the bridge. + +In dev_ioctl(), Thread A bumps the bridge device's refcnt by +netdev_hold() and releases RTNL because the following br_ioctl_call() +also re-acquires RTNL. + +In the race window, Thread B could acquire RTNL and try to remove +the bridge device. Then, rtnl_unlock() by Thread B will release RTNL +and wait for netdev_put() by Thread A. + +Thread A, however, must hold RTNL after the unlock in dev_ifsioc(), +which may take long under RTNL pressure, resulting in the splat by +Thread B. + + Thread A (SIOCBRDELIF) Thread B (SIOCBRDELBR) + ---------------------- ---------------------- + sock_ioctl sock_ioctl + `- sock_do_ioctl `- br_ioctl_call + `- dev_ioctl `- br_ioctl_stub + |- rtnl_lock | + |- dev_ifsioc ' + ' |- dev = __dev_get_by_name(...) + |- netdev_hold(dev, ...) . + / |- rtnl_unlock ------. | + | |- br_ioctl_call `---> |- rtnl_lock + Race | | `- br_ioctl_stub |- br_del_bridge + Window | | | |- dev = __dev_get_by_name(...) + | | | May take long | `- br_dev_delete(dev, ...) + | | | under RTNL pressure | `- unregister_netdevice_queue(dev, ...) + | | | | `- rtnl_unlock + \ | |- rtnl_lock <-' `- netdev_run_todo + | |- ... `- netdev_run_todo + | `- rtnl_unlock |- __rtnl_unlock + | |- netdev_wait_allrefs_any + |- netdev_put(dev, ...) <----------------' + Wait refcnt decrement + and log splat below + +To avoid blocking SIOCBRDELBR unnecessarily, let's not call +dev_ioctl() for SIOCBRADDIF and SIOCBRDELIF. + +In the dev_ioctl() path, we do the following: + + 1. Copy struct ifreq by get_user_ifreq in sock_do_ioctl() + 2. Check CAP_NET_ADMIN in dev_ioctl() + 3. Call dev_load() in dev_ioctl() + 4. Fetch the master dev from ifr.ifr_name in dev_ifsioc() + +3. can be done by request_module() in br_ioctl_call(), so we move +1., 2., and 4. to br_ioctl_stub(). + +Note that 2. is also checked later in add_del_if(), but it's better +performed before RTNL. + +SIOCBRADDIF and SIOCBRDELIF have been processed in dev_ioctl() since +the pre-git era, and there seems to be no specific reason to process +them there. + +[0]: +unregister_netdevice: waiting for wpan3 to become free. Usage count = 2 +ref_tracker: wpan3@ffff8880662d8608 has 1/1 users at + __netdev_tracker_alloc include/linux/netdevice.h:4282 [inline] + netdev_hold include/linux/netdevice.h:4311 [inline] + dev_ifsioc+0xc6a/0x1160 net/core/dev_ioctl.c:624 + dev_ioctl+0x255/0x10c0 net/core/dev_ioctl.c:826 + sock_do_ioctl+0x1ca/0x260 net/socket.c:1213 + sock_ioctl+0x23a/0x6c0 net/socket.c:1318 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:906 [inline] + __se_sys_ioctl fs/ioctl.c:892 [inline] + __x64_sys_ioctl+0x1a4/0x210 fs/ioctl.c:892 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xcb/0x250 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 893b19587534 ("net: bridge: fix ioctl locking") +Reported-by: syzkaller +Reported-by: yan kang +Reported-by: yue sun +Closes: https://lore.kernel.org/netdev/SY8P300MB0421225D54EB92762AE8F0F2A1D32@SY8P300MB0421.AUSP300.PROD.OUTLOOK.COM/ +Signed-off-by: Kuniyuki Iwashima +Acked-by: Stanislav Fomichev +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20250316192851.19781-1-kuniyu@amazon.com +Signed-off-by: Paolo Abeni +[cascardo: fixed conflict at dev_ifsioc] +Signed-off-by: Thadeu Lima de Souza Cascardo +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/if_bridge.h | 6 ++---- + net/bridge/br_ioctl.c | 36 +++++++++++++++++++++++++++++++++--- + net/bridge/br_private.h | 3 +-- + net/core/dev_ioctl.c | 16 ---------------- + net/socket.c | 19 +++++++++---------- + 5 files changed, 45 insertions(+), 35 deletions(-) + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -63,11 +63,9 @@ struct br_ip_list { + #define BR_DEFAULT_AGEING_TIME (300 * HZ) + + struct net_bridge; +-void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br, +- unsigned int cmd, struct ifreq *ifr, ++void brioctl_set(int (*hook)(struct net *net, unsigned int cmd, + void __user *uarg)); +-int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, +- struct ifreq *ifr, void __user *uarg); ++int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg); + + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) + int br_multicast_list_adjacent(struct net_device *dev, +--- a/net/bridge/br_ioctl.c ++++ b/net/bridge/br_ioctl.c +@@ -394,10 +394,26 @@ static int old_deviceless(struct net *ne + return -EOPNOTSUPP; + } + +-int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd, +- struct ifreq *ifr, void __user *uarg) ++int br_ioctl_stub(struct net *net, unsigned int cmd, void __user *uarg) + { + int ret = -EOPNOTSUPP; ++ struct ifreq ifr; ++ ++ if (cmd == SIOCBRADDIF || cmd == SIOCBRDELIF) { ++ void __user *data; ++ char *colon; ++ ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (get_user_ifreq(&ifr, &data, uarg)) ++ return -EFAULT; ++ ++ ifr.ifr_name[IFNAMSIZ - 1] = 0; ++ colon = strchr(ifr.ifr_name, ':'); ++ if (colon) ++ *colon = 0; ++ } + + rtnl_lock(); + +@@ -430,7 +446,21 @@ int br_ioctl_stub(struct net *net, struc + break; + case SIOCBRADDIF: + case SIOCBRDELIF: +- ret = add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF); ++ { ++ struct net_device *dev; ++ ++ dev = __dev_get_by_name(net, ifr.ifr_name); ++ if (!dev || !netif_device_present(dev)) { ++ ret = -ENODEV; ++ break; ++ } ++ if (!netif_is_bridge_master(dev)) { ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ ret = add_del_if(netdev_priv(dev), ifr.ifr_ifindex, cmd == SIOCBRADDIF); ++ } + break; + } + +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -895,8 +895,7 @@ br_port_get_check_rtnl(const struct net_ + /* br_ioctl.c */ + int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, + void __user *data, int cmd); +-int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd, +- struct ifreq *ifr, void __user *uarg); ++int br_ioctl_stub(struct net *net, unsigned int cmd, void __user *uarg); + + /* br_multicast.c */ + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING +--- a/net/core/dev_ioctl.c ++++ b/net/core/dev_ioctl.c +@@ -315,7 +315,6 @@ static int dev_ifsioc(struct net *net, s + int err; + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); + const struct net_device_ops *ops; +- netdevice_tracker dev_tracker; + + if (!dev) + return -ENODEV; +@@ -378,19 +377,6 @@ static int dev_ifsioc(struct net *net, s + case SIOCWANDEV: + return dev_siocwandev(dev, &ifr->ifr_settings); + +- case SIOCBRADDIF: +- case SIOCBRDELIF: +- if (!netif_device_present(dev)) +- return -ENODEV; +- if (!netif_is_bridge_master(dev)) +- return -EOPNOTSUPP; +- netdev_hold(dev, &dev_tracker, GFP_KERNEL); +- rtnl_unlock(); +- err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL); +- netdev_put(dev, &dev_tracker); +- rtnl_lock(); +- return err; +- + case SIOCSHWTSTAMP: + err = net_hwtstamp_validate(ifr); + if (err) +@@ -575,8 +561,6 @@ int dev_ioctl(struct net *net, unsigned + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: +- case SIOCBRADDIF: +- case SIOCBRDELIF: + case SIOCSHWTSTAMP: + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + return -EPERM; +--- a/net/socket.c ++++ b/net/socket.c +@@ -1151,12 +1151,10 @@ static ssize_t sock_write_iter(struct ki + */ + + static DEFINE_MUTEX(br_ioctl_mutex); +-static int (*br_ioctl_hook)(struct net *net, struct net_bridge *br, +- unsigned int cmd, struct ifreq *ifr, ++static int (*br_ioctl_hook)(struct net *net, unsigned int cmd, + void __user *uarg); + +-void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br, +- unsigned int cmd, struct ifreq *ifr, ++void brioctl_set(int (*hook)(struct net *net, unsigned int cmd, + void __user *uarg)) + { + mutex_lock(&br_ioctl_mutex); +@@ -1165,8 +1163,7 @@ void brioctl_set(int (*hook)(struct net + } + EXPORT_SYMBOL(brioctl_set); + +-int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, +- struct ifreq *ifr, void __user *uarg) ++int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg) + { + int err = -ENOPKG; + +@@ -1175,7 +1172,7 @@ int br_ioctl_call(struct net *net, struc + + mutex_lock(&br_ioctl_mutex); + if (br_ioctl_hook) +- err = br_ioctl_hook(net, br, cmd, ifr, uarg); ++ err = br_ioctl_hook(net, cmd, uarg); + mutex_unlock(&br_ioctl_mutex); + + return err; +@@ -1272,7 +1269,9 @@ static long sock_ioctl(struct file *file + case SIOCSIFBR: + case SIOCBRADDBR: + case SIOCBRDELBR: +- err = br_ioctl_call(net, NULL, cmd, NULL, argp); ++ case SIOCBRADDIF: ++ case SIOCBRDELIF: ++ err = br_ioctl_call(net, cmd, argp); + break; + case SIOCGIFVLAN: + case SIOCSIFVLAN: +@@ -3376,6 +3375,8 @@ static int compat_sock_ioctl_trans(struc + case SIOCGPGRP: + case SIOCBRADDBR: + case SIOCBRDELBR: ++ case SIOCBRADDIF: ++ case SIOCBRDELIF: + case SIOCGIFVLAN: + case SIOCSIFVLAN: + case SIOCGSKNS: +@@ -3415,8 +3416,6 @@ static int compat_sock_ioctl_trans(struc + case SIOCGIFPFLAGS: + case SIOCGIFTXQLEN: + case SIOCSIFTXQLEN: +- case SIOCBRADDIF: +- case SIOCBRDELIF: + case SIOCGIFNAME: + case SIOCSIFNAME: + case SIOCGMIIPHY: diff --git a/queue-6.1/nfsd-clear-seclabel-in-the-suppattr_exclcreat-bitmap.patch b/queue-6.1/nfsd-clear-seclabel-in-the-suppattr_exclcreat-bitmap.patch new file mode 100644 index 0000000000..5614ad8cf3 --- /dev/null +++ b/queue-6.1/nfsd-clear-seclabel-in-the-suppattr_exclcreat-bitmap.patch @@ -0,0 +1,57 @@ +From stable+bounces-204318-greg=kroah.com@vger.kernel.org Wed Dec 31 04:55:43 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 22:55:37 -0500 +Subject: NFSD: Clear SECLABEL in the suppattr_exclcreat bitmap +To: stable@vger.kernel.org +Cc: Chuck Lever , Jeff Layton , Sasha Levin +Message-ID: <20251231035537.2722284-1-sashal@kernel.org> + +From: Chuck Lever + +[ Upstream commit 27d17641cacfedd816789b75d342430f6b912bd2 ] + +>>From RFC 8881: + +5.8.1.14. Attribute 75: suppattr_exclcreat + +> The bit vector that would set all REQUIRED and RECOMMENDED +> attributes that are supported by the EXCLUSIVE4_1 method of file +> creation via the OPEN operation. The scope of this attribute +> applies to all objects with a matching fsid. + +There's nothing in RFC 8881 that states that suppattr_exclcreat is +or is not allowed to contain bits for attributes that are clear in +the reported supported_attrs bitmask. But it doesn't make sense for +an NFS server to indicate that it /doesn't/ implement an attribute, +but then also indicate that clients /are/ allowed to set that +attribute using OPEN(create) with EXCLUSIVE4_1. + +Ensure that the SECURITY_LABEL and ACL bits are not set in the +suppattr_exclcreat bitmask when they are also not set in the +supported_attrs bitmask. + +Fixes: 8c18f2052e75 ("nfsd41: SUPPATTR_EXCLCREAT attribute") +Cc: stable@vger.kernel.org +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4xdr.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3408,6 +3408,11 @@ out_acl: + u32 supp[3]; + + memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp)); ++ if (!IS_POSIXACL(d_inode(dentry))) ++ supp[0] &= ~FATTR4_WORD0_ACL; ++ if (!contextsupport) ++ supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++ + supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0; + supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; + supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; diff --git a/queue-6.1/nfsd-nfsv4-file-creation-neglects-setting-acl.patch b/queue-6.1/nfsd-nfsv4-file-creation-neglects-setting-acl.patch new file mode 100644 index 0000000000..40b9399c22 --- /dev/null +++ b/queue-6.1/nfsd-nfsv4-file-creation-neglects-setting-acl.patch @@ -0,0 +1,49 @@ +From stable+bounces-204918-greg=kroah.com@vger.kernel.org Mon Jan 5 21:33:17 2026 +From: Chuck Lever +Date: Mon, 5 Jan 2026 15:33:11 -0500 +Subject: NFSD: NFSv4 file creation neglects setting ACL +To: +Cc: Greg Kroah-Hartman , Sasha Levin , , Chuck Lever , Aurelien Couderc +Message-ID: <20260105203311.3562329-1-cel@kernel.org> + +From: Chuck Lever + +[ Upstream commit 913f7cf77bf14c13cfea70e89bcb6d0b22239562 ] + +An NFSv4 client that sets an ACL with a named principal during file +creation retrieves the ACL afterwards, and finds that it is only a +default ACL (based on the mode bits) and not the ACL that was +requested during file creation. This violates RFC 8881 section +6.4.1.3: "the ACL attribute is set as given". + +The issue occurs in nfsd_create_setattr(). On 6.1.y, the check to +determine whether nfsd_setattr() should be called is simply +"iap->ia_valid", which only accounts for iattr changes. When only +an ACL is present (and no iattr fields are set), nfsd_setattr() is +skipped and the POSIX ACL is never applied to the inode. + +Subsequently, when the client retrieves the ACL, the server finds +no POSIX ACL on the inode and returns one generated from the file's +mode bits rather than returning the originally-specified ACL. + +Reported-by: Aurelien Couderc +Fixes: c0cbe70742f4 ("NFSD: add posix ACLs to struct nfsd_attrs") +Cc: stable@vger.kernel.org +[ cel: Adjust nfsd_create_setattr() instead of nfsd_attrs_valid() ] +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/vfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1320,7 +1320,7 @@ nfsd_create_setattr(struct svc_rqst *rqs + * Callers expect new file metadata to be committed even + * if the attributes have not changed. + */ +- if (iap->ia_valid) ++ if (iap->ia_valid || attrs->na_pacl || attrs->na_dpacl) + status = nfsd_setattr(rqstp, resfhp, attrs, 0, (time64_t)0); + else + status = nfserrno(commit_metadata(resfhp)); diff --git a/queue-6.1/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch b/queue-6.1/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch new file mode 100644 index 0000000000..a2720ba13e --- /dev/null +++ b/queue-6.1/page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch @@ -0,0 +1,146 @@ +From stable+bounces-200718-greg=kroah.com@vger.kernel.org Wed Dec 10 13:16:30 2025 +From: ruohanlan@aliyun.com +Date: Wed, 10 Dec 2025 12:15:55 +0000 +Subject: page_pool: Fix use-after-free in page_pool_recycle_in_ring +To: stable@vger.kernel.org +Cc: "Dong Chenchen" , "Jakub Kicinski" , syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com, "Toke Høiland-Jørgensen" , "Mina Almasry" , "Ruohan Lan" +Message-ID: <20251210121555.5106-1-ruohanlan@aliyun.com> + +From: Dong Chenchen + +[ Upstream commit 271683bb2cf32e5126c592b5d5e6a756fa374fd9 ] + +syzbot reported a uaf in page_pool_recycle_in_ring: + +BUG: KASAN: slab-use-after-free in lock_release+0x151/0xa30 kernel/locking/lockdep.c:5862 +Read of size 8 at addr ffff8880286045a0 by task syz.0.284/6943 + +CPU: 0 UID: 0 PID: 6943 Comm: syz.0.284 Not tainted 6.13.0-rc3-syzkaller-gdfa94ce54f41 #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 +Call Trace: + + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0x169/0x550 mm/kasan/report.c:489 + kasan_report+0x143/0x180 mm/kasan/report.c:602 + lock_release+0x151/0xa30 kernel/locking/lockdep.c:5862 + __raw_spin_unlock_bh include/linux/spinlock_api_smp.h:165 [inline] + _raw_spin_unlock_bh+0x1b/0x40 kernel/locking/spinlock.c:210 + spin_unlock_bh include/linux/spinlock.h:396 [inline] + ptr_ring_produce_bh include/linux/ptr_ring.h:164 [inline] + page_pool_recycle_in_ring net/core/page_pool.c:707 [inline] + page_pool_put_unrefed_netmem+0x748/0xb00 net/core/page_pool.c:826 + page_pool_put_netmem include/net/page_pool/helpers.h:323 [inline] + page_pool_put_full_netmem include/net/page_pool/helpers.h:353 [inline] + napi_pp_put_page+0x149/0x2b0 net/core/skbuff.c:1036 + skb_pp_recycle net/core/skbuff.c:1047 [inline] + skb_free_head net/core/skbuff.c:1094 [inline] + skb_release_data+0x6c4/0x8a0 net/core/skbuff.c:1125 + skb_release_all net/core/skbuff.c:1190 [inline] + __kfree_skb net/core/skbuff.c:1204 [inline] + sk_skb_reason_drop+0x1c9/0x380 net/core/skbuff.c:1242 + kfree_skb_reason include/linux/skbuff.h:1263 [inline] + __skb_queue_purge_reason include/linux/skbuff.h:3343 [inline] + +root cause is: + +page_pool_recycle_in_ring + ptr_ring_produce + spin_lock(&r->producer_lock); + WRITE_ONCE(r->queue[r->producer++], ptr) + //recycle last page to pool + page_pool_release + page_pool_scrub + page_pool_empty_ring + ptr_ring_consume + page_pool_return_page //release all page + __page_pool_destroy + free_percpu(pool->recycle_stats); + free(pool) //free + + spin_unlock(&r->producer_lock); //pool->ring uaf read + recycle_stat_inc(pool, ring); + +page_pool can be free while page pool recycle the last page in ring. +Add producer-lock barrier to page_pool_release to prevent the page +pool from being free before all pages have been recycled. + +recycle_stat_inc() is empty when CONFIG_PAGE_POOL_STATS is not +enabled, which will trigger Wempty-body build warning. Add definition +for pool stat macro to fix warning. + +Suggested-by: Jakub Kicinski +Link: https://lore.kernel.org/netdev/20250513083123.3514193-1-dongchenchen2@huawei.com +Fixes: ff7d6b27f894 ("page_pool: refurbish version of page_pool code") +Reported-by: syzbot+204a4382fcb3311f3858@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=204a4382fcb3311f3858 +Signed-off-by: Dong Chenchen +Reviewed-by: Toke Høiland-Jørgensen +Reviewed-by: Mina Almasry +Link: https://patch.msgid.link/20250527114152.3119109-1-dongchenchen2@huawei.com +Signed-off-by: Jakub Kicinski +[ Minor context change fixed. ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + net/core/page_pool.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -128,9 +128,9 @@ u64 *page_pool_ethtool_stats_get(u64 *da + EXPORT_SYMBOL(page_pool_ethtool_stats_get); + + #else +-#define alloc_stat_inc(pool, __stat) +-#define recycle_stat_inc(pool, __stat) +-#define recycle_stat_add(pool, __stat, val) ++#define alloc_stat_inc(...) do { } while (0) ++#define recycle_stat_inc(...) do { } while (0) ++#define recycle_stat_add(...) do { } while (0) + #endif + + static bool page_pool_producer_lock(struct page_pool *pool) +@@ -539,19 +539,16 @@ static void page_pool_return_page(struct + + static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page) + { +- int ret; +- /* BH protection not needed if current is softirq */ +- if (in_softirq()) +- ret = ptr_ring_produce(&pool->ring, page); +- else +- ret = ptr_ring_produce_bh(&pool->ring, page); ++ bool in_softirq, ret; + +- if (!ret) { ++ /* BH protection not needed if current is softirq */ ++ in_softirq = page_pool_producer_lock(pool); ++ ret = !__ptr_ring_produce(&pool->ring, page); ++ if (ret) + recycle_stat_inc(pool, ring); +- return true; +- } ++ page_pool_producer_unlock(pool, in_softirq); + +- return false; ++ return ret; + } + + /* Only allow direct recycling in special circumstances, into the +@@ -826,10 +823,14 @@ static void page_pool_scrub(struct page_ + + static int page_pool_release(struct page_pool *pool) + { ++ bool in_softirq; + int inflight; + + page_pool_scrub(pool); + inflight = page_pool_inflight(pool); ++ /* Acquire producer lock to make sure producers have exited. */ ++ in_softirq = page_pool_producer_lock(pool); ++ page_pool_producer_unlock(pool, in_softirq); + if (!inflight) + page_pool_free(pool); + diff --git a/queue-6.1/pci-brcmstb-fix-disabling-l0s-capability.patch b/queue-6.1/pci-brcmstb-fix-disabling-l0s-capability.patch new file mode 100644 index 0000000000..7dfdfea9fe --- /dev/null +++ b/queue-6.1/pci-brcmstb-fix-disabling-l0s-capability.patch @@ -0,0 +1,79 @@ +From stable+bounces-204893-greg=kroah.com@vger.kernel.org Mon Jan 5 20:14:47 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 14:14:41 -0500 +Subject: PCI: brcmstb: Fix disabling L0s capability +To: stable@vger.kernel.org +Cc: Jim Quinlan , Bjorn Helgaas , Manivannan Sadhasivam , Florian Fainelli , Sasha Levin +Message-ID: <20260105191441.2731420-1-sashal@kernel.org> + +From: Jim Quinlan + +[ Upstream commit 9583f9d22991d2cfb5cc59a2552040c4ae98d998 ] + +caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") +set PCI_EXP_LNKCAP_ASPM_L1 and (optionally) PCI_EXP_LNKCAP_ASPM_L0S in +PCI_EXP_LNKCAP (aka PCIE_RC_CFG_PRIV1_LINK_CAPABILITY in brcmstb). + +But instead of using PCI_EXP_LNKCAP_ASPM_L1 and PCI_EXP_LNKCAP_ASPM_L0S +directly, it used PCIE_LINK_STATE_L1 and PCIE_LINK_STATE_L0S, which are +Linux-created values that only coincidentally matched the PCIe spec. +b478e162f227 ("PCI/ASPM: Consolidate link state defines") later changed +them so they no longer matched the PCIe spec, so the bits ended up in the +wrong place in PCI_EXP_LNKCAP. + +Use PCI_EXP_LNKCAP_ASPM_L0S to clear L0s support when there's an +'aspm-no-l0s' property. Rely on brcmstb hardware to advertise L0s and/or +L1 support otherwise. + +Fixes: caab002d5069 ("PCI: brcmstb: Disable L0s component of ASPM if requested") +Reported-by: Bjorn Helgaas +Closes: https://lore.kernel.org/linux-pci/20250925194424.GA2197200@bhelgaas +Signed-off-by: Jim Quinlan +[mani: reworded subject and description, added closes tag and CCed stable] +Signed-off-by: Manivannan Sadhasivam +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Florian Fainelli +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251003170436.1446030-1-james.quinlan@broadcom.com +[ adapted context due to missing link width negotiation defines and variables ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/controller/pcie-brcmstb.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -45,7 +45,6 @@ + #define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff + + #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc +-#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + + #define PCIE_RC_DL_MDIO_ADDR 0x1100 + #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 +@@ -869,7 +868,7 @@ static int brcm_pcie_setup(struct brcm_p + void __iomem *base = pcie->base; + struct pci_host_bridge *bridge; + struct resource_entry *entry; +- u32 tmp, burst, aspm_support; ++ u32 tmp, burst; + int num_out_wins = 0; + int ret, memc; + +@@ -963,12 +962,9 @@ static int brcm_pcie_setup(struct brcm_p + writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); + + /* Don't advertise L0s capability if 'aspm-no-l0s' */ +- aspm_support = PCIE_LINK_STATE_L1; +- if (!of_property_read_bool(pcie->np, "aspm-no-l0s")) +- aspm_support |= PCIE_LINK_STATE_L0S; + tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); +- u32p_replace_bits(&tmp, aspm_support, +- PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); ++ if (of_property_read_bool(pcie->np, "aspm-no-l0s")) ++ tmp &= ~PCI_EXP_LNKCAP_ASPM_L0S; + writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + + /* diff --git a/queue-6.1/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_probe.patch b/queue-6.1/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_probe.patch new file mode 100644 index 0000000000..b1682929c3 --- /dev/null +++ b/queue-6.1/pmdomain-imx-fix-reference-count-leak-in-imx_gpc_probe.patch @@ -0,0 +1,48 @@ +From stable+bounces-205127-greg=kroah.com@vger.kernel.org Tue Jan 6 19:44:43 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:05:17 -0500 +Subject: pmdomain: imx: Fix reference count leak in imx_gpc_probe() +To: stable@vger.kernel.org +Cc: Wentao Liang , Frank Li , Ulf Hansson , Sasha Levin +Message-ID: <20260106170520.3081258-2-sashal@kernel.org> + +From: Wentao Liang + +[ Upstream commit 73cb5f6eafb0ac7aea8cdeb8ff12981aa741d8fb ] + +of_get_child_by_name() returns a node pointer with refcount incremented. +Use the __free() attribute to manage the pgc_node reference, ensuring +automatic of_node_put() cleanup when pgc_node goes out of scope. + +This eliminates the need for explicit error handling paths and avoids +reference count leaks. + +Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver") +Cc: stable@vger.kernel.org +Signed-off-by: Wentao Liang +Reviewed-by: Frank Li +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/soc/imx/gpc.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/soc/imx/gpc.c ++++ b/drivers/soc/imx/gpc.c +@@ -405,13 +405,12 @@ clk_err: + static int imx_gpc_probe(struct platform_device *pdev) + { + const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev); +- struct device_node *pgc_node; ++ struct device_node *pgc_node __free(device_node) ++ = of_get_child_by_name(pdev->dev.of_node, "pgc"); + struct regmap *regmap; + void __iomem *base; + int ret; + +- pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); +- + /* bail out if DT too old and doesn't provide the necessary info */ + if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + !pgc_node) diff --git a/queue-6.1/pmdomain-use-device_get_match_data.patch b/queue-6.1/pmdomain-use-device_get_match_data.patch new file mode 100644 index 0000000000..0835a1ed02 --- /dev/null +++ b/queue-6.1/pmdomain-use-device_get_match_data.patch @@ -0,0 +1,134 @@ +From stable+bounces-205126-greg=kroah.com@vger.kernel.org Tue Jan 6 18:13:57 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:05:16 -0500 +Subject: pmdomain: Use device_get_match_data() +To: stable@vger.kernel.org +Cc: Rob Herring , Ulf Hansson , Sasha Levin +Message-ID: <20260106170520.3081258-1-sashal@kernel.org> + +From: Rob Herring + +[ Upstream commit 3ba9fdfaa550936837b50b73d6c27ac401fde875 ] + +Use preferred device_get_match_data() instead of of_match_device() to +get the driver match data. With this, adjust the includes to explicitly +include the correct headers. + +Signed-off-by: Rob Herring +Link: https://lore.kernel.org/r/20231006224614.444488-1-robh@kernel.org +Signed-off-by: Ulf Hansson +Stable-dep-of: 73cb5f6eafb0 ("pmdomain: imx: Fix reference count leak in imx_gpc_probe()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/soc/actions/owl-sps.c | 16 +++++----------- + drivers/soc/imx/gpc.c | 7 +++---- + drivers/soc/rockchip/pm_domains.c | 13 ++++--------- + 3 files changed, 12 insertions(+), 24 deletions(-) + +--- a/drivers/soc/actions/owl-sps.c ++++ b/drivers/soc/actions/owl-sps.c +@@ -8,8 +8,10 @@ + * Copyright (c) 2017 Andreas Färber + */ + ++#include + #include +-#include ++#include ++#include + #include + #include + #include +@@ -96,24 +98,16 @@ static int owl_sps_init_domain(struct ow + + static int owl_sps_probe(struct platform_device *pdev) + { +- const struct of_device_id *match; + const struct owl_sps_info *sps_info; + struct owl_sps *sps; + int i, ret; + +- if (!pdev->dev.of_node) { +- dev_err(&pdev->dev, "no device node\n"); +- return -ENODEV; +- } +- +- match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); +- if (!match || !match->data) { ++ sps_info = device_get_match_data(&pdev->dev); ++ if (!sps_info) { + dev_err(&pdev->dev, "unknown compatible or missing data\n"); + return -EINVAL; + } + +- sps_info = match->data; +- + sps = devm_kzalloc(&pdev->dev, + struct_size(sps, domains, sps_info->num_domains), + GFP_KERNEL); +--- a/drivers/soc/imx/gpc.c ++++ b/drivers/soc/imx/gpc.c +@@ -7,9 +7,10 @@ + #include + #include + #include +-#include ++#include + #include + #include ++#include + #include + #include + +@@ -403,9 +404,7 @@ clk_err: + + static int imx_gpc_probe(struct platform_device *pdev) + { +- const struct of_device_id *of_id = +- of_match_device(imx_gpc_dt_ids, &pdev->dev); +- const struct imx_gpc_dt_data *of_id_data = of_id->data; ++ const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev); + struct device_node *pgc_node; + struct regmap *regmap; + void __iomem *base; +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -9,11 +9,13 @@ + #include + #include + #include ++#include + #include + #include ++#include ++#include + #include + #include +-#include + #include + #include + #include +@@ -770,7 +772,6 @@ static int rockchip_pm_domain_probe(stru + struct device_node *node; + struct device *parent; + struct rockchip_pmu *pmu; +- const struct of_device_id *match; + const struct rockchip_pmu_info *pmu_info; + int error; + +@@ -779,13 +780,7 @@ static int rockchip_pm_domain_probe(stru + return -ENODEV; + } + +- match = of_match_device(dev->driver->of_match_table, dev); +- if (!match || !match->data) { +- dev_err(dev, "missing pmu data\n"); +- return -EINVAL; +- } +- +- pmu_info = match->data; ++ pmu_info = device_get_match_data(dev); + + pmu = devm_kzalloc(dev, + struct_size(pmu, domains, pmu_info->num_domains), diff --git a/queue-6.1/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch b/queue-6.1/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch new file mode 100644 index 0000000000..a8314af0b6 --- /dev/null +++ b/queue-6.1/powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch @@ -0,0 +1,45 @@ +From stable+bounces-204888-greg=kroah.com@vger.kernel.org Mon Jan 5 19:21:13 2026 +From: Sasha Levin +Date: Mon, 5 Jan 2026 13:18:49 -0500 +Subject: powerpc/pseries/cmm: adjust BALLOON_MIGRATE when migrating pages +To: stable@vger.kernel.org +Cc: David Hildenbrand , "Ritesh Harjani (IBM)" , Christophe Leroy , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , Andrew Morton , Sasha Levin +Message-ID: <20260105181849.2717306-3-sashal@kernel.org> + +From: David Hildenbrand + +[ Upstream commit 0da2ba35c0d532ca0fe7af698b17d74c4d084b9a ] + +Let's properly adjust BALLOON_MIGRATE like the other drivers. + +Note that the INFLATE/DEFLATE events are triggered from the core when +enqueueing/dequeueing pages. + +This was found by code inspection. + +Link: https://lkml.kernel.org/r/20251021100606.148294-3-david@redhat.com +Fixes: fe030c9b85e6 ("powerpc/pseries/cmm: Implement balloon compaction") +Signed-off-by: David Hildenbrand +Reviewed-by: Ritesh Harjani (IBM) +Cc: Christophe Leroy +Cc: Madhavan Srinivasan +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/pseries/cmm.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/powerpc/platforms/pseries/cmm.c ++++ b/arch/powerpc/platforms/pseries/cmm.c +@@ -532,6 +532,7 @@ static int cmm_migratepage(struct balloo + + spin_lock_irqsave(&b_dev_info->pages_lock, flags); + balloon_page_insert(b_dev_info, newpage); ++ __count_vm_event(BALLOON_MIGRATE); + b_dev_info->isolated_pages--; + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); + diff --git a/queue-6.1/scsi-ufs-core-add-ufshcd_update_evt_hist-for-ufs-suspend-error.patch b/queue-6.1/scsi-ufs-core-add-ufshcd_update_evt_hist-for-ufs-suspend-error.patch new file mode 100644 index 0000000000..a4b156d6c9 --- /dev/null +++ b/queue-6.1/scsi-ufs-core-add-ufshcd_update_evt_hist-for-ufs-suspend-error.patch @@ -0,0 +1,50 @@ +From stable+bounces-204240-greg=kroah.com@vger.kernel.org Tue Dec 30 17:02:09 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 11:01:59 -0500 +Subject: scsi: ufs: core: Add ufshcd_update_evt_hist() for UFS suspend error +To: stable@vger.kernel.org +Cc: Seunghwan Baek , Peter Wang , "Martin K. Petersen" , Sasha Levin +Message-ID: <20251230160159.2292887-1-sashal@kernel.org> + +From: Seunghwan Baek + +[ Upstream commit c9f36f04a8a2725172cdf2b5e32363e4addcb14c ] + +If UFS resume fails, the event history is updated in ufshcd_resume(), but +there is no code anywhere to record UFS suspend. Therefore, add code to +record UFS suspend error event history. + +Fixes: dd11376b9f1b ("scsi: ufs: Split the drivers/scsi/ufs directory") +Cc: stable@vger.kernel.org +Signed-off-by: Seunghwan Baek +Reviewed-by: Peter Wang +Link: https://patch.msgid.link/20251210063854.1483899-2-sh8267.baek@samsung.com +Signed-off-by: Martin K. Petersen +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ufs/core/ufshcd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -9437,7 +9437,7 @@ static int ufshcd_suspend(struct ufs_hba + ret = ufshcd_setup_clocks(hba, false); + if (ret) { + ufshcd_enable_irq(hba); +- return ret; ++ goto out; + } + if (ufshcd_is_clkgating_allowed(hba)) { + hba->clk_gating.state = CLKS_OFF; +@@ -9448,6 +9448,9 @@ static int ufshcd_suspend(struct ufs_hba + ufshcd_vreg_set_lpm(hba); + /* Put the host controller in low power mode if possible */ + ufshcd_hba_vreg_set_lpm(hba); ++out: ++ if (ret) ++ ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret); + return ret; + } + diff --git a/queue-6.1/serial-make-uart_remove_one_port-return-void.patch b/queue-6.1/serial-make-uart_remove_one_port-return-void.patch new file mode 100644 index 0000000000..0a463cfa94 --- /dev/null +++ b/queue-6.1/serial-make-uart_remove_one_port-return-void.patch @@ -0,0 +1,245 @@ +From stable+bounces-204281-greg=kroah.com@vger.kernel.org Tue Dec 30 20:49:10 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 14:49:02 -0500 +Subject: serial: Make uart_remove_one_port() return void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Greg Kroah-Hartman" , "Sasha Levin" +Message-ID: <20251230194904.2442970-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit d5b3d02d0b107345f2a6ecb5b06f98356f5c97ab ] + +The return value is only ever used as a return value for remove callbacks +of platform drivers. This return value is ignored by the driver core. +(The only effect is an error message, but uart_remove_one_port() already +emitted one in this case.) + +So the return value isn't used at all and uart_remove_one_port() can be +changed to return void without any loss. Also this better matches the +Linux device model as remove functions are not supposed to fail. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20230512173810.131447-3-u.kleine-koenig@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 74098cc06e75 ("xhci: dbgtty: fix device unregister: fixup") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/atmel_serial.c | 5 ++--- + drivers/tty/serial/clps711x.c | 4 +++- + drivers/tty/serial/cpm_uart/cpm_uart_core.c | 5 ++++- + drivers/tty/serial/imx.c | 4 +++- + drivers/tty/serial/lantiq.c | 4 +++- + drivers/tty/serial/serial_core.c | 6 +----- + drivers/tty/serial/st-asc.c | 4 +++- + drivers/tty/serial/uartlite.c | 12 ++++-------- + drivers/tty/serial/xilinx_uartps.c | 5 ++--- + include/linux/serial_core.h | 2 +- + 10 files changed, 26 insertions(+), 25 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -3022,14 +3022,13 @@ static int atmel_serial_remove(struct pl + { + struct uart_port *port = platform_get_drvdata(pdev); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +- int ret = 0; + + tasklet_kill(&atmel_port->tasklet_rx); + tasklet_kill(&atmel_port->tasklet_tx); + + device_init_wakeup(&pdev->dev, 0); + +- ret = uart_remove_one_port(&atmel_uart, port); ++ uart_remove_one_port(&atmel_uart, port); + + kfree(atmel_port->rx_ring.buf); + +@@ -3039,7 +3038,7 @@ static int atmel_serial_remove(struct pl + + pdev->dev.of_node = NULL; + +- return ret; ++ return 0; + } + + static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, +--- a/drivers/tty/serial/clps711x.c ++++ b/drivers/tty/serial/clps711x.c +@@ -515,7 +515,9 @@ static int uart_clps711x_remove(struct p + { + struct clps711x_port *s = platform_get_drvdata(pdev); + +- return uart_remove_one_port(&clps711x_uart, &s->port); ++ uart_remove_one_port(&clps711x_uart, &s->port); ++ ++ return 0; + } + + static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { +--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c ++++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c +@@ -1428,7 +1428,10 @@ static int cpm_uart_probe(struct platfor + static int cpm_uart_remove(struct platform_device *ofdev) + { + struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev); +- return uart_remove_one_port(&cpm_reg, &pinfo->port); ++ ++ uart_remove_one_port(&cpm_reg, &pinfo->port); ++ ++ return 0; + } + + static const struct of_device_id cpm_uart_match[] = { +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -2538,7 +2538,9 @@ static int imx_uart_remove(struct platfo + { + struct imx_port *sport = platform_get_drvdata(pdev); + +- return uart_remove_one_port(&imx_uart_uart_driver, &sport->port); ++ uart_remove_one_port(&imx_uart_uart_driver, &sport->port); ++ ++ return 0; + } + + static void imx_uart_restore_context(struct imx_port *sport) +--- a/drivers/tty/serial/lantiq.c ++++ b/drivers/tty/serial/lantiq.c +@@ -918,7 +918,9 @@ static int lqasc_remove(struct platform_ + { + struct uart_port *port = platform_get_drvdata(pdev); + +- return uart_remove_one_port(&lqasc_reg, port); ++ uart_remove_one_port(&lqasc_reg, port); ++ ++ return 0; + } + + static const struct ltq_soc_data soc_data_lantiq = { +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -3186,13 +3186,12 @@ EXPORT_SYMBOL(uart_add_one_port); + * This unhooks (and hangs up) the specified port structure from the core + * driver. No further calls will be made to the low-level code for this port. + */ +-int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) ++void uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) + { + struct uart_state *state = drv->state + uport->line; + struct tty_port *port = &state->port; + struct uart_port *uart_port; + struct tty_struct *tty; +- int ret = 0; + + mutex_lock(&port_mutex); + +@@ -3208,7 +3207,6 @@ int uart_remove_one_port(struct uart_dri + + if (!uart_port) { + mutex_unlock(&port->mutex); +- ret = -EINVAL; + goto out; + } + uport->flags |= UPF_DEAD; +@@ -3251,8 +3249,6 @@ int uart_remove_one_port(struct uart_dri + mutex_unlock(&port->mutex); + out: + mutex_unlock(&port_mutex); +- +- return ret; + } + EXPORT_SYMBOL(uart_remove_one_port); + +--- a/drivers/tty/serial/st-asc.c ++++ b/drivers/tty/serial/st-asc.c +@@ -834,7 +834,9 @@ static int asc_serial_remove(struct plat + { + struct uart_port *port = platform_get_drvdata(pdev); + +- return uart_remove_one_port(&asc_uart_driver, port); ++ uart_remove_one_port(&asc_uart_driver, port); ++ ++ return 0; + } + + #ifdef CONFIG_PM_SLEEP +--- a/drivers/tty/serial/uartlite.c ++++ b/drivers/tty/serial/uartlite.c +@@ -686,18 +686,15 @@ static int ulite_assign(struct device *d + * + * @dev: pointer to device structure + */ +-static int ulite_release(struct device *dev) ++static void ulite_release(struct device *dev) + { + struct uart_port *port = dev_get_drvdata(dev); +- int rc = 0; + + if (port) { +- rc = uart_remove_one_port(&ulite_uart_driver, port); ++ uart_remove_one_port(&ulite_uart_driver, port); + dev_set_drvdata(dev, NULL); + port->mapbase = 0; + } +- +- return rc; + } + + /** +@@ -891,14 +888,13 @@ static int ulite_remove(struct platform_ + { + struct uart_port *port = dev_get_drvdata(&pdev->dev); + struct uartlite_data *pdata = port->private_data; +- int rc; + + clk_disable_unprepare(pdata->clk); +- rc = ulite_release(&pdev->dev); ++ ulite_release(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); +- return rc; ++ return 0; + } + + /* work with hotplug and coldplug */ +--- a/drivers/tty/serial/xilinx_uartps.c ++++ b/drivers/tty/serial/xilinx_uartps.c +@@ -1670,14 +1670,13 @@ static int cdns_uart_remove(struct platf + { + struct uart_port *port = platform_get_drvdata(pdev); + struct cdns_uart *cdns_uart_data = port->private_data; +- int rc; + + /* Remove the cdns_uart port from the serial core */ + #ifdef CONFIG_COMMON_CLK + clk_notifier_unregister(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb); + #endif +- rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port); ++ uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port); + port->mapbase = 0; + clk_disable_unprepare(cdns_uart_data->uartclk); + clk_disable_unprepare(cdns_uart_data->pclk); +@@ -1693,7 +1692,7 @@ static int cdns_uart_remove(struct platf + + if (!--instances) + uart_unregister_driver(cdns_uart_data->cdns_uart_driver); +- return rc; ++ return 0; + } + + static struct platform_driver cdns_uart_platform_driver = { +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -847,7 +847,7 @@ void uart_console_write(struct uart_port + int uart_register_driver(struct uart_driver *uart); + void uart_unregister_driver(struct uart_driver *uart); + int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); +-int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port); ++void uart_remove_one_port(struct uart_driver *reg, struct uart_port *port); + bool uart_match_port(const struct uart_port *port1, + const struct uart_port *port2); + diff --git a/queue-6.1/series b/queue-6.1/series index 80e5ea3f25..625794102e 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -523,3 +523,84 @@ mm-damon-tests-core-kunit-handle-memory-failure-from-damon_test_target.patch mm-damon-tests-core-kunit-handle-alloc-failures-on-damon_test_split_regions_of.patch mm-damon-tests-core-kunit-handle-memory-alloc-failure-from-damon_test_aggregate.patch mm-damon-tests-core-kunit-handle-alloc-failures-in-damon_test_set_regions.patch +kbuild-use-crc32-and-a-1mib-dictionary-for-xz-compressed-modules.patch +fscache-delete-fscache_cookie_lru_timer-when-fscache-exits-to-avoid-uaf.patch +net-dsa-sja1105-fix-kasan-out-of-bounds-warning-in-sja1105_table_delete_entry.patch +ksmbd-fix-out-of-bounds-in-parse_sec_desc.patch +page_pool-fix-use-after-free-in-page_pool_recycle_in_ring.patch +kvm-x86-mmu-use-emultype-flag-to-track-write-pfs-to-shadow-pages.patch +kvm-svm-don-t-skip-unrelated-instruction-if-int3-into-is-replaced.patch +mptcp-initialise-rcv_mss-before-calling-tcp_send_active_reset-in-mptcp_do_fastclose.patch +alsa-hda-cs35l41-fix-null-pointer-dereference-in-cs35l41_hda_read_acpi.patch +alsa-wavefront-use-guard-for-spin-locks.patch +alsa-wavefront-clear-substream-pointers-on-close.patch +alsa-wavefront-use-standard-print-api.patch +alsa-wavefront-fix-integer-overflow-in-sample-size-validation.patch +can-gs_usb-gs_can_open-fix-error-handling.patch +wifi-mt76-fix-dts-power-limits-on-little-endian-systems.patch +btrfs-don-t-rewrite-ret-from-inode_permission.patch +gfs2-fix-freeze-error-handling.patch +jbd2-fix-the-inconsistency-between-checksum-and-data-in-memory-for-journal-sb.patch +ext4-fix-string-copying-in-parse_apply_sb_mount_options.patch +mptcp-avoid-deadlock-on-fallback-while-reinjecting.patch +usb-ohci-nxp-use-helper-function-devm_clk_get_enabled.patch +usb-ohci-nxp-fix-device-leak-on-probe-failure.patch +mptcp-pm-ignore-unknown-endpoint-flags.patch +usb-dwc3-keep-susphy-enabled-during-exit-to-avoid-controller-faults.patch +scsi-ufs-core-add-ufshcd_update_evt_hist-for-ufs-suspend-error.patch +f2fs-fix-to-avoid-updating-zero-sized-extent-in-extent-cache.patch +f2fs-remove-unused-gc_failure_pin.patch +f2fs-keep-posix_fadv_noreuse-ranges.patch +f2fs-drop-inode-from-the-donation-list-when-the-last-file-is-closed.patch +f2fs-fix-to-avoid-updating-compression-context-during-writeback.patch +f2fs-fix-to-propagate-error-from-f2fs_enable_checkpoint.patch +f2fs-use-global-inline_xattr_slab-instead-of-per-sb-slab-cache.patch +f2fs-fix-to-detect-recoverable-inode-during-dryrun-of-find_fsync_dnodes.patch +nfsd-clear-seclabel-in-the-suppattr_exclcreat-bitmap.patch +sunrpc-svcauth_gss-avoid-null-deref-on-zero-length-gss_token-in-gss_read_proxy_verf.patch +btrfs-don-t-log-conflicting-inode-if-it-s-a-dir-moved-in-the-current-transaction.patch +crypto-af_alg-zero-initialize-memory-allocated-via-sock_kmalloc.patch +arm-dts-microchip-sama5d2-fix-spi-flexcom-fifo-size-to-32.patch +arm-dts-microchip-sama7g5-fix-uart-fifo-size-to-32.patch +iommu-mediatek-improve-safety-for-mediatek-smi-property-in-larb-nodes.patch +iommu-mediatek-fix-use-after-free-on-probe-deferral.patch +iommu-mtk_iommu_v1-convert-to-platform-remove-callback-returning-void.patch +iommu-mediatek-v1-fix-device-leaks-on-probe.patch +asoc-stm32-sai-use-the-devm_clk_get_optional-helper.patch +asoc-stm32-sai-fix-clk-prepare-imbalance-on-probe-failure.patch +fuse-fix-readahead-reclaim-deadlock.patch +asoc-stm-stm32_sai_sub-convert-to-platform-remove-callback-returning-void.patch +asoc-stm32-sai-fix-of-node-leak-on-probe.patch +media-verisilicon-fix-cpu-stalls-on-g2-bus-error.patch +arm64-dts-ti-k3-j721e-sk-fix-pinmux-for-pin-y1-used-by-power-regulator.patch +pci-brcmstb-fix-disabling-l0s-capability.patch +mm-balloon_compaction-we-cannot-have-isolated-pages-in-the-balloon-list.patch +mm-balloon_compaction-convert-balloon_page_delete-to-balloon_page_finalize.patch +powerpc-pseries-cmm-adjust-balloon_migrate-when-migrating-pages.patch +kvm-nvmx-immediately-refresh-apicv-controls-as-needed-on-nested-vm-exit.patch +media-amphion-add-a-frame-flush-mode-for-decoder.patch +media-amphion-make-some-vpu_v4l2-functions-static.patch +media-amphion-remove-vpu_vb_is_codecconfig.patch +media-mediatek-vcodec-fix-a-reference-leak-in-mtk_vcodec_fw_vpu_init.patch +pmdomain-use-device_get_match_data.patch +pmdomain-imx-fix-reference-count-leak-in-imx_gpc_probe.patch +mptcp-fallback-earlier-on-simult-connection.patch +lockd-fix-vfs_test_lock-calls.patch +mm-simplify-folio_expected_ref_count.patch +mm-consider-non-anon-swap-cache-folios-in-folio_expected_ref_count.patch +wifi-mac80211-discard-beacon-frames-to-non-broadcast-address.patch +drm-amdgpu-cleanup-scheduler-job-initialization-v2.patch +drm-amdgpu-add-missing-lock-to-amdgpu_ttm_access_memory_sdma.patch +drm-mediatek-fix-probe-memory-leak.patch +drm-gma500-remove-unused-helper-psb_fbdev_fb_setcolreg.patch +net-remove-rtnl-dance-for-siocbraddif-and-siocbrdelif.patch +serial-make-uart_remove_one_port-return-void.patch +tty-introduce-and-use-tty_port_tty_vhangup-helper.patch +xhci-dbgtty-fix-device-unregister-fixup.patch +nfsd-nfsv4-file-creation-neglects-setting-acl.patch +iommu-arm-smmu-drop-if-with-an-always-false-condition.patch +iommu-arm-smmu-convert-to-platform-remove-callback-returning-void.patch +iommu-qcom-use-the-asid-read-from-device-tree-if-specified.patch +iommu-qcom-index-contexts-by-asid-number-to-allow-asid-0.patch +iommu-qcom-fix-device-leak-on-of_xlate.patch +virtio_console-fix-order-of-fields-cols-and-rows.patch diff --git a/queue-6.1/sunrpc-svcauth_gss-avoid-null-deref-on-zero-length-gss_token-in-gss_read_proxy_verf.patch b/queue-6.1/sunrpc-svcauth_gss-avoid-null-deref-on-zero-length-gss_token-in-gss_read_proxy_verf.patch new file mode 100644 index 0000000000..ab6161e9d0 --- /dev/null +++ b/queue-6.1/sunrpc-svcauth_gss-avoid-null-deref-on-zero-length-gss_token-in-gss_read_proxy_verf.patch @@ -0,0 +1,41 @@ +From stable+bounces-204356-greg=kroah.com@vger.kernel.org Wed Dec 31 15:32:46 2025 +From: Sasha Levin +Date: Wed, 31 Dec 2025 09:32:39 -0500 +Subject: SUNRPC: svcauth_gss: avoid NULL deref on zero length gss_token in gss_read_proxy_verf +To: stable@vger.kernel.org +Cc: Joshua Rogers , Chuck Lever , Sasha Levin +Message-ID: <20251231143239.3043585-1-sashal@kernel.org> + +From: Joshua Rogers + +[ Upstream commit d4b69a6186b215d2dc1ebcab965ed88e8d41768d ] + +A zero length gss_token results in pages == 0 and in_token->pages[0] +is NULL. The code unconditionally evaluates +page_address(in_token->pages[0]) for the initial memcpy, which can +dereference NULL even when the copy length is 0. Guard the first +memcpy so it only runs when length > 0. + +Fixes: 5866efa8cbfb ("SUNRPC: Fix svcauth_gss_proxy_init()") +Cc: stable@vger.kernel.org +Signed-off-by: Joshua Rogers +Signed-off-by: Chuck Lever +[ adapted xdr buffer pointer API to older argv iov_base/iov_len API ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/sunrpc/auth_gss/svcauth_gss.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -1179,7 +1179,8 @@ static int gss_read_proxy_verf(struct sv + } + + length = min_t(unsigned int, inlen, argv->iov_len); +- memcpy(page_address(in_token->pages[0]), argv->iov_base, length); ++ if (length) ++ memcpy(page_address(in_token->pages[0]), argv->iov_base, length); + inlen -= length; + + to_offs = length; diff --git a/queue-6.1/tty-introduce-and-use-tty_port_tty_vhangup-helper.patch b/queue-6.1/tty-introduce-and-use-tty_port_tty_vhangup-helper.patch new file mode 100644 index 0000000000..83d159539d --- /dev/null +++ b/queue-6.1/tty-introduce-and-use-tty_port_tty_vhangup-helper.patch @@ -0,0 +1,233 @@ +From stable+bounces-204282-greg=kroah.com@vger.kernel.org Tue Dec 30 20:49:12 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 14:49:03 -0500 +Subject: tty: introduce and use tty_port_tty_vhangup() helper +To: stable@vger.kernel.org +Cc: "Jiri Slaby (SUSE)" , "Karsten Keil" , "David Lin" , "Johan Hovold" , "Alex Elder" , "Oliver Neukum" , "Marcel Holtmann" , "Johan Hedberg" , "Luiz Augusto von Dentz" , "Ilpo Järvinen" , "Greg Kroah-Hartman" , "Sasha Levin" +Message-ID: <20251230194904.2442970-2-sashal@kernel.org> + +From: "Jiri Slaby (SUSE)" + +[ Upstream commit 2b5eac0f8c6e79bc152c8804f9f88d16717013ab ] + +This code (tty_get -> vhangup -> tty_put) is repeated on few places. +Introduce a helper similar to tty_port_tty_hangup() (asynchronous) to +handle even vhangup (synchronous). + +And use it on those places. + +In fact, reuse the tty_port_tty_hangup()'s code and call tty_vhangup() +depending on a new bool parameter. + +Signed-off-by: "Jiri Slaby (SUSE)" +Cc: Karsten Keil +Cc: David Lin +Cc: Johan Hovold +Cc: Alex Elder +Cc: Oliver Neukum +Cc: Marcel Holtmann +Cc: Johan Hedberg +Cc: Luiz Augusto von Dentz +Reviewed-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20250611100319.186924-2-jirislaby@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 74098cc06e75 ("xhci: dbgtty: fix device unregister: fixup") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/isdn/capi/capi.c | 8 +------- + drivers/staging/greybus/uart.c | 7 +------ + drivers/tty/serial/serial_core.c | 7 +------ + drivers/tty/tty_port.c | 12 ++++++++---- + drivers/usb/class/cdc-acm.c | 7 +------ + drivers/usb/serial/usb-serial.c | 7 +------ + include/linux/tty_port.h | 12 +++++++++++- + net/bluetooth/rfcomm/tty.c | 7 +------ + 8 files changed, 25 insertions(+), 42 deletions(-) + +--- a/drivers/isdn/capi/capi.c ++++ b/drivers/isdn/capi/capi.c +@@ -304,15 +304,9 @@ static void capincci_alloc_minor(struct + static void capincci_free_minor(struct capincci *np) + { + struct capiminor *mp = np->minorp; +- struct tty_struct *tty; + + if (mp) { +- tty = tty_port_tty_get(&mp->port); +- if (tty) { +- tty_vhangup(tty); +- tty_kref_put(tty); +- } +- ++ tty_port_tty_vhangup(&mp->port); + capiminor_free(mp); + } + } +--- a/drivers/staging/greybus/uart.c ++++ b/drivers/staging/greybus/uart.c +@@ -915,7 +915,6 @@ static void gb_uart_remove(struct gbphy_ + { + struct gb_tty *gb_tty = gb_gbphy_get_data(gbphy_dev); + struct gb_connection *connection = gb_tty->connection; +- struct tty_struct *tty; + int ret; + + ret = gbphy_runtime_get_sync(gbphy_dev); +@@ -928,11 +927,7 @@ static void gb_uart_remove(struct gbphy_ + wake_up_all(&gb_tty->wioctl); + mutex_unlock(&gb_tty->mutex); + +- tty = tty_port_tty_get(&gb_tty->port); +- if (tty) { +- tty_vhangup(tty); +- tty_kref_put(tty); +- } ++ tty_port_tty_vhangup(&gb_tty->port); + + gb_connection_disable_rx(connection); + tty_unregister_device(gb_tty_driver, gb_tty->minor); +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -3191,7 +3191,6 @@ void uart_remove_one_port(struct uart_dr + struct uart_state *state = drv->state + uport->line; + struct tty_port *port = &state->port; + struct uart_port *uart_port; +- struct tty_struct *tty; + + mutex_lock(&port_mutex); + +@@ -3217,11 +3216,7 @@ void uart_remove_one_port(struct uart_dr + */ + tty_port_unregister_device(port, drv->tty_driver, uport->line); + +- tty = tty_port_tty_get(port); +- if (tty) { +- tty_vhangup(port->tty); +- tty_kref_put(tty); +- } ++ tty_port_tty_vhangup(port); + + /* + * If the port is used as a console, unregister it +--- a/drivers/tty/tty_port.c ++++ b/drivers/tty/tty_port.c +@@ -416,15 +416,19 @@ EXPORT_SYMBOL(tty_port_hangup); + * @port: tty port + * @check_clocal: hang only ttys with %CLOCAL unset? + */ +-void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) ++void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async) + { + struct tty_struct *tty = tty_port_tty_get(port); + +- if (tty && (!check_clocal || !C_CLOCAL(tty))) +- tty_hangup(tty); ++ if (tty && (!check_clocal || !C_CLOCAL(tty))) { ++ if (async) ++ tty_hangup(tty); ++ else ++ tty_vhangup(tty); ++ } + tty_kref_put(tty); + } +-EXPORT_SYMBOL_GPL(tty_port_tty_hangup); ++EXPORT_SYMBOL_GPL(__tty_port_tty_hangup); + + /** + * tty_port_tty_wakeup - helper to wake up a tty +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1548,7 +1548,6 @@ err_put_port: + static void acm_disconnect(struct usb_interface *intf) + { + struct acm *acm = usb_get_intfdata(intf); +- struct tty_struct *tty; + int i; + + /* sibling interface is already cleaning up */ +@@ -1575,11 +1574,7 @@ static void acm_disconnect(struct usb_in + usb_set_intfdata(acm->data, NULL); + mutex_unlock(&acm->mutex); + +- tty = tty_port_tty_get(&acm->port); +- if (tty) { +- tty_vhangup(tty); +- tty_kref_put(tty); +- } ++ tty_port_tty_vhangup(&acm->port); + + cancel_delayed_work_sync(&acm->dwork); + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -1179,7 +1179,6 @@ static void usb_serial_disconnect(struct + struct usb_serial *serial = usb_get_intfdata(interface); + struct device *dev = &interface->dev; + struct usb_serial_port *port; +- struct tty_struct *tty; + + /* sibling interface is cleaning up */ + if (!serial) +@@ -1194,11 +1193,7 @@ static void usb_serial_disconnect(struct + + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; +- tty = tty_port_tty_get(&port->port); +- if (tty) { +- tty_vhangup(tty); +- tty_kref_put(tty); +- } ++ tty_port_tty_vhangup(&port->port); + usb_serial_port_poison_urbs(port); + wake_up_interruptible(&port->port.delta_msr_wait); + cancel_work_sync(&port->work); +--- a/include/linux/tty_port.h ++++ b/include/linux/tty_port.h +@@ -234,7 +234,7 @@ int tty_port_carrier_raised(struct tty_p + void tty_port_raise_dtr_rts(struct tty_port *port); + void tty_port_lower_dtr_rts(struct tty_port *port); + void tty_port_hangup(struct tty_port *port); +-void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); ++void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async); + void tty_port_tty_wakeup(struct tty_port *port); + int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, + struct file *filp); +@@ -253,4 +253,14 @@ static inline int tty_port_users(struct + return port->count + port->blocked_open; + } + ++static inline void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) ++{ ++ __tty_port_tty_hangup(port, check_clocal, true); ++} ++ ++static inline void tty_port_tty_vhangup(struct tty_port *port) ++{ ++ __tty_port_tty_hangup(port, false, false); ++} ++ + #endif +--- a/net/bluetooth/rfcomm/tty.c ++++ b/net/bluetooth/rfcomm/tty.c +@@ -438,7 +438,6 @@ static int __rfcomm_release_dev(void __u + { + struct rfcomm_dev_req req; + struct rfcomm_dev *dev; +- struct tty_struct *tty; + + if (copy_from_user(&req, arg, sizeof(req))) + return -EFAULT; +@@ -464,11 +463,7 @@ static int __rfcomm_release_dev(void __u + rfcomm_dlc_close(dev->dlc, 0); + + /* Shut down TTY synchronously before freeing rfcomm_dev */ +- tty = tty_port_tty_get(&dev->port); +- if (tty) { +- tty_vhangup(tty); +- tty_kref_put(tty); +- } ++ tty_port_tty_vhangup(&dev->port); + + if (!test_bit(RFCOMM_TTY_OWNED, &dev->status)) + tty_port_put(&dev->port); diff --git a/queue-6.1/usb-dwc3-keep-susphy-enabled-during-exit-to-avoid-controller-faults.patch b/queue-6.1/usb-dwc3-keep-susphy-enabled-during-exit-to-avoid-controller-faults.patch new file mode 100644 index 0000000000..89751d6230 --- /dev/null +++ b/queue-6.1/usb-dwc3-keep-susphy-enabled-during-exit-to-avoid-controller-faults.patch @@ -0,0 +1,58 @@ +From sashal@kernel.org Tue Dec 30 15:54:25 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 09:54:19 -0500 +Subject: usb: dwc3: keep susphy enabled during exit to avoid controller faults +To: stable@vger.kernel.org +Cc: Udipto Goswami , stable , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20251230145419.2259989-1-sashal@kernel.org> + +From: Udipto Goswami + +[ Upstream commit e1003aa7ec9eccdde4c926bd64ef42816ad55f25 ] + +On some platforms, switching USB roles from host to device can trigger +controller faults due to premature PHY power-down. This occurs when the +PHY is disabled too early during teardown, causing synchronization +issues between the PHY and controller. + +Keep susphy enabled during dwc3_host_exit() and dwc3_gadget_exit() +ensures the PHY remains in a low-power state capable of handling +required commands during role switch. + +Cc: stable +Fixes: 6d735722063a ("usb: dwc3: core: Prevent phy suspend during init") +Suggested-by: Thinh Nguyen +Signed-off-by: Udipto Goswami +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20251126054221.120638-1-udipto.goswami@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/gadget.c | 2 +- + drivers/usb/dwc3/host.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -4646,7 +4646,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) + if (!dwc->gadget) + return; + +- dwc3_enable_susphy(dwc, false); ++ dwc3_enable_susphy(dwc, true); + usb_del_gadget(dwc->gadget); + dwc3_gadget_free_endpoints(dwc); + usb_put_gadget(dwc->gadget); +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -162,7 +162,7 @@ err: + + void dwc3_host_exit(struct dwc3 *dwc) + { +- dwc3_enable_susphy(dwc, false); ++ dwc3_enable_susphy(dwc, true); + platform_device_unregister(dwc->xhci); + dwc->xhci = NULL; + } diff --git a/queue-6.1/usb-ohci-nxp-fix-device-leak-on-probe-failure.patch b/queue-6.1/usb-ohci-nxp-fix-device-leak-on-probe-failure.patch new file mode 100644 index 0000000000..6bb0fec6bd --- /dev/null +++ b/queue-6.1/usb-ohci-nxp-fix-device-leak-on-probe-failure.patch @@ -0,0 +1,49 @@ +From stable+bounces-204213-greg=kroah.com@vger.kernel.org Tue Dec 30 14:26:44 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 08:26:34 -0500 +Subject: usb: ohci-nxp: fix device leak on probe failure +To: stable@vger.kernel.org +Cc: Johan Hovold , Ma Ke , Alan Stern , Vladimir Zapolskiy , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20251230132634.2198371-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit b4c61e542faf8c9131d69ecfc3ad6de96d1b2ab8 ] + +Make sure to drop the reference taken when looking up the PHY I2C device +during probe on probe failure (e.g. probe deferral) and on driver +unbind. + +Fixes: 73108aa90cbf ("USB: ohci-nxp: Use isp1301 driver") +Cc: stable@vger.kernel.org # 3.5 +Reported-by: Ma Ke +Link: https://lore.kernel.org/lkml/20251117013428.21840-1-make24@iscas.ac.cn/ +Signed-off-by: Johan Hovold +Acked-by: Alan Stern +Reviewed-by: Vladimir Zapolskiy +Link: https://patch.msgid.link/20251218153519.19453-4-johan@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/ohci-nxp.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/host/ohci-nxp.c ++++ b/drivers/usb/host/ohci-nxp.c +@@ -224,6 +224,7 @@ static int ohci_hcd_nxp_probe(struct pla + fail_resource: + usb_put_hcd(hcd); + fail_disable: ++ put_device(&isp1301_i2c_client->dev); + isp1301_i2c_client = NULL; + return ret; + } +@@ -235,6 +236,7 @@ static int ohci_hcd_nxp_remove(struct pl + usb_remove_hcd(hcd); + ohci_nxp_stop_hc(); + usb_put_hcd(hcd); ++ put_device(&isp1301_i2c_client->dev); + isp1301_i2c_client = NULL; + + return 0; diff --git a/queue-6.1/usb-ohci-nxp-use-helper-function-devm_clk_get_enabled.patch b/queue-6.1/usb-ohci-nxp-use-helper-function-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..b5698a111f --- /dev/null +++ b/queue-6.1/usb-ohci-nxp-use-helper-function-devm_clk_get_enabled.patch @@ -0,0 +1,93 @@ +From stable+bounces-204212-greg=kroah.com@vger.kernel.org Tue Dec 30 14:26:44 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 08:26:33 -0500 +Subject: usb: ohci-nxp: Use helper function devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Zhang Zekun , Alan Stern , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20251230132634.2198371-1-sashal@kernel.org> + +From: Zhang Zekun + +[ Upstream commit c146ede472717f352b7283a525bd9a1a2b15e2cf ] + +devm_clk_get() and clk_prepare_enable() can be replaced by helper +function devm_clk_get_enabled(). Let's use devm_clk_get_enabled() to +simplify code and avoid calling clk_disable_unprepare(). + +Signed-off-by: Zhang Zekun +Acked-by: Alan Stern +Link: https://lore.kernel.org/r/20240902123020.29267-3-zhangzekun11@huawei.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: b4c61e542faf ("usb: ohci-nxp: fix device leak on probe failure") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/ohci-nxp.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +--- a/drivers/usb/host/ohci-nxp.c ++++ b/drivers/usb/host/ohci-nxp.c +@@ -51,8 +51,6 @@ static struct hc_driver __read_mostly oh + + static struct i2c_client *isp1301_i2c_client; + +-static struct clk *usb_host_clk; +- + static void isp1301_configure_lpc32xx(void) + { + /* LPC32XX only supports DAT_SE0 USB mode */ +@@ -155,6 +153,7 @@ static int ohci_hcd_nxp_probe(struct pla + struct resource *res; + int ret = 0, irq; + struct device_node *isp1301_node; ++ struct clk *usb_host_clk; + + if (pdev->dev.of_node) { + isp1301_node = of_parse_phandle(pdev->dev.of_node, +@@ -180,26 +179,20 @@ static int ohci_hcd_nxp_probe(struct pla + } + + /* Enable USB host clock */ +- usb_host_clk = devm_clk_get(&pdev->dev, NULL); ++ usb_host_clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(usb_host_clk)) { +- dev_err(&pdev->dev, "failed to acquire USB OHCI clock\n"); ++ dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n"); + ret = PTR_ERR(usb_host_clk); + goto fail_disable; + } + +- ret = clk_prepare_enable(usb_host_clk); +- if (ret < 0) { +- dev_err(&pdev->dev, "failed to start USB OHCI clock\n"); +- goto fail_disable; +- } +- + isp1301_configure(); + + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); + ret = -ENOMEM; +- goto fail_hcd; ++ goto fail_disable; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -230,8 +223,6 @@ static int ohci_hcd_nxp_probe(struct pla + ohci_nxp_stop_hc(); + fail_resource: + usb_put_hcd(hcd); +-fail_hcd: +- clk_disable_unprepare(usb_host_clk); + fail_disable: + isp1301_i2c_client = NULL; + return ret; +@@ -244,7 +235,6 @@ static int ohci_hcd_nxp_remove(struct pl + usb_remove_hcd(hcd); + ohci_nxp_stop_hc(); + usb_put_hcd(hcd); +- clk_disable_unprepare(usb_host_clk); + isp1301_i2c_client = NULL; + + return 0; diff --git a/queue-6.1/virtio_console-fix-order-of-fields-cols-and-rows.patch b/queue-6.1/virtio_console-fix-order-of-fields-cols-and-rows.patch new file mode 100644 index 0000000000..e0738c2580 --- /dev/null +++ b/queue-6.1/virtio_console-fix-order-of-fields-cols-and-rows.patch @@ -0,0 +1,36 @@ +From 5326ab737a47278dbd16ed3ee7380b26c7056ddd Mon Sep 17 00:00:00 2001 +From: Maximilian Immanuel Brandtner +Date: Mon, 24 Mar 2025 15:42:46 +0100 +Subject: virtio_console: fix order of fields cols and rows + +From: Maximilian Immanuel Brandtner + +commit 5326ab737a47278dbd16ed3ee7380b26c7056ddd upstream. + +According to section 5.3.6.2 (Multiport Device Operation) of the virtio +spec(version 1.2) a control buffer with the event VIRTIO_CONSOLE_RESIZE +is followed by a virtio_console_resize struct containing cols then rows. +The kernel implements this the wrong way around (rows then cols) resulting +in the two values being swapped. + +Signed-off-by: Maximilian Immanuel Brandtner +Message-Id: <20250324144300.905535-1-maxbr@linux.ibm.com> +Signed-off-by: Michael S. Tsirkin +Cc: Filip Hejsek +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/virtio_console.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1615,8 +1615,8 @@ static void handle_control_message(struc + break; + case VIRTIO_CONSOLE_RESIZE: { + struct { +- __virtio16 rows; + __virtio16 cols; ++ __virtio16 rows; + } size; + + if (!is_console_port(port)) diff --git a/queue-6.1/wifi-mac80211-discard-beacon-frames-to-non-broadcast-address.patch b/queue-6.1/wifi-mac80211-discard-beacon-frames-to-non-broadcast-address.patch new file mode 100644 index 0000000000..8850d06459 --- /dev/null +++ b/queue-6.1/wifi-mac80211-discard-beacon-frames-to-non-broadcast-address.patch @@ -0,0 +1,62 @@ +From stable+bounces-206080-greg=kroah.com@vger.kernel.org Wed Jan 7 03:37:44 2026 +From: Sasha Levin +Date: Tue, 6 Jan 2026 21:34:39 -0500 +Subject: wifi: mac80211: Discard Beacon frames to non-broadcast address +To: stable@vger.kernel.org +Cc: Jouni Malinen , Johannes Berg , Sasha Levin +Message-ID: <20260107023440.3510800-1-sashal@kernel.org> + +From: Jouni Malinen + +[ Upstream commit 193d18f60588e95d62e0f82b6a53893e5f2f19f8 ] + +Beacon frames are required to be sent to the broadcast address, see IEEE +Std 802.11-2020, 11.1.3.1 ("The Address 1 field of the Beacon .. frame +shall be set to the broadcast address"). A unicast Beacon frame might be +used as a targeted attack to get one of the associated STAs to do +something (e.g., using CSA to move it to another channel). As such, it +is better have strict filtering for this on the received side and +discard all Beacon frames that are sent to an unexpected address. + +This is even more important for cases where beacon protection is used. +The current implementation in mac80211 is correctly discarding unicast +Beacon frames if the Protected Frame bit in the Frame Control field is +set to 0. However, if that bit is set to 1, the logic used for checking +for configured BIGTK(s) does not actually work. If the driver does not +have logic for dropping unicast Beacon frames with Protected Frame bit +1, these frames would be accepted in mac80211 processing as valid Beacon +frames even though they are not protected. This would allow beacon +protection to be bypassed. While the logic for checking beacon +protection could be extended to cover this corner case, a more generic +check for discard all Beacon frames based on A1=unicast address covers +this without needing additional changes. + +Address all these issues by dropping received Beacon frames if they are +sent to a non-broadcast address. + +Cc: stable@vger.kernel.org +Fixes: af2d14b01c32 ("mac80211: Beacon protection using the new BIGTK (STA)") +Signed-off-by: Jouni Malinen +Link: https://patch.msgid.link/20251215151134.104501-1-jouni.malinen@oss.qualcomm.com +Signed-off-by: Johannes Berg +[ adapted RX_DROP return value to RX_DROP_MONITOR ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/mac80211/rx.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3299,6 +3299,11 @@ ieee80211_rx_h_mgmt_check(struct ieee802 + if (!ieee80211_is_mgmt(mgmt->frame_control)) + return RX_DROP_MONITOR; + ++ /* Drop non-broadcast Beacon frames */ ++ if (ieee80211_is_beacon(mgmt->frame_control) && ++ !is_broadcast_ether_addr(mgmt->da)) ++ return RX_DROP_MONITOR; ++ + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && + ieee80211_is_beacon(mgmt->frame_control) && + !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { diff --git a/queue-6.1/wifi-mt76-fix-dts-power-limits-on-little-endian-systems.patch b/queue-6.1/wifi-mt76-fix-dts-power-limits-on-little-endian-systems.patch new file mode 100644 index 0000000000..5f3585678b --- /dev/null +++ b/queue-6.1/wifi-mt76-fix-dts-power-limits-on-little-endian-systems.patch @@ -0,0 +1,139 @@ +From stable+bounces-204137-greg=kroah.com@vger.kernel.org Mon Dec 29 22:13:38 2025 +From: Sasha Levin +Date: Mon, 29 Dec 2025 16:13:28 -0500 +Subject: wifi: mt76: Fix DTS power-limits on little endian systems +To: stable@vger.kernel.org +Cc: "Sven Eckelmann (Plasma Cloud)" , Felix Fietkau , Sasha Levin +Message-ID: <20251229211328.1711248-1-sashal@kernel.org> + +From: "Sven Eckelmann (Plasma Cloud)" + +[ Upstream commit 38b845e1f9e810869b0a0b69f202b877b7b7fb12 ] + +The power-limits for ru and mcs and stored in the devicetree as bytewise +array (often with sizes which are not a multiple of 4). These arrays have a +prefix which defines for how many modes a line is applied. This prefix is +also only a byte - but the code still tried to fix the endianness of this +byte with a be32 operation. As result, loading was mostly failing or was +sending completely unexpected values to the firmware. + +Since the other rates are also stored in the devicetree as bytewise arrays, +just drop the u32 access + be32_to_cpu conversion and directly access them +as bytes arrays. + +Cc: stable@vger.kernel.org +Fixes: 22b980badc0f ("mt76: add functions for parsing rate power limits from DT") +Fixes: a9627d992b5e ("mt76: extend DT rate power limits to support 11ax devices") +Signed-off-by: Sven Eckelmann (Plasma Cloud) +Signed-off-by: Felix Fietkau +[ Adjust context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/eeprom.c | 37 ++++++++++++++++++---------- + 1 file changed, 24 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/eeprom.c ++++ b/drivers/net/wireless/mediatek/mt76/eeprom.c +@@ -189,6 +189,19 @@ mt76_get_of_array(struct device_node *np + return prop->value; + } + ++static const s8 * ++mt76_get_of_array_s8(struct device_node *np, char *name, size_t *len, int min) ++{ ++ struct property *prop = of_find_property(np, name, NULL); ++ ++ if (!prop || !prop->value || prop->length < min) ++ return NULL; ++ ++ *len = prop->length; ++ ++ return prop->value; ++} ++ + static struct device_node * + mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) + { +@@ -228,7 +241,7 @@ mt76_get_txs_delta(struct device_node *n + } + + static void +-mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data, ++mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, + s8 target_power, s8 nss_delta, s8 *max_power) + { + int i; +@@ -237,15 +250,14 @@ mt76_apply_array_limit(s8 *pwr, size_t p + return; + + for (i = 0; i < pwr_len; i++) { +- pwr[i] = min_t(s8, target_power, +- be32_to_cpu(data[i]) + nss_delta); ++ pwr[i] = min_t(s8, target_power, data[i] + nss_delta); + *max_power = max(*max_power, pwr[i]); + } + } + + static void + mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, +- const __be32 *data, size_t len, s8 target_power, ++ const s8 *data, size_t len, s8 target_power, + s8 nss_delta, s8 *max_power) + { + int i, cur; +@@ -253,8 +265,7 @@ mt76_apply_multi_array_limit(s8 *pwr, si + if (!data) + return; + +- len /= 4; +- cur = be32_to_cpu(data[0]); ++ cur = data[0]; + for (i = 0; i < pwr_num; i++) { + if (len < pwr_len + 1) + break; +@@ -269,7 +280,7 @@ mt76_apply_multi_array_limit(s8 *pwr, si + if (!len) + break; + +- cur = be32_to_cpu(data[0]); ++ cur = data[0]; + } + } + +@@ -280,7 +291,7 @@ s8 mt76_get_rate_power_limits(struct mt7 + { + struct mt76_dev *dev = phy->dev; + struct device_node *np; +- const __be32 *val; ++ const s8 *val; + char name[16]; + u32 mcs_rates = dev->drv->mcs_rates; + u32 ru_rates = ARRAY_SIZE(dest->ru[0]); +@@ -326,21 +337,21 @@ s8 mt76_get_rate_power_limits(struct mt7 + + txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask)); + +- val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); ++ val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); + mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, + target_power, txs_delta, &max_power); + +- val = mt76_get_of_array(np, "rates-ofdm", +- &len, ARRAY_SIZE(dest->ofdm)); ++ val = mt76_get_of_array_s8(np, "rates-ofdm", ++ &len, ARRAY_SIZE(dest->ofdm)); + mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, + target_power, txs_delta, &max_power); + +- val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1); ++ val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); + mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), + ARRAY_SIZE(dest->mcs), val, len, + target_power, txs_delta, &max_power); + +- val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1); ++ val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1); + mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), + ARRAY_SIZE(dest->ru), val, len, + target_power, txs_delta, &max_power); diff --git a/queue-6.1/xhci-dbgtty-fix-device-unregister-fixup.patch b/queue-6.1/xhci-dbgtty-fix-device-unregister-fixup.patch new file mode 100644 index 0000000000..1c1ade62fb --- /dev/null +++ b/queue-6.1/xhci-dbgtty-fix-device-unregister-fixup.patch @@ -0,0 +1,40 @@ +From stable+bounces-204283-greg=kroah.com@vger.kernel.org Tue Dec 30 20:49:13 2025 +From: Sasha Levin +Date: Tue, 30 Dec 2025 14:49:04 -0500 +Subject: xhci: dbgtty: fix device unregister: fixup +To: stable@vger.kernel.org +Cc: "Łukasz Bartosik" , stable , "Greg Kroah-Hartman" , "Sasha Levin" +Message-ID: <20251230194904.2442970-3-sashal@kernel.org> + +From: Łukasz Bartosik + +[ Upstream commit 74098cc06e753d3ffd8398b040a3a1dfb65260c0 ] + +This fixup replaces tty_vhangup() call with call to +tty_port_tty_vhangup(). Both calls hangup tty device +synchronously however tty_port_tty_vhangup() increases +reference count during the hangup operation using +scoped_guard(tty_port_tty). + +Cc: stable +Fixes: 1f73b8b56cf3 ("xhci: dbgtty: fix device unregister") +Signed-off-by: Łukasz Bartosik +Link: https://patch.msgid.link/20251127111644.3161386-1-ukaszb@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-dbgtty.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-dbgtty.c ++++ b/drivers/usb/host/xhci-dbgtty.c +@@ -523,7 +523,7 @@ static void xhci_dbc_tty_unregister_devi + * Hang up the TTY. This wakes up any blocked + * writers and causes subsequent writes to fail. + */ +- tty_vhangup(port->port.tty); ++ tty_port_tty_vhangup(&port->port); + + tty_unregister_device(dbc_tty_driver, port->minor); + xhci_dbc_tty_exit_port(port);