From: Sasha Levin Date: Sat, 23 May 2026 14:09:26 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v5.10.258~65 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=949955bf8fa950e42a58b498b24f3850e225de03;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-5.10/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..01dee0fba6 --- /dev/null +++ b/queue-5.10/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From f4f12960df81a489d5206a597af87bc716b293c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index cf824841ffead..6781d6f44e4d3 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1085,6 +1085,8 @@ static int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-5.10/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-5.10/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..ca982a6b4b --- /dev/null +++ b/queue-5.10/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From 7761749577ba2cff6c8ee0a813a485dd68cefbed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 6781d6f44e4d3..ea0fecd2bf65f 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1285,16 +1285,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-5.10/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-5.10/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..4379d471b9 --- /dev/null +++ b/queue-5.10/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From 7093838a7c3719a6591863f3ffa34822b24fe0fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index b2bf7016e1b34..287f674b7af17 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -85,6 +85,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-5.10/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-5.10/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..fe682337dd --- /dev/null +++ b/queue-5.10/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 7934cd7a57483f1b8b871c5fc8ad715ba66b87c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 12028b3e2eee4..65cb8e3f74eed 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -1020,10 +1020,12 @@ static int onyx_i2c_probe(struct i2c_client *client, + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-5.10/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-5.10/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..382aff11f5 --- /dev/null +++ b/queue-5.10/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From f8a1ffed05e824bc3eb1277cda3e626a63fdbad7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index d3e37577b5299..4fa4e8dd43555 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -909,6 +909,7 @@ static int tas_i2c_probe(struct i2c_client *client, + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-5.10/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-5.10/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..9aa5f5a6a2 --- /dev/null +++ b/queue-5.10/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 81d36e2f6977057cc17a597567c1ed901230eb86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 222ea652edf37..318717784659c 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -161,6 +161,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %d total %d bytes\n", + tstamp->byte_offset, tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-5.10/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-5.10/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..91e0ca9d23 --- /dev/null +++ b/queue-5.10/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From 5397666681b1631688171a05669328955fe27606 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c +index 0ebf4d9078522..3ff1603fd7d88 100644 +--- a/sound/hda/hdmi_chmap.c ++++ b/sound/hda/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-5.10/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-5.10/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..fae5743058 --- /dev/null +++ b/queue-5.10/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From 6f7a1be43e08c98b822f0f92545a6b85917c6a86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 7f64199139d31..4157cdafb0195 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1192,6 +1192,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-5.10/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-5.10/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..41b15bc543 --- /dev/null +++ b/queue-5.10/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From 2d686b265f6fc36a3d29da710e024cbf68680ada Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index 518c7557f78a2..848a6bd004744 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -205,8 +205,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -215,9 +216,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-5.10/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-5.10/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..9b31330d0a --- /dev/null +++ b/queue-5.10/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From dad0704605ba81b77e7c4616d73a3aa261d63b86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index 1be82113c59ae..87f19d40f9084 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -527,9 +527,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-5.10/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-5.10/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..6b0a673554 --- /dev/null +++ b/queue-5.10/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 4b4102c2cdf6fb0f975e33e1c393df923b93f938 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index 381b525db2b14..4d4208098f112 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -253,6 +253,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + } + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-5.10/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-5.10/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..6aacd33e54 --- /dev/null +++ b/queue-5.10/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 27d3c8e1356288f6135bcd389d1c436456c40495 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index f5bcf68841c39..361377561dbb3 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -213,6 +213,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + } + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-5.10/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-5.10/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..8d20efc8ec --- /dev/null +++ b/queue-5.10/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From 9fa662aa13efe38137db786323a15b80df7b6528 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index 8442be93eb1c6..f595e717496ea 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -75,6 +75,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -83,6 +85,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-5.10/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-5.10/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..0033a36378 --- /dev/null +++ b/queue-5.10/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From 81708644478d490619c985a64f55f8bb8b5e6014 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index c12966025cfae..02f2fe96696bd 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1841,6 +1841,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src) + return 0; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + reg_val |= RT5640_SCLK_SRC_MCLK; +-- +2.53.0 + diff --git a/queue-5.10/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-5.10/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..f26c969cc8 --- /dev/null +++ b/queue-5.10/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From a3f1343123c6b0e3d8d823b7d67b93cfa4461fad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index f045876c12f17..9dd0dc77597d7 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -492,7 +492,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -501,7 +501,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -590,7 +590,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_get_sync(component->dev); + if (ret < 0) { +@@ -615,7 +615,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -628,7 +628,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-5.10/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-5.10/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..1e312ef346 --- /dev/null +++ b/queue-5.10/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From cbdf42f271884a1c05860cfadee3dd2e1151e952 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index 61ea444f2018d..b6f6954bc9953 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2468,6 +2468,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-5.10/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-5.10/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..f91374044e --- /dev/null +++ b/queue-5.10/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From 123a297319f66aff85a8a92c684fa082c39e6f36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index e700024a8b482..2580fcc450190 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2790,7 +2790,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-5.10/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..4e69a445c3 --- /dev/null +++ b/queue-5.10/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From 2ee5ed6d5c5b79bd25f5ed62518772f062b4f429 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 636db3b7e470b..64e0537b83a9e 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -441,6 +441,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-5.10/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..726308e943 --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From dde77f9ac05ed0375fe1edbc8a001b2eff172f33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 45e1e8192e3b6..5ae47e8493582 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7665,6 +7665,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); + +-- +2.53.0 + diff --git a/queue-5.10/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-5.10/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..843c5a2a07 --- /dev/null +++ b/queue-5.10/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From d1bce87bf3c060561e778dc334fb931a5309c859 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index db613a97ee5f9..8813f1691eca7 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1581,12 +1581,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) + if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-5.10/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-5.10/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..c1223c70b0 --- /dev/null +++ b/queue-5.10/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 72413c46c82b945441daed14b89102eeb9eba3fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index 69ab10c9237fc..0c424cb16081f 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -322,10 +322,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + return avail; +-- +2.53.0 + diff --git a/queue-5.10/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-5.10/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..1f779ad1e2 --- /dev/null +++ b/queue-5.10/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From c1cf1dd1e7f98cc152e8c21a4c29c9cd6a575e18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 6cf2f7bb30c27..514f52bf7346a 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -248,7 +248,11 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -393,7 +397,11 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1378,7 +1386,11 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-5.10/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-5.10/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..53bb0cd51f --- /dev/null +++ b/queue-5.10/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 6da9710d9e79792d5b13faedbc5a9a8a0b71c803 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index c4e3c1a5de059..9a969c67b0cba 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -2413,7 +2413,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-5.10/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-5.10/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..957e1cd8ce --- /dev/null +++ b/queue-5.10/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From 6097e3a6bd8d5d9c5ec11ed16d230b5ef2e8860f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index eb4fd803bae0d..a3dad7ed78d66 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -643,6 +643,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-5.10/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-5.10/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..2a7a363f62 --- /dev/null +++ b/queue-5.10/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From 97dfc8ab8c80d483bb1b4436e01ad36b8319bb78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index fed1941696668..839bf73d3f2f6 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -341,13 +341,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-5.10/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-5.10/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..fdd10266df --- /dev/null +++ b/queue-5.10/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 2e3a0ed998f225e6e39458100c4e57c2ee3ff356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index 7972d2784b3b5..77bf5d4df963e 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -3025,6 +3025,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-5.10/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..a2088544ef --- /dev/null +++ b/queue-5.10/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From f41151a0c5375a8b0803eb3eccccdca9b6567ae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 43d271c358858..b6458cebc4d34 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1851,3 +1851,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 79747130a48f7..ecb00465f1f5a 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -143,6 +143,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 770bccd1fbb98..4b2204fe291c6 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2997,6 +2997,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -3013,6 +3016,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3568,7 +3585,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-5.10/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..4f54e2cf17 --- /dev/null +++ b/queue-5.10/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From 62aaf89c2c036e7c16ce5b66adbd30783eebd4e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index d37ee8277480d..a01b67bf454f0 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1929,7 +1929,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-5.10/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-5.10/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..65a7b22646 --- /dev/null +++ b/queue-5.10/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 48d4be7b1d150f07b43d7df213533c53ea401423 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index addeda42339fa..ec97adeceb6a6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1606,6 +1606,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = kmalloc_array(fence_count, sizeof(struct drm_amdgpu_fence), + GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-5.10/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-5.10/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..3f574cb11f --- /dev/null +++ b/queue-5.10/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From 97d5f6724e19228ec213af0ce7978d1142439fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 3fa22af13f745..bbf3722576663 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -590,6 +590,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -649,6 +664,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -694,30 +711,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-5.10/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-5.10/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..5c5ac92318 --- /dev/null +++ b/queue-5.10/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 67878e19c723c2aba48e13c17de9998e475ee06e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index e9bf3054529f1..5ee19665ef939 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - const: marvell,armada7040 +-- +2.53.0 + diff --git a/queue-5.10/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-5.10/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..8924601a81 --- /dev/null +++ b/queue-5.10/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From 60e879c4e91d3cbea33d94cb2af7cd1f7103609e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index b2f6a1937d239..19dbe9d1187e1 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -567,6 +567,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-5.10/enic-add-v2-sr-iov-vf-device-id.patch b/queue-5.10/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..f64b07582c --- /dev/null +++ b/queue-5.10/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,54 @@ +From ae1764dd4659dec7f52d9b174a03904cd343bc32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index f59d658d624f5..ceb82cdd23ab2 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,6 +66,7 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + #define RX_COPYBREAK_DEFAULT 256 + +@@ -74,6 +75,7 @@ static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -309,7 +311,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-5.10/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-5.10/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..13d4b4449f --- /dev/null +++ b/queue-5.10/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From e2e18074aa28448a7bad60bc5905b08153fd52a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-5.10/exfat-fix-bitwise-operation-having-different-size.patch b/queue-5.10/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..75c80e8a1a --- /dev/null +++ b/queue-5.10/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 429d2fd30db196d414a88766d3fcfa3f2ff92618 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 2c2ac7fca3270..05d3c72b1dace 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -263,7 +263,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-5.10/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-5.10/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..e87b6b33a7 --- /dev/null +++ b/queue-5.10/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From 7aff74e2dd93b52f1fbe7c9a98ec06cf3b9283ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index 4bd73820a4ac0..09eefde4f4689 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -638,7 +638,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-5.10/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-5.10/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..f6f6d006be --- /dev/null +++ b/queue-5.10/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From 27691d11c6cfc5827945f569ff2855b4bd82f61c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index bb2860c09a587..145b2fee63e08 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -634,7 +634,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-5.10/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-5.10/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..b4baa1dcee --- /dev/null +++ b/queue-5.10/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From d5102376b07e005566ab020936423d157d4f7a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index dfa99cd195b83..da3421ab15110 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -744,6 +744,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-5.10/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-5.10/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..8e324fb86e --- /dev/null +++ b/queue-5.10/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From e7b5395e16d277b37faba7d2d61e460ebe101d2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index a3decc7fadde3..7cdc2a894dc6f 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1119,7 +1119,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-5.10/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-5.10/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..6c6d7b099a --- /dev/null +++ b/queue-5.10/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From d9265c1e4be9e3a43284acc45a748fc90ece90a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index 224d7c8146a94..930dd4c2649b2 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2317,6 +2317,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-5.10/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-5.10/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..a3b2417d48 --- /dev/null +++ b/queue-5.10/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From d54e40c4da53bd14e010c80e44730f3ae97a89e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index 4a869402d120d..2abb839bb1bf2 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -956,6 +956,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-5.10/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-5.10/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..f7e52b97f4 --- /dev/null +++ b/queue-5.10/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From d0b02a81b7883b8456f13a3542cd86fdbfd88e8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 442bdc6e8dc4f..2917c12c1890b 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3193,7 +3193,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-5.10/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-5.10/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..11adc849df --- /dev/null +++ b/queue-5.10/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 52d7fa44b809e9a2bb57a78ff50f7dcde1e68edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 93b6bbf01d715..02ef2ebcdcb58 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -343,7 +343,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-5.10/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-5.10/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..4e57813bce --- /dev/null +++ b/queue-5.10/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From c52d7c1d605065aedb5c4325a1f8ae2e27dbc96f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index c0abc9c6851b6..75d14a779a410 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -77,7 +77,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-5.10/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-5.10/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..ff8d153957 --- /dev/null +++ b/queue-5.10/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 3b5cde1e0e54212bf02ce1952cb39b5337c8e903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index 6ad0c37b862eb..17224b10bc4ec 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-5.10/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-5.10/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..c1679e8fe7 --- /dev/null +++ b/queue-5.10/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 74d9d5529c2c918a476879369c1c262f3e679a7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 70fad87ff2db7..41aea180ae2e3 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -63,7 +63,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-5.10/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-5.10/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..441de1a24f --- /dev/null +++ b/queue-5.10/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From e2d6ceba7ec361d32c1d7e489d58cc495260086a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 1e9d8262d0ffc..1157417a8b330 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -52,7 +52,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, +-- +2.53.0 + diff --git a/queue-5.10/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-5.10/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..60fc5836f2 --- /dev/null +++ b/queue-5.10/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From e6bd23563beef16985087a22640a2528437c721f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index c301c1d56dd28..be91d6c744e58 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -283,7 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-5.10/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-5.10/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..3fe134aaaf --- /dev/null +++ b/queue-5.10/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From 523265989f9e4afbcfe4b7fdeee3931e596f56d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-5.10/hfsplus-fix-generic-642-failure.patch b/queue-5.10/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..f17b6b3735 --- /dev/null +++ b/queue-5.10/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From 9aaff3bb569b7334d2bf83582076673dcc418ea0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 1918544a78716..b26cd7504e113 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-5.10/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-5.10/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..d6b0fa4e0b --- /dev/null +++ b/queue-5.10/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From efc5de99668aed19086a6c2c309c10a7619d9817 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 84a9c9e761bcd..3a7b231759098 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -222,7 +222,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-5.10/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-5.10/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..5b8186eb44 --- /dev/null +++ b/queue-5.10/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 3a8e0888d17a259aa67736bd0bf04fe7fd1624c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index 1e8f71ffc8ce7..7fff700eab2b1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -438,14 +438,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + enum ice_status ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-5.10/iio-abi-fix-current_trigger-description.patch b/queue-5.10/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..1e412222e8 --- /dev/null +++ b/queue-5.10/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From 3e1da62521eb57f1736cf941fa2f4fc3dde71d42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index 53f07fc41b966..038a601b54053 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1113,7 +1113,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/buffer/length + KernelVersion: 2.6.35 +-- +2.53.0 + diff --git a/queue-5.10/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-5.10/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..f6541ce542 --- /dev/null +++ b/queue-5.10/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From 89947af6c12d383dc8eec95fda6acd782f6113a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index dda90c77f8984..be99e51f5c60c 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -60,6 +60,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -456,11 +458,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-5.10/irqchip-ath79-cpu-remove-unused-function.patch b/queue-5.10/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..f4fa0ac2f4 --- /dev/null +++ b/queue-5.10/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From b452870e6948fe13f1cae91e71a220f787d851ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-5.10/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-5.10/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..37aa264ab4 --- /dev/null +++ b/queue-5.10/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From 6e5f8571ced823c692c3b8b41e3d864a64c83abf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index f34025cc9b057..5ad993d4a6abe 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1440,7 +1527,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1770,7 +1857,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2553,7 +2640,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3518,6 +3605,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3535,6 +3627,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3548,6 +3644,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3567,6 +3667,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3582,6 +3686,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-5.10/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-5.10/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..e875c45e6c --- /dev/null +++ b/queue-5.10/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From baae24182308dcbf5cdc563a8d4f504002551bd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 55702b31ab3c4..b8701c32ba4ed 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -376,11 +376,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-5.10/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-5.10/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..fcc7db059d --- /dev/null +++ b/queue-5.10/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 872ea4d4506de182d7469aab1184945aaef5adbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 176580f54af96..076c665231a4a 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -181,6 +181,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -293,7 +294,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index 97a2eb0f0b75d..ae99b4c16dada 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-5.10/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-5.10/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..ec3a795f15 --- /dev/null +++ b/queue-5.10/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From b37d3d3b43683161ee329b8377ff3fa58687d107 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index d02bca48bc7b0..3525b5a485f32 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 7fd125c8dd192..635615139d036 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 3e8b13e6aa01f..09cf081e985f4 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -97,6 +104,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-5.10/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-5.10/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..2e569f918b --- /dev/null +++ b/queue-5.10/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 7d7789ba0c26e91f29ab20ce5d1dd3b63d84fcc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 3525b5a485f32..978d82ced83fc 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2189,8 +2189,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2205,12 +2203,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2234,8 +2230,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2287,8 +2282,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2299,6 +2292,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2311,9 +2305,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-5.10/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-5.10/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..13b74507a4 --- /dev/null +++ b/queue-5.10/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From 96263c441963ce2343409fb0caebb732debf2b97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 00909e6a24438..9eb78ea5e90fc 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -15,8 +15,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-5.10/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-5.10/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..58bee8dd48 --- /dev/null +++ b/queue-5.10/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 87d103102eaa2d763eda1516acc01202b76717e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 9eb78ea5e90fc..48d4a2d95fd80 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,6 +16,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-5.10/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-5.10/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..b972ab2920 --- /dev/null +++ b/queue-5.10/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 19228c7290efccb1413b60f6db9cb0c8968e8016 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 94abf3d8afc52..f9cb5d5fd78f7 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -22,6 +22,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -77,9 +84,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -103,16 +109,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-5.10/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-5.10/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..0526562736 --- /dev/null +++ b/queue-5.10/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From a7f28c78fc469b108c50f5ce6f71b07331e83cf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 637acb8ef60d3..6d75351eb33d6 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3889,6 +3889,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-5.10/media-au0828-fix-green-screen-in-analog.patch b/queue-5.10/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..e1a5d01881 --- /dev/null +++ b/queue-5.10/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From dea482300201a7bc9c5c6c17688045877d7e775c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index aa5bc6a2ae20e..b272049c82fab 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1676,6 +1676,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1769,8 +1790,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-5.10/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-5.10/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..ba7c1e7a79 --- /dev/null +++ b/queue-5.10/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 124d04b1ea2d18b9e0013001dbfe430ac6befc81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index e2e935f789869..0e21910a649d1 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-5.10/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-5.10/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..d860619edf --- /dev/null +++ b/queue-5.10/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From 20323d74654fc397015113f564a9d26b041062d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index 18440c5104ad9..37f0814d808e4 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1159,6 +1159,10 @@ static int mt9p031_probe(struct i2c_client *client, + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-5.10/media-pulse8-cec-handle-partial-deinit.patch b/queue-5.10/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..329c337f85 --- /dev/null +++ b/queue-5.10/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From 55334e0a1c3431fdce0565030e8847d8ca3085c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 171366fe35443..90b8a968fed77 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-5.10/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-5.10/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..282e062de0 --- /dev/null +++ b/queue-5.10/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From e61c65f7d6f34d27bee51ba36cad052536114c24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/vsp1/vsp1_rwpf.c | 28 +++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c +index 049bdd958e56b..90907534799de 100644 +--- a/drivers/media/platform/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/vsp1/vsp1_rwpf.c +@@ -179,6 +179,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_pad_config *config; + struct v4l2_mbus_framefmt *format; +@@ -208,18 +210,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-5.10/media-saa7164-fix-rev2-firmware-filename.patch b/queue-5.10/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..14fb62b191 --- /dev/null +++ b/queue-5.10/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 541a44bb3bf58857c388774051d3094985086476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index 363689484c54a..c57d56678eb36 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-5.10/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-5.10/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..fbea27f84b --- /dev/null +++ b/queue-5.10/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From 43c95dc5d92c4c44283e7c4f56a3632d005a2ff7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 28e1d59d6b3e7..47c418c8abad2 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-5.10/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-5.10/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..6c044caa3f --- /dev/null +++ b/queue-5.10/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From 3c0eda441cdad3916879f79d4993ecfa2f0b07bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 14b93a7d33589..28e1d59d6b3e7 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -564,8 +564,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-5.10/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-5.10/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..db246abd3c --- /dev/null +++ b/queue-5.10/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From a805e68c48be4649377ed57c7823441260ed1242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c +index 233e4d3feacd9..68474d22f16cc 100644 +--- a/drivers/media/platform/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/stm32/stm32-dcmi.c +@@ -454,9 +454,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-5.10/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-5.10/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..648adbb0c3 --- /dev/null +++ b/queue-5.10/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From 2de746ba0d7b51086842162548415b829edb5ec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 9e1e87536c1ee..b3df833cc4954 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7149,7 +7149,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-5.10/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-5.10/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..61ccde6136 --- /dev/null +++ b/queue-5.10/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From aa3a180ea413f5163c8c5e55fb30c461677e46e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 642ef6b3eebaf..3e93d1115f1aa 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1414,6 +1415,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1427,7 +1429,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1467,6 +1468,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1477,6 +1479,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1511,6 +1514,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1519,6 +1523,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1528,6 +1533,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1857,6 +1863,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-5.10/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-5.10/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..e901c46b01 --- /dev/null +++ b/queue-5.10/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From 92c9a5e8fec24af89e55a349d4271cec8072ca54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index ee51367df6488..642ef6b3eebaf 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1463,6 +1463,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-5.10/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-5.10/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..643fab90bb --- /dev/null +++ b/queue-5.10/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From bb23acd32077ba0151dc9b8e6ea2d2b7de1bd14f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 04a034cd5183f..ee51367df6488 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -121,6 +121,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1412,10 +1414,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1469,6 +1471,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1519,6 +1522,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1847,6 +1851,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-5.10/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-5.10/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..b008cc511f --- /dev/null +++ b/queue-5.10/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From 51a0be36a53474dbfd835cbae19ab12198e5f5a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index 33ace33070593..77af8ace4d7b1 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1270,7 +1270,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1297,7 +1296,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-5.10/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-5.10/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..7f75fd96dd --- /dev/null +++ b/queue-5.10/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From c64ffcaf2e64f63caad4ec0c98bb78a5b36f9462 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 3e131788a4a3c..a846504b4cb6c 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -1713,6 +1713,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* Stop PTP Clock driver */ + if (priv->chip_id == RCAR_GEN2) +-- +2.53.0 + diff --git a/queue-5.10/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-5.10/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..100c43994e --- /dev/null +++ b/queue-5.10/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From 652dd3983e21df6f8ea8fc7ab0d264d7507d31ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 5c17c92add8ab..19b541082abb5 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -207,6 +207,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-5.10/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-5.10/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..a1cb3b4611 --- /dev/null +++ b/queue-5.10/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From 16b3e12aae9539ba180c313ebd43f6d74eef19f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index eeb6c47d81678..2cf2b60861388 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1905,6 +1905,8 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-5.10/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-5.10/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..a6e13f5c03 --- /dev/null +++ b/queue-5.10/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From 9e7f4c173c05a7831e9bf7f2a7c2f70a7bea3aa4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 963ea323362ad..67657a9b74a5e 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2011,6 +2011,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + sk_refcnt_debug_inc(newsk); + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-5.10/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-5.10/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..248570627a --- /dev/null +++ b/queue-5.10/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From f77ffd0440d3f84d63b17654b3f943df48251d37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index fdb7a5a12f035..f0867ca74d75c 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -359,7 +359,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -459,7 +459,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-5.10/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-5.10/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..66256d26bb --- /dev/null +++ b/queue-5.10/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 5bfdc8d4ac8295674093b0f0e17912339789ef27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 6af786d66b03a..d301e657356e3 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -269,6 +269,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-5.10/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-5.10/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..988de92500 --- /dev/null +++ b/queue-5.10/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 13c07b3c4ae483717f4e9b4db61d7caa23583a49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index a300d1ac13a88..9969222dd2150 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -741,11 +741,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-5.10/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-5.10/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..380fc8092f --- /dev/null +++ b/queue-5.10/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From 8a70384efe25d749ad6f2006cf210710e56c6083 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 9969222dd2150..1b8e003d5e70b 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -730,21 +730,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-5.10/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-5.10/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..f26b8afa87 --- /dev/null +++ b/queue-5.10/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From fc15028dce452eedea161531605834b28f945fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 3deca0d9a26bb..f40e003337cf8 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3907,3 +3907,4 @@ module_init(nvme_fc_init_module); + module_exit(nvme_fc_exit_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 824d4c088646a..293c4aa26571c 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2509,3 +2509,4 @@ module_init(nvme_rdma_init_module); + module_exit(nvme_rdma_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 26ede87e95cd3..e5f43b9774fc1 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2695,3 +2695,4 @@ module_init(nvme_tcp_init_module); + module_exit(nvme_tcp_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-5.10/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-5.10/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..31b021cc63 --- /dev/null +++ b/queue-5.10/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From 4545d41d9935e0a69be6dd9fcf7a82f2fef0e8b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 03df42e613f0f..ae3f99aa3a847 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3317,6 +3317,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-5.10/nvme-core-fix-parameter-name-in-comment.patch b/queue-5.10/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..0dcef2fd8f --- /dev/null +++ b/queue-5.10/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From 390799b8b7c7208c485b720d6e64a248591b9b08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index cb9b38e142edd..5ad3dcb8724fe 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2731,7 +2731,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-5.10/orangefs-validate-getxattr-response-length.patch b/queue-5.10/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..28274535eb --- /dev/null +++ b/queue-5.10/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From dfc091279b8ffbcdadecb7aa8ce4425f71bea0ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index 5e355d9d9a819..30c34d713aae7 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-5.10/pci-avoid-flr-for-amd-npu-device.patch b/queue-5.10/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..8f767f04b2 --- /dev/null +++ b/queue-5.10/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From 2e79f1a904b57d1c39562e65ac440792aaf25f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 0319aca1f762b..e001838bdb705 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5399,6 +5399,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * +@@ -5411,6 +5412,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + +-- +2.53.0 + diff --git a/queue-5.10/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-5.10/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..23c9adf1b2 --- /dev/null +++ b/queue-5.10/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From 629e2cbe1b968e75e9815d033b4de49a130abb54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index e59939ec2022c..738b836494f61 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -42,6 +42,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1400,6 +1401,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-5.10/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-5.10/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..86d0935146 --- /dev/null +++ b/queue-5.10/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 4ddf5cfa2f758bcf3c159302999505f15c16fba7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/gpu/vga/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c +index 5180c5687ee53..0fb6ca10f3b19 100644 +--- a/drivers/gpu/vga/vgaarb.c ++++ b/drivers/gpu/vga/vgaarb.c +@@ -1078,6 +1078,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1109,7 +1110,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists... */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-5.10/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-5.10/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..2d0292145f --- /dev/null +++ b/queue-5.10/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From b5ed290fe0baa88696b8fe8a4c46d3a69d457c49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 8525b7960787c..60457724931b2 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -432,6 +432,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-5.10/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-5.10/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..de7d583edf --- /dev/null +++ b/queue-5.10/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From 8a124dcea1be9cd05aeb92c765a8f014b7e4959a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 71576dceed3a2..57add2f28f2f3 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1002,6 +1002,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-5.10/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-5.10/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..7c40d8fc76 --- /dev/null +++ b/queue-5.10/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From 236866ced69a4e851b6151e14704eaa37e14699b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 666243d9dd593..20d59d78cd6b4 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-5.10/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-5.10/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..f2dad69857 --- /dev/null +++ b/queue-5.10/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From 1b73fe3871c508dd78fbed59816126061f620863 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 262d9be4f449e..50ecccc6dc064 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2830,12 +2830,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into the + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + pch->chan = NULL; + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-5.10/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-5.10/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..f20205e751 --- /dev/null +++ b/queue-5.10/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 368c0033760c75a540c4529011398870a51525c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index f8633d37e3581..5be4dd041f987 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -213,6 +213,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-5.10/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-5.10/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..31d65282cd --- /dev/null +++ b/queue-5.10/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,53 @@ +From 0510a6cfcc673bced511c3a4b0e1559f20938ac6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index b545798e400c4..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -113,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +-- +2.53.0 + diff --git a/queue-5.10/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-5.10/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..aaad5c6895 --- /dev/null +++ b/queue-5.10/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 1caa658585a9410423815144fdc56eaad015216e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index d91e022a0154c..f60c8632d542d 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1141,6 +1141,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1151,22 +1171,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-5.10/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-5.10/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..d0134c5d25 --- /dev/null +++ b/queue-5.10/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From 47bb34570a77e1eca2a8447432c31a82c37aa2d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index cdc7c0ff090f6..2593d5fc4bf8f 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -783,6 +783,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-5.10/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-5.10/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..926cdc1e18 --- /dev/null +++ b/queue-5.10/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 7938bde9a3c789b471d740abb514f6e364ea75c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index 7caba23365c1c..6c085f84ae8c7 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -136,6 +136,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + }; +@@ -243,7 +244,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1088,11 +1089,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 0dc6bd55ba..90b320ae30 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -525,3 +525,119 @@ drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeou drm-gma500-oaktrail_hdmi-fix-i2c-adapter-leak-on-setup.patch io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +irqchip-ath79-cpu-remove-unused-function.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +enic-add-v2-sr-iov-vf-device-id.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +pci-avoid-flr-for-amd-npu-device.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +virtiofs-add-fuse-protocol-validation.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +orangefs-validate-getxattr-response-length.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +iio-abi-fix-current_trigger-description.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +rculist-add-list_splice_rcu-for-private-lists.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-5.10/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-5.10/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..b86d774e3f --- /dev/null +++ b/queue-5.10/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From 80abf4dfa0d63a062c8e9887d563a2d516e1211e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index 5e11362ecc47e..3957a783852d9 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -4835,6 +4835,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + return rc; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + npages = DIV_ROUND_UP(len, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-5.10/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-5.10/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..f1fa933694 --- /dev/null +++ b/queue-5.10/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From 731ef687fb59a37db3032408bec2f7c39738dfda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index b545c2ca80a41..74a64b34e1b41 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -388,7 +388,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-5.10/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-5.10/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..a72f18beed --- /dev/null +++ b/queue-5.10/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From f888d2515fcb997133bc44394975f915b0884071 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 9ebd665e5d427..2618ba9898c31 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-5.10/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-5.10/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..65ef7e109f --- /dev/null +++ b/queue-5.10/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 126a36afb28f329ffc187b12be273c67b7d4a894 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index ead9e51f75ada..e6b8e8a0c68db 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1447,6 +1447,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1454,7 +1457,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-5.10/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-5.10/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..43ed80af47 --- /dev/null +++ b/queue-5.10/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From 732e48299fc04b089b4e4c537fc3fc5b2a377450 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 6e49928bb8646..c6e45ee06eb1b 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1384,9 +1384,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1508,8 +1508,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-5.10/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-5.10/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..be866ad7dd --- /dev/null +++ b/queue-5.10/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From e2c382197bf5e6999df02b29c35abd04f6142145 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index fafdc9fdb4a50..a1af6fed52ad1 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-5.10/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-5.10/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..14ba4c46c9 --- /dev/null +++ b/queue-5.10/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From 782991baa3205c41314731a4ee9dc011fb0e497e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index e21ea34f63a13..3ef2fc0e396cb 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -593,7 +593,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -601,11 +601,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.10/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-5.10/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..f724889df7 --- /dev/null +++ b/queue-5.10/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From 414de204d9645cfc68e3bf7e81fac27ccde69ea4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index 3ef2fc0e396cb..07c53d554dfd7 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -701,6 +701,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-5.10/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-5.10/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..50160f1b8e --- /dev/null +++ b/queue-5.10/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From cb35b8e47fd9a265d74d2a7f9b80f87807745d44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index 171c15a4d72bc..e21ea34f63a13 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -596,7 +596,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -627,14 +627,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-5.10/virtiofs-add-fuse-protocol-validation.patch b/queue-5.10/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..73e64a51e2 --- /dev/null +++ b/queue-5.10/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From fb9296c7c8ad0eec0cd3d093dc3cb0694116434a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index d405cdf36247c..96e6ebb0a4ee2 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -556,6 +556,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -566,10 +587,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct page *page; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -625,6 +642,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-5.10/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-5.10/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..5446b2c0c3 --- /dev/null +++ b/queue-5.10/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From 02eb4b6187935fc6f534ba2010257bb70522456e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index f3c628a64b954..a2ac28d1d02ce 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -1910,10 +1910,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-5.10/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-5.10/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..5762cbed38 --- /dev/null +++ b/queue-5.10/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From 4cc8bc81f11938513737a10d0a197b5bf7e44439 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index cf68731bd0944..750c3a12d5701 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -528,6 +528,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-5.10/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-5.10/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..9183bd2f6e --- /dev/null +++ b/queue-5.10/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From 6625cd7c95685da32855c45196f8956cb5d616b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index dc3f5222f4b54..1cc15cb142d7c 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -326,6 +326,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index 11388a1469621..7214325bc4bc9 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -875,6 +875,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c68076d58d117..9eefd23f37505 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-5.10/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-5.10/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..ff5b06ddce --- /dev/null +++ b/queue-5.10/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From 8ce3f3e88f403638a846c74d7c03fa1569c962bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index ca8072177ae38..7cf580ebf9d55 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -362,7 +362,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + vif = si->vif; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-5.15/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-5.15/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..b3c35f8622 --- /dev/null +++ b/queue-5.15/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From 3d8fa5186921b31139b8d37188f5303c6999bcd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 6b71082d474f9..1fd5015b914e6 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1082,6 +1082,8 @@ static int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-5.15/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-5.15/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..044986d660 --- /dev/null +++ b/queue-5.15/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From 9d4983a07cbc91fa7b83808cda2c49c5d61004be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 1fd5015b914e6..4e72dbfca7fb9 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1282,16 +1282,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-5.15/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-5.15/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..97de9fa0b9 --- /dev/null +++ b/queue-5.15/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From de0bc7f8d58ade934ea6cbf7023c6a651354a897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index b2bf7016e1b34..287f674b7af17 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -85,6 +85,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-5.15/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-5.15/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..c1f5373536 --- /dev/null +++ b/queue-5.15/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 0ebe6a3bb890344369b987f278752de86cb2a437 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 1abee841cc451..3ad849de5c109 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -1020,10 +1020,12 @@ static int onyx_i2c_probe(struct i2c_client *client, + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-5.15/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-5.15/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..afaf8b0c5b --- /dev/null +++ b/queue-5.15/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From d74c7b9be03dd9e2d04cdea2f9ef95735c75799a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index ab19a37e2a68e..f251588fad6b7 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -908,6 +908,7 @@ static int tas_i2c_probe(struct i2c_client *client, + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-5.15/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-5.15/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..ee2be3608b --- /dev/null +++ b/queue-5.15/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 5a03d6583b25679d29f245dfc4b60f0b4cd2cb06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 1ba90a87808e4..84841f9db0850 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -161,6 +161,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %d total %d bytes\n", + tstamp->byte_offset, tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-5.15/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..ae25657bbc --- /dev/null +++ b/queue-5.15/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From c1f3f7ab0961450aad8e445db591b51b7ca97eb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c +index 0ebf4d9078522..3ff1603fd7d88 100644 +--- a/sound/hda/hdmi_chmap.c ++++ b/sound/hda/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-5.15/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-5.15/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..c8a899efd5 --- /dev/null +++ b/queue-5.15/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From 3b56b0a4e50b33475eccc6741ae7d04a6722e818 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 297d15383bded..e1c38390177e0 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1756,6 +1756,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1768,8 +1771,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-5.15/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-5.15/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..7081732c7e --- /dev/null +++ b/queue-5.15/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From 92ea93460880808a2c9ca41b13d376166d41ba83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index 59de416c61a30..6fa3ca1e4e6c9 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -213,8 +213,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -223,9 +224,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-5.15/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-5.15/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..eb111c4b96 --- /dev/null +++ b/queue-5.15/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From 7e82a98bcb462c5ef76a756556e355882dd2f391 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index 4c7ebc7fb4001..e3f63f879cd66 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -853,9 +853,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-5.15/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-5.15/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..65816704f4 --- /dev/null +++ b/queue-5.15/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From b55ab11452c47987503b4868146b03a54363c24f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index 0c7da72a7b846..dac3e9eadfeb5 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -284,6 +284,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + } + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-5.15/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-5.15/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..b1ecde5110 --- /dev/null +++ b/queue-5.15/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 87e270d492f496d52fd6b47c20e0f7fe1c5e902c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index b0b41a03c083e..eb800246ef082 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -213,6 +213,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + } + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-5.15/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-5.15/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..81bf4ff089 --- /dev/null +++ b/queue-5.15/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From c51cc20598d6c97ba6380dd61020285f48da65c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index ba96741c7771b..cf57fc5895594 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-5.15/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-5.15/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..7fc8c29411 --- /dev/null +++ b/queue-5.15/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From 8c36bd4d14fe884500b288ac4539b56e118d61b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 9998bdb954ba9..de3ddeaca45b4 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1841,6 +1841,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src) + return 0; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + reg_val |= RT5640_SCLK_SRC_MCLK; +-- +2.53.0 + diff --git a/queue-5.15/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-5.15/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..a4ad854242 --- /dev/null +++ b/queue-5.15/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From dc544a079495f302dcac552a84708cb2d9327d34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index ba36525a57898..2e4cdd9de5e91 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -492,7 +492,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -501,7 +501,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -590,7 +590,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_get_sync(component->dev); + if (ret < 0) { +@@ -615,7 +615,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -628,7 +628,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-5.15/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-5.15/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..54307c2dc6 --- /dev/null +++ b/queue-5.15/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From ddf1fc1e09f89520c1ba985b6fdb12233270e6c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index dbd30604816e5..65be92421d039 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2536,6 +2536,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-5.15/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-5.15/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..085144f9ee --- /dev/null +++ b/queue-5.15/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From af5de5c27bc913da6abcb1a977698af0e06c0509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index f0b690b39bf7a..405475d72b769 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2790,7 +2790,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-5.15/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..7de080f646 --- /dev/null +++ b/queue-5.15/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From 9f96e310173f67e416d9ba7522c1d87c691aed41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index f228cdbccaee3..f82e6ece316eb 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -493,6 +493,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-5.15/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..9b4105f406 --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From 6999de2523a5c0a54d5a7395913fbe1e2f4ce835 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index a5db427c13de2..d55d1465b23fb 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7655,6 +7655,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); + +-- +2.53.0 + diff --git a/queue-5.15/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-5.15/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..6ea6f11dfc --- /dev/null +++ b/queue-5.15/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From e27550e3a24f7f9e96db2ede8f27950fea5f3e6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 73a1c66e54175..7269b1a57e3ac 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1587,12 +1587,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-5.15/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-5.15/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..8013edc3bb --- /dev/null +++ b/queue-5.15/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 61a1f42d07ed627f30d4a9f0f8e8522914b6dbae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index 9482f34ebf845..7d773f1e11528 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -319,10 +319,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + return avail; +-- +2.53.0 + diff --git a/queue-5.15/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-5.15/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..e8552c5d6d --- /dev/null +++ b/queue-5.15/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From cf9ff6015512efe7fc07d3bfc2e223b25e0fd1bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index aff09ffddb32a..ff1e125fcc2b2 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -528,6 +528,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-5.15/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-5.15/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..61cd66c375 --- /dev/null +++ b/queue-5.15/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From 27e8eee3c790cb5f04b1c071874d08e94affb489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 3abec44c62559..464fa2d1f6a48 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -248,7 +248,11 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -391,7 +395,11 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1374,7 +1382,11 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-5.15/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-5.15/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..a98e667109 --- /dev/null +++ b/queue-5.15/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 494979a9da969fc0ffd44eed7cd7e4040047e698 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 4bc7a5e63b86d..01dc724582898 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -2767,7 +2767,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-5.15/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-5.15/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..a6b9f65f3e --- /dev/null +++ b/queue-5.15/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From 0eecda005b8237e45408711c4c5c6665ce3ad384 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index c75db0cd02653..e008e0bde63f8 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3617,7 +3617,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-5.15/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..f19c051276 --- /dev/null +++ b/queue-5.15/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From ef6ad5918f3b1f421db2098eab1f20eed975a23d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 05aa831ac7a44..626513393a731 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -730,6 +730,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-5.15/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-5.15/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..ca2a39066a --- /dev/null +++ b/queue-5.15/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From 7a126a2ed8554a83f070aa2f818ff8ba7fb78600 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index fed1941696668..839bf73d3f2f6 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -341,13 +341,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-5.15/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-5.15/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..c4c9294f7d --- /dev/null +++ b/queue-5.15/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 0f7bf0a9fd5edc38bee87c207f83d5b879c42bc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index 4ada7e7493904..95daa344e6d5e 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -3044,6 +3044,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-5.15/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..0a07917c73 --- /dev/null +++ b/queue-5.15/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From 3d81446c73c5c71290c75bc00f4d8ababb0870bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index c183c2fc1691c..4ac1cfb283d6b 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1851,3 +1851,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 79747130a48f7..ecb00465f1f5a 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -143,6 +143,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 37c8740d6d996..277ea162ba1ef 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2922,6 +2922,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2938,6 +2941,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3517,7 +3534,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-5.15/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..ac1f439aeb --- /dev/null +++ b/queue-5.15/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From de341bcee64cbfedafb0e4b6c3ea576e61773e17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index d8982aca8ef68..f0022cf92b420 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1930,7 +1930,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-5.15/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-5.15/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..060085912b --- /dev/null +++ b/queue-5.15/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 32697e2ecfc4b0de596297068a881232237807f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 98c842cf03e4a..17756019b7640 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1628,6 +1628,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-5.15/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-5.15/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..7f1d4e714e --- /dev/null +++ b/queue-5.15/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From adc1d4b7c6842e818c77bd4653992d1a19eaeec7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index cac98f0104257..2b104fcd90ebf 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -595,6 +595,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -654,6 +669,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -699,30 +716,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-5.15/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-5.15/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..52ca4d88cf --- /dev/null +++ b/queue-5.15/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 3f9212a224e732ba3a1c844f7b6fed729b43308e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index e9bf3054529f1..5ee19665ef939 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - const: marvell,armada7040 +-- +2.53.0 + diff --git a/queue-5.15/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-5.15/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..ff3a97023d --- /dev/null +++ b/queue-5.15/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From b0f972df2c91bacafb29c38dea45cb0c25d4a437 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 2dd23a82e0de5..d3f8a579f2302 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -573,6 +573,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-5.15/enic-add-v2-sr-iov-vf-device-id.patch b/queue-5.15/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..a668308da3 --- /dev/null +++ b/queue-5.15/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,54 @@ +From 895181b85348bb267e0c8760183e2b20632feeb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index a3f57069e972b..129558fce9aa8 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,6 +66,7 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + #define RX_COPYBREAK_DEFAULT 256 + +@@ -74,6 +75,7 @@ static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -309,7 +311,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-5.15/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-5.15/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..e03e150674 --- /dev/null +++ b/queue-5.15/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From 443dd8e73bdbb323bf269416db899c07059ee7d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-5.15/exfat-fix-bitwise-operation-having-different-size.patch b/queue-5.15/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..62eee467e4 --- /dev/null +++ b/queue-5.15/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 4e27a00dd78d8266866f9f0018212a361f0daf06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 70d0849826f26..d5b691e56cef2 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -264,7 +264,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-5.15/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-5.15/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..8c2dc48eab --- /dev/null +++ b/queue-5.15/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From 58b21d91de2cf3351bfed2dd54257c9468760040 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index 23d8c364edff9..9e1bc3a9ce189 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -640,7 +640,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-5.15/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-5.15/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..3736a90469 --- /dev/null +++ b/queue-5.15/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From c4845e910209980c3904c2e7a0bed963702f16af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index f8d8c21261727..97b9efac7b404 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -634,7 +634,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-5.15/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-5.15/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..5fa31cb747 --- /dev/null +++ b/queue-5.15/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From 404906b38e55a62e8d3b5114ede61c1559467161 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 9a57754e6e0c1..9f2c9137a4886 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -764,6 +764,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-5.15/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-5.15/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..27ae66446d --- /dev/null +++ b/queue-5.15/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From 96fe4bdc125634a7f033fa600af6dd715f1093c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index a3decc7fadde3..7cdc2a894dc6f 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1119,7 +1119,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-5.15/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-5.15/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..7c4c6a842d --- /dev/null +++ b/queue-5.15/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From 606ed5025cbe3d903af9bf12cffbbcd052ccc9cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index 224d7c8146a94..930dd4c2649b2 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2317,6 +2317,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-5.15/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-5.15/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..18beacb003 --- /dev/null +++ b/queue-5.15/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From e506064ae2e9364e995cee58c92fddd101aaac45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index 088b962076b51..8edaa725aa46b 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-5.15/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-5.15/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..45ded5e21a --- /dev/null +++ b/queue-5.15/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From 39b0ae86e38dedc949b8286206a443f5b4f8300b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index ebf502290e5f3..00cc23baa681f 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-5.15/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-5.15/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..bd402fab3c --- /dev/null +++ b/queue-5.15/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 9759b9d94faea30d0751688efef1b21798863235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 0f02ea16305cf..7790ef1eb25fd 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -342,7 +342,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-5.15/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-5.15/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..0419b6caec --- /dev/null +++ b/queue-5.15/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From 81893ac9d78511c4effd3c58d71d10ee32e74b15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index 4a7753384b0e9..2392b70cdadeb 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1021,7 +1021,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-5.15/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-5.15/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..a17fa81765 --- /dev/null +++ b/queue-5.15/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From ce9fcee1a8c81fb5f9ecd893a84fb69321362a2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 4ba1501119bff..9889bcfc9a6c3 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1269,7 +1269,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-5.15/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..d378b422ff --- /dev/null +++ b/queue-5.15/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 10d5c4d0fa0d77194e41b0a9c1ccb7050123fde3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 9b12d5a7ac8d5..ced1521d9d076 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-5.15/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-5.15/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..f3c41553ad --- /dev/null +++ b/queue-5.15/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From 331b184aa4709b9220e641a977ce02cbf04466bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 8e10d89f25078..b61932905adf2 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -119,6 +119,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-5.15/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-5.15/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..ac7f683aa2 --- /dev/null +++ b/queue-5.15/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From fea55624f96b95e68a1aa6627be209169b58e894 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 9a4d55f703bb5..f0faac5796bbf 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-5.15/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-5.15/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..e442cf2fa0 --- /dev/null +++ b/queue-5.15/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 1e9353fb02f1f859af2ee185550d5f2ccc87b055 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index 49446a030f108..672f0f5b1ee79 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-5.15/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-5.15/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..b39e37b00a --- /dev/null +++ b/queue-5.15/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 96a2c469242c8b71dfd913dd50764d52dff7c0bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 70fad87ff2db7..41aea180ae2e3 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -63,7 +63,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-5.15/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-5.15/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..5ad0eb279e --- /dev/null +++ b/queue-5.15/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From c44bcd069ea165f54d33738a75cc2805ee3ca015 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 1e9d8262d0ffc..1157417a8b330 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -52,7 +52,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, +-- +2.53.0 + diff --git a/queue-5.15/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-5.15/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..3dcae8eb8d --- /dev/null +++ b/queue-5.15/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From c98016694b7768019a692b38d518858345cefb23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index e55d28a8a66f2..a8ab97bf49770 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -283,7 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-5.15/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-5.15/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..4206aed8ea --- /dev/null +++ b/queue-5.15/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From ac609d27ba8de1f6aaebca6b880dc48faa906be1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 8756f9cbd631e..6f908ff1099a2 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -608,11 +608,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -624,7 +629,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.15/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-5.15/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..32517f0b2d --- /dev/null +++ b/queue-5.15/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From b6dd5e320131466cc591785b51377e9db162c5b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-5.15/hfsplus-fix-generic-642-failure.patch b/queue-5.15/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..cf20fa9923 --- /dev/null +++ b/queue-5.15/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From 13014a7c54def7a8db805c720903849b120c370f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 1918544a78716..b26cd7504e113 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-5.15/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-5.15/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..e0907335df --- /dev/null +++ b/queue-5.15/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From ba606a2cf152743566de5f45a5501c0ebdf5c654 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 9eb4d02cc6d77..6e9501fe1a281 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -222,7 +222,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-5.15/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-5.15/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..aba1e331db --- /dev/null +++ b/queue-5.15/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From 0fd482cd5561e6ba7a617b939f47226d69500a55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 6e9501fe1a281..1e41fcf2efa87 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -123,6 +123,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-5.15/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-5.15/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..0e43205502 --- /dev/null +++ b/queue-5.15/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 951731b6397ad5249dd81c12666f4cfd9ed8034f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index dd4195e964faf..b415e375d6205 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -450,14 +450,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + enum ice_status ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-5.15/iio-abi-fix-current_trigger-description.patch b/queue-5.15/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..73ffc2a20c --- /dev/null +++ b/queue-5.15/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From c7c216475c5ac963ccd19f6cd4e6e03496b53bdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index f41e767e702bd..6e36bd430de34 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1236,7 +1236,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-5.15/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-5.15/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..2e986cd898 --- /dev/null +++ b/queue-5.15/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From 946a70b4aec38b0eaac5e7c380781586ad97f1b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 53930c28b6946..6e2a790a76818 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -60,6 +60,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -430,11 +432,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-5.15/irqchip-ath79-cpu-remove-unused-function.patch b/queue-5.15/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..9d2dd3b1cd --- /dev/null +++ b/queue-5.15/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From fd15b6ddaeda83b6a5eb1b388ee2b9aec234e913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-5.15/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-5.15/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..0f24772eaa --- /dev/null +++ b/queue-5.15/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From 4d37b3f379d208ed2f8ebae7171e503a04186be1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index f4f4c5ec38c67..c6a5e55df54df 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1440,7 +1527,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1770,7 +1857,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2553,7 +2640,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3522,6 +3609,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3539,6 +3631,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3552,6 +3648,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3571,6 +3671,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3586,6 +3690,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-5.15/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-5.15/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..0c2ac90fb8 --- /dev/null +++ b/queue-5.15/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From 8c8fb3827e92b2ba35903777013924b52ce79768 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index cb57d4f1161f0..1d85836523e48 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4595,3 +4595,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index 1f2e452a76764..06bada49ab1e9 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-5.15/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-5.15/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..87f8315849 --- /dev/null +++ b/queue-5.15/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From 6668a8c60b0c35d9f65a538a8317d153d2317e45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 55702b31ab3c4..b8701c32ba4ed 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -376,11 +376,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-5.15/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-5.15/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..4a83f0c878 --- /dev/null +++ b/queue-5.15/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 596b28ec9b83dc9d0429b018fcac956674e90e6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 176580f54af96..076c665231a4a 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -181,6 +181,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -293,7 +294,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index d322a22477e49..2b99395d60080 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-5.15/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-5.15/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..68428d2179 --- /dev/null +++ b/queue-5.15/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From 67c434c2baf97dce7d98b1ec927eb37b31d8c100 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index d02bca48bc7b0..3525b5a485f32 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 805877ce50204..17e0490a24fb0 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 3e8b13e6aa01f..09cf081e985f4 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -97,6 +104,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-5.15/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-5.15/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..3e3635654d --- /dev/null +++ b/queue-5.15/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 4a66e07c99c05c0de56400dc19397751ca87dd51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 3525b5a485f32..978d82ced83fc 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2189,8 +2189,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2205,12 +2203,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2234,8 +2230,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2287,8 +2282,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2299,6 +2292,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2311,9 +2305,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-5.15/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-5.15/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..a83932168f --- /dev/null +++ b/queue-5.15/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 9a30d9a9e0eb3a42efc6512164ebd1a982dab25a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/ksmbd/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c +index 9fef4d88ee8ba..f0d0d7b2974a6 100644 +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -2819,7 +2819,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -2833,7 +2833,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-5.15/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-5.15/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..ffcf0dcb64 --- /dev/null +++ b/queue-5.15/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From b6e011148e4d31f7dbd7e13c839cff14909db453 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/ksmbd/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c +index f0d0d7b2974a6..4be56a45e3e45 100644 +--- a/fs/ksmbd/smb2pdu.c ++++ b/fs/ksmbd/smb2pdu.c +@@ -6960,7 +6960,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-5.15/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-5.15/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..1d9bb207c1 --- /dev/null +++ b/queue-5.15/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From 303edf85b0ce9ee46fb66182a6483eac1ccb2240 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 0b5dfb001bacc..a32943555b67d 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-5.15/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-5.15/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..081bc9d875 --- /dev/null +++ b/queue-5.15/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 42747e2ae5bc9d2d924c01d413d0b513b1cff8b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index a32943555b67d..b27ef9f1af1d3 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-5.15/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-5.15/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..429cd1166f --- /dev/null +++ b/queue-5.15/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From 365fd783cded3e0a771f49e3f1d1bffb30e31f1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 45045c2a26574..d2b836337a4d2 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-5.15/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-5.15/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..95541cdca6 --- /dev/null +++ b/queue-5.15/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 9e96cd3bce64966c60491f0d1085c6bd46604dd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 7d63e2f1555a0..37926b4b205af 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -21,6 +21,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -73,9 +80,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -99,16 +105,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-5.15/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-5.15/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..be06ac89d2 --- /dev/null +++ b/queue-5.15/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From 8d8920325eb379217d9c65100fef80e9b27bbbd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index a957eb3ce7bc6..4051c6a522501 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3889,6 +3889,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-5.15/media-au0828-fix-green-screen-in-analog.patch b/queue-5.15/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..a5960fda39 --- /dev/null +++ b/queue-5.15/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From 8e6abbf07f8f319bcd0c327125b3fb09b8c844d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index c0f118563c7d1..4b34bf117e63d 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1675,6 +1675,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1768,8 +1789,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-5.15/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-5.15/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..fe082bb5dd --- /dev/null +++ b/queue-5.15/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From ceb0707ef3d4dfd2e775a30ba9f872b18dd5fbba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index fe9e3a90749de..9094acd393218 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -807,9 +807,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-5.15/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-5.15/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..d231d493ce --- /dev/null +++ b/queue-5.15/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 0a9bc4b47c2c30a9a3b22731c6de9d489a86e156 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index dc31944c7d5b1..79f5f08f49933 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-5.15/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-5.15/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..6801972301 --- /dev/null +++ b/queue-5.15/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From 1408b17c6ce40f1c93662fab9ab5f00fad1a5397 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 8ab10518957c4..6d4529435b188 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2712,10 +2712,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-5.15/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-5.15/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..ae93105a78 --- /dev/null +++ b/queue-5.15/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From d2835a2f74104796fd374dfb1318d8d1c9d5db88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index 3ae1b28c8351b..0941345c8c420 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1165,6 +1165,10 @@ static int mt9p031_probe(struct i2c_client *client, + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-5.15/media-pulse8-cec-handle-partial-deinit.patch b/queue-5.15/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..15f8fe69b6 --- /dev/null +++ b/queue-5.15/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From b8137582b6855676dd14790115f50eee10867af8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 171366fe35443..90b8a968fed77 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-5.15/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-5.15/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..411bb64274 --- /dev/null +++ b/queue-5.15/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From 066f641e93f77b22f92ec0e53f9607eab19ca293 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c +index 897dfe99323af..47edd4f4cb379 100644 +--- a/drivers/media/platform/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/vsp1/vsp1_histo.c +@@ -172,7 +172,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.15/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-5.15/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..fe2ed1f3aa --- /dev/null +++ b/queue-5.15/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From 6224c6fe293179c5a1c63fe3a3d2039613beb756 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/vsp1/vsp1_rwpf.c | 28 +++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c +index 22a82d218152f..44335cb50bbca 100644 +--- a/drivers/media/platform/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/vsp1/vsp1_rwpf.c +@@ -182,6 +182,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *config; + struct v4l2_mbus_framefmt *format; +@@ -212,18 +214,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-5.15/media-saa7164-fix-rev2-firmware-filename.patch b/queue-5.15/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..87ea49c7f5 --- /dev/null +++ b/queue-5.15/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 942e1d95b5a971dee587cfefc642dbdc3400851b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index 363689484c54a..c57d56678eb36 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-5.15/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-5.15/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..d165675184 --- /dev/null +++ b/queue-5.15/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From 3f34002371a8eab4ed4214b7261e83fa5ed72193 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 28e1d59d6b3e7..47c418c8abad2 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-5.15/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-5.15/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..3fc2817b5e --- /dev/null +++ b/queue-5.15/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From 27333e0e4c46b73e782952a7352cc51df58ec0a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 14b93a7d33589..28e1d59d6b3e7 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -564,8 +564,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-5.15/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-5.15/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..cf4a2fdb3c --- /dev/null +++ b/queue-5.15/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From 3a4b903d22b58bd67c4796647629a3b846e97a35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c +index 6110718645a4f..71f14e6bb8f33 100644 +--- a/drivers/media/platform/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/stm32/stm32-dcmi.c +@@ -448,9 +448,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-5.15/module-override-eexist-module-return.patch b/queue-5.15/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..8da067009a --- /dev/null +++ b/queue-5.15/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From d5a3535b1b39a4943fc7f6e9ee5b2e183d0d1aa7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module.c b/kernel/module.c +index b6409b0032b85..d562a4ea38e81 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -3754,6 +3754,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-5.15/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-5.15/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..7ba32586e9 --- /dev/null +++ b/queue-5.15/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From bde9b0b0b9b2c7fe08c7705f7868098aed72b1e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 4aa21422e1d0a..fac2aed82a393 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7455,7 +7455,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-5.15/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-5.15/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..4281e65a34 --- /dev/null +++ b/queue-5.15/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From 13dbf1addfa99fbd207cae746cc1129a4f13d855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index be2b106b4aa27..8cc3cca1f4bd4 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -121,6 +121,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1413,6 +1414,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1426,7 +1428,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1466,6 +1467,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1476,6 +1478,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1510,6 +1513,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1518,6 +1522,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1527,6 +1532,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1856,6 +1862,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-5.15/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-5.15/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..84a8d331e6 --- /dev/null +++ b/queue-5.15/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From bad298a8e8d192938b6ca150f39aaafd9ba3ab05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 29f8e19661efa..be2b106b4aa27 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1462,6 +1462,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-5.15/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-5.15/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..22d2c213ab --- /dev/null +++ b/queue-5.15/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From eaf308373aa6c8f733e5ee11bf55847a369bdb6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 3a11dccec8c1b..29f8e19661efa 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -120,6 +120,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1411,10 +1413,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1468,6 +1470,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1518,6 +1521,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1846,6 +1850,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-5.15/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-5.15/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..bc3c4efba7 --- /dev/null +++ b/queue-5.15/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From d2ea2c540c70a0e104ef0a0c9fd1bc5d6dcbdcf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index d0c4c8b7a15ab..9795f959c9bde 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1270,7 +1270,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1297,7 +1296,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-5.15/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-5.15/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..bf7e6e5bb8 --- /dev/null +++ b/queue-5.15/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From 42fa595afea0b323d24b5e9cdeb66845ed5ed9a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 4f115058eba19..d3c536eaf667f 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -1787,6 +1787,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* Stop PTP Clock driver */ + if (info->gptp) +-- +2.53.0 + diff --git a/queue-5.15/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-5.15/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..caedd7dde2 --- /dev/null +++ b/queue-5.15/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From c83ec6bec4f5d5c016e9bfd6232ca20a92303ec5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 027b04795421d..6e14d646a7965 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -207,6 +207,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-5.15/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-5.15/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..f923b8c0e5 --- /dev/null +++ b/queue-5.15/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From 84827621a2704f23b153203541913fd87ac1ee1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index 39db3cae4dd1a..a487dacc86990 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1908,6 +1908,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-5.15/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-5.15/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..626dd75a7e --- /dev/null +++ b/queue-5.15/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From bd930ce68bf82f5a08e08f89414b698ca80e48ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index bf2bec10d5d6a..91a90a976c609 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2167,6 +2167,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + sk_refcnt_debug_inc(newsk); + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-5.15/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-5.15/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..62ffad4d1d --- /dev/null +++ b/queue-5.15/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From 3ae9aac04906f5b63de5f553a7d82a83dc8e07f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index 3f124268bd4d4..89a2a65a5133f 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5243,6 +5243,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5373,6 +5375,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-5.15/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-5.15/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..21a9229455 --- /dev/null +++ b/queue-5.15/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From f7039edacde1115b0cd71faec746a215c617fb20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index 431fd1f2b80c1..be130b8ff759e 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -359,7 +359,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -460,7 +460,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-5.15/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-5.15/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..af37451fb6 --- /dev/null +++ b/queue-5.15/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 4856ca03e930ced95457090464f693e4d8b824d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 6af786d66b03a..d301e657356e3 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -269,6 +269,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-5.15/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-5.15/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..a26911d424 --- /dev/null +++ b/queue-5.15/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 8fa3afa159bb6c555e2ff033d8dd9a777c59cfd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 002806908aa82..33b8afa2048ce 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -784,11 +784,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-5.15/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-5.15/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..2bc9dbe21b --- /dev/null +++ b/queue-5.15/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From 4ec5c069c2f44d5ee351cdb4084de1cd3e125ed9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 33b8afa2048ce..630fa387da14f 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -773,21 +773,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-arp_tables-allow-use-of-arpt_do_table-as-h.patch b/queue-5.15/netfilter-arp_tables-allow-use-of-arpt_do_table-as-h.patch new file mode 100644 index 0000000000..48742cfe97 --- /dev/null +++ b/queue-5.15/netfilter-arp_tables-allow-use-of-arpt_do_table-as-h.patch @@ -0,0 +1,87 @@ +From 5332b52d5b6ad0955535ade9bc4130d81ba1abce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Oct 2021 17:15:12 +0200 +Subject: netfilter: arp_tables: allow use of arpt_do_table as hookfn + +From: Florian Westphal + +[ Upstream commit e8d225b6002673366abc2e40e30c991bdc8d62ca ] + +This is possible now that the xt_table structure is passed in via *priv. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter_arp/arp_tables.h | 5 ++--- + net/ipv4/netfilter/arp_tables.c | 7 ++++--- + net/ipv4/netfilter/arptable_filter.c | 10 +--------- + 3 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index 4f9a4b3c58926..a40aaf645fa47 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -54,9 +54,8 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); + void arpt_unregister_table_pre_exit(struct net *net, const char *name); +-extern unsigned int arpt_do_table(struct sk_buff *skb, +- const struct nf_hook_state *state, +- struct xt_table *table); ++extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, ++ const struct nf_hook_state *state); + + #ifdef CONFIG_NETFILTER_XTABLES_COMPAT + #include +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 92bc90ee76748..564054123772a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -191,10 +191,11 @@ struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) + return (void *)entry + entry->next_offset; + } + +-unsigned int arpt_do_table(struct sk_buff *skb, +- const struct nf_hook_state *state, +- struct xt_table *table) ++unsigned int arpt_do_table(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) + { ++ const struct xt_table *table = priv; + unsigned int hook = state->hook; + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); + unsigned int verdict = NF_DROP; +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 771eec4629352..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -26,14 +26,6 @@ static const struct xt_table packet_filter = { + .priority = NF_IP_PRI_FILTER, + }; + +-/* The work comes in here from netfilter.c */ +-static unsigned int +-arptable_filter_hook(void *priv, struct sk_buff *skb, +- const struct nf_hook_state *state) +-{ +- return arpt_do_table(skb, state, priv); +-} +- + static struct nf_hook_ops *arpfilter_ops __read_mostly; + + static int arptable_filter_table_init(struct net *net) +@@ -72,7 +64,7 @@ static int __init arptable_filter_init(void) + if (ret < 0) + return ret; + +- arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arptable_filter_hook); ++ arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); + if (IS_ERR(arpfilter_ops)) { + xt_unregister_template(&packet_filter); + return PTR_ERR(arpfilter_ops); +-- +2.53.0 + diff --git a/queue-5.15/netfilter-arptables-allow-xtables-nft-only-builds.patch b/queue-5.15/netfilter-arptables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..9a17a1ac39 --- /dev/null +++ b/queue-5.15/netfilter-arptables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,82 @@ +From 2501d53e27723a906a71073a3b32a041c22b45e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Jan 2024 16:42:48 +0100 +Subject: netfilter: arptables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 4654467dc7e111e84f43ed1b70322873ae77e7be ] + +Allows to build kernel that supports the arptables mangle target +via nftables' compat infra but without the arptables get/setsockopt +interface or the old arptables filter interpreter. + +IOW, setting IP_NF_ARPFILTER=n will break arptables-legacy, but +arptables-nft will continue to work as long as nftables compat +support is enabled. + +Signed-off-by: Florian Westphal +Reviewed-by: Phil Sutter +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 63cb953bd0196..5c2cdcb19dba3 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -331,36 +331,34 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate "ARP tables support" +- select NETFILTER_XTABLES +- select NETFILTER_FAMILY_ARP +- depends on NETFILTER_ADVANCED +- help +- arptables is a general, extensible packet identification framework. +- The ARP packet filtering and mangling (manipulation)subsystems +- use this: say Y or M here if you want to use either of those. +- +- To compile it as a module, choose M here. If unsure, say N. ++ tristate + +-if IP_NF_ARPTABLES ++config NFT_COMPAT_ARP ++ tristate ++ depends on NF_TABLES_ARP && NFT_COMPAT ++ default m if NFT_COMPAT=m ++ default y if NFT_COMPAT=y + + config IP_NF_ARPFILTER +- tristate "ARP packet filtering" ++ tristate "arptables-legacy packet filtering support" ++ select IP_NF_ARPTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +- local output. On a bridge, you can also specify filtering rules +- for forwarded ARP packets. See the man page for arptables(8). ++ local output. This is only needed for arptables-legacy(8). ++ Neither arptables-nft nor nftables need this to work. + + To compile it as a module, choose M here. If unsure, say N. + + config IP_NF_ARP_MANGLE + tristate "ARP payload mangling" ++ depends on IP_NF_ARPTABLES || NFT_COMPAT_ARP + help + Allows altering the ARP packet payload: source and destination + hardware and network addresses. + +-endif # IP_NF_ARPTABLES ++ This option is needed by both arptables-legacy and arptables-nft. ++ It is not used by nftables. + + endmenu + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-arptables-select-netfilter_family_arp-when.patch b/queue-5.15/netfilter-arptables-select-netfilter_family_arp-when.patch new file mode 100644 index 0000000000..e51d4ea9f1 --- /dev/null +++ b/queue-5.15/netfilter-arptables-select-netfilter_family_arp-when.patch @@ -0,0 +1,112 @@ +From 5173e61c4c2b2444ba66b6888c09b7d89a2fdce7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Mar 2024 21:15:52 -0700 +Subject: netfilter: arptables: Select NETFILTER_FAMILY_ARP when building + arp_tables.c + +From: Kuniyuki Iwashima + +[ Upstream commit 15fba562f7a9f04322b8bfc8f392e04bb93d81be ] + +syzkaller started to report a warning below [0] after consuming the +commit 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only +builds"). + +The change accidentally removed the dependency on NETFILTER_FAMILY_ARP +from IP_NF_ARPTABLES. + +If NF_TABLES_ARP is not enabled on Kconfig, NETFILTER_FAMILY_ARP will +be removed and some code necessary for arptables will not be compiled. + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + CONFIG_NETFILTER_FAMILY_ARP=y + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + + $ make olddefconfig + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + +So, when nf_register_net_hooks() is called for arptables, it will +trigger the splat below. + +Now IP_NF_ARPTABLES is only enabled by IP_NF_ARPFILTER, so let's +restore the dependency on NETFILTER_FAMILY_ARP in IP_NF_ARPFILTER. + +[0]: +WARNING: CPU: 0 PID: 242 at net/netfilter/core.c:316 nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Modules linked in: +CPU: 0 PID: 242 Comm: syz-executor.0 Not tainted 6.8.0-12821-g537c2e91d354 #10 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 +RIP: 0010:nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Code: 83 fd 04 0f 87 bc 00 00 00 e8 5b 84 83 fd 4d 8d ac ec a8 0b 00 00 e8 4e 84 83 fd 4c 89 e8 5b 5d 41 5c 41 5d c3 e8 3f 84 83 fd <0f> 0b e8 38 84 83 fd 45 31 ed 5b 5d 4c 89 e8 41 5c 41 5d c3 e8 26 +RSP: 0018:ffffc90000b8f6e8 EFLAGS: 00010293 +RAX: 0000000000000000 RBX: 0000000000000003 RCX: ffffffff83c42164 +RDX: ffff888106851180 RSI: ffffffff83c42321 RDI: 0000000000000005 +RBP: 0000000000000000 R08: 0000000000000005 R09: 000000000000000a +R10: 0000000000000003 R11: ffff8881055c2f00 R12: ffff888112b78000 +R13: 0000000000000000 R14: ffff8881055c2f00 R15: ffff8881055c2f00 +FS: 00007f377bd78800(0000) GS:ffff88811b000000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000496068 CR3: 000000011298b003 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + __nf_register_net_hook+0xcd/0x7a0 net/netfilter/core.c:428 + nf_register_net_hook+0x116/0x170 net/netfilter/core.c:578 + nf_register_net_hooks+0x5d/0xc0 net/netfilter/core.c:594 + arpt_register_table+0x250/0x420 net/ipv4/netfilter/arp_tables.c:1553 + arptable_filter_table_init+0x41/0x60 net/ipv4/netfilter/arptable_filter.c:39 + xt_find_table_lock+0x2e9/0x4b0 net/netfilter/x_tables.c:1260 + xt_request_find_table_lock+0x2b/0xe0 net/netfilter/x_tables.c:1285 + get_info+0x169/0x5c0 net/ipv4/netfilter/arp_tables.c:808 + do_arpt_get_ctl+0x3f9/0x830 net/ipv4/netfilter/arp_tables.c:1444 + nf_getsockopt+0x76/0xd0 net/netfilter/nf_sockopt.c:116 + ip_getsockopt+0x17d/0x1c0 net/ipv4/ip_sockglue.c:1777 + tcp_getsockopt+0x99/0x100 net/ipv4/tcp.c:4373 + do_sock_getsockopt+0x279/0x360 net/socket.c:2373 + __sys_getsockopt+0x115/0x1e0 net/socket.c:2402 + __do_sys_getsockopt net/socket.c:2412 [inline] + __se_sys_getsockopt net/socket.c:2409 [inline] + __x64_sys_getsockopt+0xbd/0x150 net/socket.c:2409 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0x4f/0x110 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x46/0x4e +RIP: 0033:0x7f377beca6fe +Code: 1f 44 00 00 48 8b 15 01 97 0a 00 f7 d8 64 89 02 b8 ff ff ff ff eb b8 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 37 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 0a c3 66 0f 1f 84 00 00 00 00 00 48 8b 15 c9 +RSP: 002b:00000000005df728 EFLAGS: 00000246 ORIG_RAX: 0000000000000037 +RAX: ffffffffffffffda RBX: 00000000004966e0 RCX: 00007f377beca6fe +RDX: 0000000000000060 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 000000000042938a R08: 00000000005df73c R09: 00000000005df800 +R10: 00000000004966e8 R11: 0000000000000246 R12: 0000000000000003 +R13: 0000000000496068 R14: 0000000000000003 R15: 00000000004bc9d8 + + +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Reported-by: syzkaller +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Simon Horman +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 18f60e675c438..e752a07a871fe 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -351,6 +351,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ select NETFILTER_FAMILY_ARP + depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of +-- +2.53.0 + diff --git a/queue-5.15/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-5.15/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..5d1196bb4f --- /dev/null +++ b/queue-5.15/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From 7a73e98debcefb7a3d2139c19200a2a0024ac1f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 5390b25cdb45e..9374a3207a276 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2582,19 +2582,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-ebtables-allow-xtables-nft-only-builds.patch b/queue-5.15/netfilter-ebtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..e9e51f261c --- /dev/null +++ b/queue-5.15/netfilter-ebtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,84 @@ +From bdeb77711962eee92009564364bb9cfca315746a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:12 +0100 +Subject: netfilter: ebtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 7ad269787b6615ca56bb161063331991fce51abf ] + +Same patch as previous one, but for ebtables. + +To build a kernel that only supports ebtables-nft, the builtin tables +need to be disabled, i.e.: + +CONFIG_BRIDGE_EBT_BROUTE=n +CONFIG_BRIDGE_EBT_T_FILTER=n +CONFIG_BRIDGE_EBT_T_NAT=n + +The ebtables specific extensions can then be used nftables' +NFT_COMPAT interface. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 7 +++++++ + net/bridge/netfilter/Makefile | 2 +- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 7f304a19ac1bf..104c0125e32e8 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -39,6 +39,10 @@ config NF_CONNTRACK_BRIDGE + + To compile it as a module, choose M here. If unsure, say N. + ++# old sockopt interface and eval loop ++config BRIDGE_NF_EBTABLES_LEGACY ++ tristate ++ + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" + depends on BRIDGE && NETFILTER && NETFILTER_XTABLES +@@ -55,6 +59,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -65,6 +70,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -74,6 +80,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile +index 1c9ce49ab6513..b9a1303da9771 100644 +--- a/net/bridge/netfilter/Makefile ++++ b/net/bridge/netfilter/Makefile +@@ -9,7 +9,7 @@ obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o + # connection tracking + obj-$(CONFIG_NF_CONNTRACK_BRIDGE) += nf_conntrack_bridge.o + +-obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o ++obj-$(CONFIG_BRIDGE_NF_EBTABLES_LEGACY) += ebtables.o + + # tables + obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o +-- +2.53.0 + diff --git a/queue-5.15/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-5.15/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..3bb28a80ca --- /dev/null +++ b/queue-5.15/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From 47d8d349a765d858fafcf0d7227087059b74927a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index c5d6fb937394c..d54afb88761e6 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index ee3d6d5a03a35..28f6a1f33898a 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -100,18 +100,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index c98840b68fc52..a9450d6e49565 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -99,16 +99,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-5.15/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-5.15/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..c15e22452a --- /dev/null +++ b/queue-5.15/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From 7531c8e4aba6a858bddd1c35ae1e9a9f9619248b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 3d4ea774d7e8f..c5d6fb937394c 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 257d63b5dec16..ee3d6d5a03a35 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -116,8 +116,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 39179c2cf87d2..c98840b68fc52 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -115,8 +115,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index c74efcc2b4996..5390b25cdb45e 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2555,11 +2559,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-exclude-legacy-tables-on-preempt_rt.patch b/queue-5.15/netfilter-exclude-legacy-tables-on-preempt_rt.patch new file mode 100644 index 0000000000..ec2d1837fd --- /dev/null +++ b/queue-5.15/netfilter-exclude-legacy-tables-on-preempt_rt.patch @@ -0,0 +1,335 @@ +From 68d1fda31e9cf9ee1c67f35fe926763ea2069884 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Jun 2025 17:44:23 +0200 +Subject: netfilter: Exclude LEGACY TABLES on PREEMPT_RT. + +From: Pablo Neira Ayuso + +[ Upstream commit 9fce66583f06c212e95e4b76dd61d8432ffa56b6 ] + +The seqcount xt_recseq is used to synchronize the replacement of +xt_table::private in xt_replace_table() against all readers such as +ipt_do_table() + +To ensure that there is only one writer, the writing side disables +bottom halves. The sequence counter can be acquired recursively. Only the +first invocation modifies the sequence counter (signaling that a writer +is in progress) while the following (recursive) writer does not modify +the counter. +The lack of a proper locking mechanism for the sequence counter can lead +to live lock on PREEMPT_RT if the high prior reader preempts the +writer. Additionally if the per-CPU lock on PREEMPT_RT is removed from +local_bh_disable() then there is no synchronisation for the per-CPU +sequence counter. + +The affected code is "just" the legacy netfilter code which is replaced +by "netfilter tables". That code can be disabled without sacrificing +functionality because everything is provided by the newer +implementation. This will only requires the usage of the "-nft" tools +instead of the "-legacy" ones. +The long term plan is to remove the legacy code so lets accelerate the +progress. + +Relax dependencies on iptables legacy, replace select with depends on, +this should cause no harm to existing kernel configs and users can still +toggle IP{6}_NF_IPTABLES_LEGACY in any case. +Make EBTABLES_LEGACY, IPTABLES_LEGACY and ARPTABLES depend on +NETFILTER_XTABLES_LEGACY. Hide xt_recseq and its users, +xt_register_table() and xt_percpu_counter_alloc() behind +NETFILTER_XTABLES_LEGACY. Let NETFILTER_XTABLES_LEGACY depend on +!PREEMPT_RT. + +This will break selftest expecing the legacy options enabled and will be +addressed in a following patch. + +Co-developed-by: Florian Westphal +Co-developed-by: Sebastian Andrzej Siewior +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 10 +++++----- + net/ipv4/netfilter/Kconfig | 24 ++++++++++++------------ + net/ipv6/netfilter/Kconfig | 19 +++++++++---------- + net/netfilter/Kconfig | 10 ++++++++++ + net/netfilter/x_tables.c | 16 +++++++++++----- + 5 files changed, 47 insertions(+), 32 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index f16bbbbb94817..60f28e4fb5c0a 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -42,8 +42,8 @@ config NF_CONNTRACK_BRIDGE + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY + tristate "Legacy EBTABLES support" +- depends on BRIDGE && NETFILTER_XTABLES +- default n ++ depends on BRIDGE && NETFILTER_XTABLES_LEGACY ++ default n + help + Legacy ebtables packet/frame classifier. + This is not needed if you are using ebtables over nftables +@@ -65,7 +65,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -76,7 +76,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -86,7 +86,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 2e540786f9512..4cfe4b12bda7c 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -13,8 +13,8 @@ config NF_DEFRAG_IPV4 + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY + tristate "Legacy IP tables support" +- default n +- select NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + iptables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -190,8 +190,8 @@ config IP_NF_MATCH_TTL + # `filter', generic and specific targets + config IP_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -228,10 +228,10 @@ config IP_NF_TARGET_SYNPROXY + config IP_NF_NAT + tristate "iptables NAT support" + depends on NF_CONNTRACK ++ depends on IP_NF_IPTABLES_LEGACY + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -271,8 +271,8 @@ endif # IP_NF_NAT + # mangle + specific targets + config IP_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -321,7 +321,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -335,7 +335,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -347,8 +347,8 @@ endif # IP_NF_IPTABLES + # ARP tables + config IP_NF_ARPTABLES + tristate "Legacy ARPTABLES support" +- depends on NETFILTER_XTABLES +- default n ++ depends on NETFILTER_XTABLES_LEGACY ++ default n + help + arptables is a legacy packet classifier. + This is not needed if you are using arptables over nftables +@@ -364,7 +364,7 @@ config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES + select NETFILTER_FAMILY_ARP +- depends on NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index 670d23f926e62..052f1f53c4dfe 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -9,9 +9,8 @@ menu "IPv6: Netfilter Configuration" + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY + tristate "Legacy IP6 tables support" +- depends on INET && IPV6 +- select NETFILTER_XTABLES +- default n ++ depends on INET && IPV6 && NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + ip6tables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -204,8 +203,8 @@ config IP6_NF_TARGET_HL + + config IP6_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + tristate + help + Packet filtering defines a table `filter', which has a series of +@@ -241,8 +240,8 @@ config IP6_NF_TARGET_SYNPROXY + + config IP6_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -252,7 +251,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -266,7 +265,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -277,8 +276,8 @@ config IP6_NF_NAT + tristate "ip6tables NAT support" + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED ++ depends on IP6_NF_IPTABLES_LEGACY + select NF_NAT +- select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index fdfda4b6bff67..085ea824c503d 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -756,6 +756,16 @@ config NETFILTER_XTABLES_COMPAT + + If unsure, say N. + ++config NETFILTER_XTABLES_LEGACY ++ bool "Netfilter legacy tables support" ++ depends on !PREEMPT_RT ++ help ++ Say Y here if you still require support for legacy tables. This is ++ required by the legacy tools (iptables-legacy) and is not needed if ++ you use iptables over nftables (iptables-nft). ++ Legacy support is not limited to IP, it also includes EBTABLES and ++ ARPTABLES. ++ + comment "Xtables combined modules" + + config NETFILTER_XT_MARK +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 9c0ec0bbb5699..30af321d6c964 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1339,12 +1339,13 @@ void xt_compat_unlock(u_int8_t af) + EXPORT_SYMBOL_GPL(xt_compat_unlock); + #endif + +-DEFINE_PER_CPU(seqcount_t, xt_recseq); +-EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); +- + struct static_key xt_tee_enabled __read_mostly; + EXPORT_SYMBOL_GPL(xt_tee_enabled); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY ++DEFINE_PER_CPU(seqcount_t, xt_recseq); ++EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); ++ + static int xt_jumpstack_alloc(struct xt_table_info *i) + { + unsigned int size; +@@ -1536,6 +1537,7 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++#endif + + #ifdef CONFIG_PROC_FS + static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) +@@ -1919,6 +1921,7 @@ void xt_proto_fini(struct net *net, u_int8_t af) + } + EXPORT_SYMBOL_GPL(xt_proto_fini); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY + /** + * xt_percpu_counter_alloc - allocate x_tables rule counter + * +@@ -1973,6 +1976,7 @@ void xt_percpu_counter_free(struct xt_counters *counters) + free_percpu((void __percpu *)pcnt); + } + EXPORT_SYMBOL_GPL(xt_percpu_counter_free); ++#endif + + static int __net_init xt_net_init(struct net *net) + { +@@ -2005,8 +2009,10 @@ static int __init xt_init(void) + unsigned int i; + int rv; + +- for_each_possible_cpu(i) { +- seqcount_init(&per_cpu(xt_recseq, i)); ++ if (IS_ENABLED(CONFIG_NETFILTER_XTABLES_LEGACY)) { ++ for_each_possible_cpu(i) { ++ seqcount_init(&per_cpu(xt_recseq, i)); ++ } + } + + xt = kcalloc(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-5.15/netfilter-make-legacy-configs-user-selectable.patch b/queue-5.15/netfilter-make-legacy-configs-user-selectable.patch new file mode 100644 index 0000000000..8a6f669d8b --- /dev/null +++ b/queue-5.15/netfilter-make-legacy-configs-user-selectable.patch @@ -0,0 +1,104 @@ +From e983066f4d02bd8479ff37962ed9349f93574cba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 02:58:54 -0700 +Subject: netfilter: Make legacy configs user selectable + +From: Breno Leitao + +[ Upstream commit 6c959fd5e17387201dba3619b2e6af213939a0a7 ] + +This option makes legacy Netfilter Kconfig user selectable, giving users +the option to configure iptables without enabling any other config. + +Make the following KConfig entries user selectable: + * BRIDGE_NF_EBTABLES_LEGACY + * IP_NF_ARPTABLES + * IP_NF_IPTABLES_LEGACY + * IP6_NF_IPTABLES_LEGACY + +Signed-off-by: Breno Leitao +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 8 +++++++- + net/ipv4/netfilter/Kconfig | 16 ++++++++++++++-- + net/ipv6/netfilter/Kconfig | 9 ++++++++- + 3 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 104c0125e32e8..f16bbbbb94817 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -41,7 +41,13 @@ config NF_CONNTRACK_BRIDGE + + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY +- tristate ++ tristate "Legacy EBTABLES support" ++ depends on BRIDGE && NETFILTER_XTABLES ++ default n ++ help ++ Legacy ebtables packet/frame classifier. ++ This is not needed if you are using ebtables over nftables ++ (iptables-nft). + + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index e752a07a871fe..2e540786f9512 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -12,7 +12,13 @@ config NF_DEFRAG_IPV4 + + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP tables support" ++ default n ++ select NETFILTER_XTABLES ++ help ++ iptables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" +@@ -340,7 +346,13 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate ++ tristate "Legacy ARPTABLES support" ++ depends on NETFILTER_XTABLES ++ default n ++ help ++ arptables is a legacy packet classifier. ++ This is not needed if you are using arptables over nftables ++ (iptables-nft). + + config NFT_COMPAT_ARP + tristate +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index bc51a77fb6c07..670d23f926e62 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -8,7 +8,14 @@ menu "IPv6: Netfilter Configuration" + + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP6 tables support" ++ depends on INET && IPV6 ++ select NETFILTER_XTABLES ++ default n ++ help ++ ip6tables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" +-- +2.53.0 + diff --git a/queue-5.15/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-5.15/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..dd9887918e --- /dev/null +++ b/queue-5.15/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From 0b8dcbb3c9796cc883a578108a26c1d423bd8a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 7000e069bc076..66129978c06da 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -72,7 +72,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -781,6 +784,9 @@ static void dump_ipv4_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-5.15/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..75d0e6f4ce --- /dev/null +++ b/queue-5.15/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From 148a6e3ff61e472de11f2a44f7511ec03341afcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 5897f3dbaf7c3..df2022fe440b0 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -310,6 +310,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 8d09bfe850dc3..68f0153531e64 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 79e73fd7d965c..45302640c1ca9 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(struct sk_buff *skb, + const struct nf_hook_state *state, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 564054123772a..9b905c6562313 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1581,15 +1581,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index aee7cd584c926..a2a267e1b2573 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1790,14 +1790,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1952,7 +1944,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 9155c5b5318d7..9dbebfa057ee8 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -68,7 +68,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index f2997709c08b1..b7322b0051a6b 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -95,7 +95,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 226000a740860..e5e30d4e37eb0 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -136,6 +136,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 4749ecc9a416d..77dabf8ff4388 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -61,7 +61,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 3e85be8cc9803..89f8f93b36f64 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -57,7 +57,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index afd22ea9f555b..4fbb6111ed56e 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1797,14 +1797,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1960,7 +1952,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 477982fcc04ae..76b5cb69a54a0 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -68,7 +68,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index bf062c01041ec..387c53da77fd6 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -88,7 +88,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 229a81cf1a729..18d5b39936466 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -138,6 +138,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 6214c0b97f123..a13a3c6298b01 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -60,7 +60,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 36b62f848897a..56057c01ff803 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -56,7 +56,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 30af321d6c964..85155c64d0443 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1537,6 +1537,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-5.15/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-5.15/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..ea542a147d --- /dev/null +++ b/queue-5.15/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From 3963145ebeb346f89bb3b84fa8cda49fbcda2c56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index df2022fe440b0..706f08839050a 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -309,8 +309,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 9b905c6562313..f9dd18244f251 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1583,7 +1582,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index a2a267e1b2573..1829bf3774062 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1705,12 +1705,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1719,6 +1717,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1792,7 +1791,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index e5e30d4e37eb0..d5153736f1d8c 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -126,8 +126,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 4fbb6111ed56e..2b4c3fa5a8d08 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1715,12 +1715,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1729,6 +1727,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1799,7 +1798,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 18d5b39936466..4ba85748bf6d3 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -128,8 +128,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 85155c64d0443..7c87e1a478d68 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1521,23 +1524,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1547,6 +1533,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1556,6 +1550,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1566,6 +1561,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2012,8 +2051,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2022,8 +2063,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-5.15/netfilter-x_tables-unregister-the-templates-first.patch b/queue-5.15/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..79b77c9111 --- /dev/null +++ b/queue-5.15/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From 7b45672199ca02fdd2746585342013f11ab7fe56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 3de78416ec762..771eec4629352 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -90,8 +90,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 0eb0e2ab9bfc4..9155c5b5318d7 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -108,8 +108,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 40417a3f930b2..f2997709c08b1 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -134,8 +134,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 8265c67657053..4749ecc9a416d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -108,9 +108,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index f519162a2fa51..3e85be8cc9803 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -96,9 +96,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 727ee80970124..477982fcc04ae 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -108,8 +108,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 9b518ce37d6ae..bf062c01041ec 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -127,8 +127,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 4f2a04af71d32..6214c0b97f123 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -106,8 +106,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 931674034d8be..36b62f848897a 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -95,8 +95,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xtables-allow-xtables-nft-only-builds.patch b/queue-5.15/netfilter-xtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..c3654e4112 --- /dev/null +++ b/queue-5.15/netfilter-xtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,315 @@ +From e17369ab4c96d368e23e9dacfd7b4054c4fcfa19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:11 +0100 +Subject: netfilter: xtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit a9525c7f6219cee9284c0031c5930e8d41384677 ] + +Add hidden IP(6)_NF_IPTABLES_LEGACY symbol. + +When any of the "old" builtin tables are enabled the "old" iptables +interface will be supported. + +To disable the old set/getsockopt interface the existing options +for the builtin tables need to be turned off: + +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER is not set +CONFIG_IP_NF_NAT is not set +CONFIG_IP_NF_MANGLE is not set +CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_SECURITY is not set + +Same for CONFIG_IP6_NF_ variants. + +This allows to build a kernel that only supports ip(6)tables-nft +(iptables-over-nftables api). + +In the future the _LEGACY symbol will become visible and the select +statements will be turned into 'depends on', but for now be on safe side +so "make oldconfig" won't break things. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 15 ++++++++++++--- + net/ipv4/netfilter/Makefile | 2 +- + net/ipv6/netfilter/Kconfig | 20 ++++++++++++++------ + net/ipv6/netfilter/Makefile | 2 +- + net/netfilter/Kconfig | 12 ++++++------ + 5 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 5c2cdcb19dba3..7c2b8a652016d 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -10,6 +10,10 @@ config NF_DEFRAG_IPV4 + tristate + default n + ++# old sockopt interface and eval loop ++config IP_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" + help +@@ -160,7 +164,7 @@ config IP_NF_MATCH_ECN + config IP_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP_NF_MANGLE || IP_NF_RAW ++ depends on IP_NF_MANGLE || IP_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -181,6 +185,7 @@ config IP_NF_MATCH_TTL + config IP_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -190,7 +195,7 @@ config IP_NF_FILTER + + config IP_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP_NF_FILTER ++ depends on IP_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV4 + default m if NETFILTER_ADVANCED=n + help +@@ -220,6 +225,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT ++ select IP6_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -260,6 +266,7 @@ endif # IP_NF_NAT + config IP_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -283,7 +290,7 @@ config IP_NF_TARGET_CLUSTERIP + + config IP_NF_TARGET_ECN + tristate "ECN target support" +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `ECN' target, which can be used in the iptables mangle +@@ -308,6 +315,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -321,6 +329,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile +index f38fb1368ddb2..d3150ea5b8e57 100644 +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -28,7 +28,7 @@ obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o + obj-$(CONFIG_NF_FLOW_TABLE_IPV4) += nf_flow_table_ipv4.o + + # generic IP tables +-obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o ++obj-$(CONFIG_IP_NF_IPTABLES_LEGACY) += ip_tables.o + + # the three instances of ip_tables + obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index f22233e44ee97..bc51a77fb6c07 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -6,6 +6,10 @@ + menu "IPv6: Netfilter Configuration" + depends on INET && IPV6 && NETFILTER + ++# old sockopt interface and eval loop ++config IP6_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" + help +@@ -155,7 +159,7 @@ config IP6_NF_MATCH_MH + config IP6_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP6_NF_MANGLE || IP6_NF_RAW ++ depends on IP6_NF_MANGLE || IP6_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -194,6 +198,8 @@ config IP6_NF_TARGET_HL + config IP6_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY ++ tristate + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -203,7 +209,7 @@ config IP6_NF_FILTER + + config IP6_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP6_NF_FILTER ++ depends on IP6_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV6 + default m if NETFILTER_ADVANCED=n + help +@@ -229,6 +235,7 @@ config IP6_NF_TARGET_SYNPROXY + config IP6_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -238,6 +245,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -251,6 +259,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -262,6 +271,7 @@ config IP6_NF_NAT + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED + select NF_NAT ++ select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +@@ -270,25 +280,23 @@ config IP6_NF_NAT + + To compile it as a module, choose M here. If unsure, say N. + +-if IP6_NF_NAT +- + config IP6_NF_TARGET_MASQUERADE + tristate "MASQUERADE target support" + select NETFILTER_XT_TARGET_MASQUERADE ++ depends on IP6_NF_NAT + help + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE. + + config IP6_NF_TARGET_NPT + tristate "NPT (Network Prefix translation) target support" ++ depends on IP6_NF_NAT || NFT_COMPAT + help + This option adds the `SNPT' and `DNPT' target, which perform + stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. + + To compile it as a module, choose M here. If unsure, say N. + +-endif # IP6_NF_NAT +- + endif # IP6_NF_IPTABLES + endmenu + +diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile +index b85383606df71..7d0a913529891 100644 +--- a/net/ipv6/netfilter/Makefile ++++ b/net/ipv6/netfilter/Makefile +@@ -4,7 +4,7 @@ + # + + # Link order matters here. +-obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o ++obj-$(CONFIG_IP6_NF_IPTABLES_LEGACY) += ip6_tables.o + obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o + obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o + obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index f02ebe4609650..fdfda4b6bff67 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -812,7 +812,7 @@ config NETFILTER_XT_TARGET_AUDIT + + config NETFILTER_XT_TARGET_CHECKSUM + tristate "CHECKSUM target support" +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `CHECKSUM' target, which can be used in the iptables mangle +@@ -863,7 +863,7 @@ config NETFILTER_XT_TARGET_CONNSECMARK + config NETFILTER_XT_TARGET_CT + tristate '"CT" target support' + depends on NF_CONNTRACK +- depends on IP_NF_RAW || IP6_NF_RAW ++ depends on IP_NF_RAW || IP6_NF_RAW || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This options adds a `CT' target, which allows to specify initial +@@ -874,7 +874,7 @@ config NETFILTER_XT_TARGET_CT + + config NETFILTER_XT_TARGET_DSCP + tristate '"DSCP" and "TOS" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `DSCP' target, which allows you to manipulate +@@ -890,7 +890,7 @@ config NETFILTER_XT_TARGET_DSCP + + config NETFILTER_XT_TARGET_HL + tristate '"HL" hoplimit target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds the "HL" (for IPv6) and "TTL" (for IPv4) +@@ -1074,7 +1074,7 @@ config NETFILTER_XT_TARGET_TPROXY + depends on NETFILTER_ADVANCED + depends on IPV6 || IPV6=n + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + select NF_DEFRAG_IPV4 + select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n + select NF_TPROXY_IPV4 +@@ -1141,7 +1141,7 @@ config NETFILTER_XT_TARGET_TCPMSS + + config NETFILTER_XT_TARGET_TCPOPTSTRIP + tristate '"TCPOPTSTRIP" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a "TCPOPTSTRIP" target, which allows you to strip +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xtables-fix-up-kconfig-dependencies.patch b/queue-5.15/netfilter-xtables-fix-up-kconfig-dependencies.patch new file mode 100644 index 0000000000..7193dfec86 --- /dev/null +++ b/queue-5.15/netfilter-xtables-fix-up-kconfig-dependencies.patch @@ -0,0 +1,58 @@ +From 4b99da24b7b1285688a508891928473c4f73bd94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Feb 2024 14:55:53 +0100 +Subject: netfilter: xtables: fix up kconfig dependencies + +From: Florian Westphal + +[ Upstream commit 749d4ef0868c5d8a98e07073791b2198178c93b4 ] + +Randy Dunlap reports arptables build failure: +arp_tables.c:(.text+0x20): undefined reference to `xt_find_table' + +... because recent change removed a 'select' on the xtables core. +Add a "depends" clause on arptables to resolve this. + +Kernel test robot reports another build breakage: +iptable_nat.c:(.text+0x8): undefined reference to `ipt_unregister_table_exit' + +... because of a typo, the nat table selected ip6tables. + +Reported-by: kernel test robot +Reported-by: Randy Dunlap +Closes: https://lore.kernel.org/netfilter-devel/d0dfbaef-046a-4c42-9daa-53636664bf6d@infradead.org/ +Fixes: a9525c7f6219 ("netfilter: xtables: allow xtables-nft only builds") +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Acked-by: Randy Dunlap +Tested-by: Randy Dunlap # build-tested +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 7c2b8a652016d..18f60e675c438 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -225,7 +225,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP6_NF_IPTABLES_LEGACY ++ select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -351,6 +351,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +-- +2.53.0 + diff --git a/queue-5.15/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-5.15/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..5b3dd85514 --- /dev/null +++ b/queue-5.15/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From f6732f1046718a3059728777393bdba8ada9e565 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index b0aa5cc63b507..c570e8b93bf7c 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1489,6 +1489,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-5.15/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-5.15/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..3ab07dd8b8 --- /dev/null +++ b/queue-5.15/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From a8ea1ddd809005418589f0696db14b1644f0ce5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index acd5be0d36c0c..51cc58bfd1db8 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -422,6 +422,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-5.15/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-5.15/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..d5494a2251 --- /dev/null +++ b/queue-5.15/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 5ae851316041e11c615d8f09c7ceb3fa87bb6a06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 9381655c1ec57..0a78764fdc65e 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3988,3 +3988,4 @@ module_init(nvme_fc_init_module); + module_exit(nvme_fc_exit_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 00c6924bf5f94..b630dbaac3cc4 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2503,3 +2503,4 @@ module_init(nvme_rdma_init_module); + module_exit(nvme_rdma_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 1be8f7867a064..587275d7677dc 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2733,3 +2733,4 @@ module_init(nvme_tcp_init_module); + module_exit(nvme_tcp_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-5.15/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-5.15/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..893003e507 --- /dev/null +++ b/queue-5.15/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From 2d4f30986e6ddea923afe05db17ae951ba5631ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 6c6dc16ab3a62..053b1959de9e6 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3432,6 +3432,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-5.15/nvme-core-fix-parameter-name-in-comment.patch b/queue-5.15/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..fc1ea5c723 --- /dev/null +++ b/queue-5.15/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From 92e5996b9c2ad3ec6e165a22ce856346b3376238 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index f3071bd11fdd3..994cf2e7d8694 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2552,7 +2552,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-5.15/orangefs-validate-getxattr-response-length.patch b/queue-5.15/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..094e6111ec --- /dev/null +++ b/queue-5.15/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From 502f0b00190aba4c809f69d2481f828f2d415587 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index 2d2d16caf9190..f12143db195b5 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-5.15/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-5.15/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..61c1eb2be9 --- /dev/null +++ b/queue-5.15/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From 32ce70b0371bb69e66703f4b72d1da101b0d4972 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index 4042d87d539dd..73d2144e64e8d 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -78,7 +78,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index 0e7c412c52478..6fafce7880c05 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -43,6 +43,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -74,7 +83,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -166,7 +176,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -188,7 +199,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -222,6 +234,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -286,7 +308,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index d2f2a0c761b65..43cc4e6ac75d0 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -71,12 +71,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-5.15/pci-avoid-flr-for-amd-npu-device.patch b/queue-5.15/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..6266cc0627 --- /dev/null +++ b/queue-5.15/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From c8b73f40460d2029ca20d0245c73fce92ea0f0ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index d4a300766cbc3..e27c9b0c22ea1 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5425,6 +5425,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * +@@ -5437,6 +5438,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-5.15/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..74844b53a2 --- /dev/null +++ b/queue-5.15/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From 3c163932b9324a50b54f71569e65feebc65bf714 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 3fd89a983f6d2..b89d7d289b09e 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -42,6 +42,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1411,6 +1412,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-5.15/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-5.15/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..12d786c8f9 --- /dev/null +++ b/queue-5.15/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From c97333afafa9110370ae97061fb42fece6869485 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/gpu/vga/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c +index 569930552957b..27c691a6de555 100644 +--- a/drivers/gpu/vga/vgaarb.c ++++ b/drivers/gpu/vga/vgaarb.c +@@ -1058,6 +1058,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1089,7 +1090,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists... */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-5.15/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-5.15/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..17860b8080 --- /dev/null +++ b/queue-5.15/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From db778e44cdf1bfb0feffae6a2d51ebce54cfe9fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 2b83056029942..2073b52e47cc4 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -427,6 +427,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-5.15/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-5.15/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..b01d6fb1f1 --- /dev/null +++ b/queue-5.15/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From dfaf47a04ae48914a72d501ea12089b63882e2ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 7e41b4842c1f4..604319b2e9002 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1102,6 +1102,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-5.15/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-5.15/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..86ffc9be53 --- /dev/null +++ b/queue-5.15/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From 0b8fda51b03ef2757b744b090a3b2260d7e415b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 71ec8f74f8359..2cf219ae6bbbf 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-5.15/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-5.15/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..a0ea2d2eb7 --- /dev/null +++ b/queue-5.15/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From ef53d0a1e5415857576628b01149d5e77eede1a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 2b76a8695fdbe..ee7731677d273 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3004,12 +3004,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into the + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-5.15/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-5.15/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..1630d8ae6f --- /dev/null +++ b/queue-5.15/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 29c11a7f0c20835b812d6009d1274da58084792c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index d29740be4833e..ad37c0584c23b 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -204,6 +204,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-5.15/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-5.15/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..0400beaf51 --- /dev/null +++ b/queue-5.15/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From e778c661b2b8028db13892899c40d95f543f372b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 4b91e3c9eafa1..3c07b50bd024c 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -26,7 +26,6 @@ + #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MD_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -78,7 +77,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -144,9 +143,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id) + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -154,6 +155,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id) + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-5.15/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-5.15/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..a13c77ee7d --- /dev/null +++ b/queue-5.15/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From 258de04edd690e8048d0bc09101d928654c5334b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-5.15/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-5.15/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..824b1ad038 --- /dev/null +++ b/queue-5.15/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From fbb34c9ae66b9bdcab683398826b340f352840b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 775afea4b2e89..9f64d509f69d0 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1186,6 +1186,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1196,22 +1216,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-5.15/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-5.15/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..c114bbbab8 --- /dev/null +++ b/queue-5.15/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From 975a1461bd695d3210d36ffa84083d77afaba8f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index 97c553182e0c5..9ce26636406c4 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -917,6 +917,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-5.15/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-5.15/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..1ec5396b7e --- /dev/null +++ b/queue-5.15/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 00c5a853362fea49f35a410b51aaad8c9a0a89b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index 45010c77fe3a6..f8a3511dd5947 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -136,6 +136,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + }; +@@ -243,7 +244,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1074,11 +1075,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index 91c8dd1493..ac0e19e49f 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -672,3 +672,156 @@ drm-panfrost-fix-wait_bo-ioctl-leaking-positive-return-from-dma_resv_wait_timeou drm-gma500-oaktrail_hdmi-fix-i2c-adapter-leak-on-setup.patch io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-arp_tables-allow-use-of-arpt_do_table-as-h.patch +netfilter-arptables-allow-xtables-nft-only-builds.patch +netfilter-xtables-allow-xtables-nft-only-builds.patch +netfilter-ebtables-allow-xtables-nft-only-builds.patch +netfilter-xtables-fix-up-kconfig-dependencies.patch +netfilter-arptables-select-netfilter_family_arp-when.patch +netfilter-make-legacy-configs-user-selectable.patch +netfilter-exclude-legacy-tables-on-preempt_rt.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +irqchip-ath79-cpu-remove-unused-function.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +pci-avoid-flr-for-amd-npu-device.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-mark-dax-inode-releases-as-blocking.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-validate-getxattr-response-length.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +iio-abi-fix-current_trigger-description.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +rculist-add-list_splice_rcu-for-private-lists.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-5.15/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-5.15/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..9498008fc9 --- /dev/null +++ b/queue-5.15/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From 71918e92fbb82934bf8fb2f08cb0a9d9949847ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index 0a62720590daf..478a9e2430ef1 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -5079,6 +5079,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + return rc; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + npages = DIV_ROUND_UP(len, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-5.15/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-5.15/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..92f62baada --- /dev/null +++ b/queue-5.15/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From e0a919e22e733d91b58e8e1d3023ae48f05c7be7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 207d578547cd9..b4883c365ba33 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -375,7 +375,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-5.15/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-5.15/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..ced34b797b --- /dev/null +++ b/queue-5.15/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From 36e08f51d30e03cc199060683b88db586ec23d27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 9ebd665e5d427..2618ba9898c31 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-5.15/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-5.15/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..ee9983954f --- /dev/null +++ b/queue-5.15/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From 7f5bd4567db88293e32dd5095b23e534a46b13a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index 412c06bf60362..d99fed07b024f 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -934,7 +934,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-5.15/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-5.15/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..fa296fdebe --- /dev/null +++ b/queue-5.15/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 7b37812fb7ba3593a889873954b3c0cf92586074 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index cd08ffe0d62b0..720c3a937d285 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1483,6 +1483,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1490,7 +1493,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-5.15/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-5.15/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..e243656b8d --- /dev/null +++ b/queue-5.15/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From ca2bde0b4728236c368f42a090d128bc9600affc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index b9ef426d5aae3..d4420a1245ceb 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1389,9 +1389,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1513,8 +1513,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-5.15/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-5.15/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..4b0ff81202 --- /dev/null +++ b/queue-5.15/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From 18fa8e00603a2f38bc7e06daa225c9f1c56e6784 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index 8e2f20b12519d..a74710d62d809 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-5.15/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-5.15/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..054ffaa3af --- /dev/null +++ b/queue-5.15/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From b2868d34a3c7a05d266be1f517e5e4d538b8a41a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index 0bf851f286f2f..4f09ad06269d7 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -588,7 +588,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -596,11 +596,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.15/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-5.15/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..2e7bff2a5e --- /dev/null +++ b/queue-5.15/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From 8da801c1d8d26e92350e89873d866acb13fee850 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index 4f09ad06269d7..edad00feb40d9 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -696,6 +696,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-5.15/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-5.15/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..413fd195a9 --- /dev/null +++ b/queue-5.15/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From a3eda8fa7a1e4eebfc6ca657522a9687a31d3cab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index e604bd759506d..0bf851f286f2f 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -591,7 +591,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -622,14 +622,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-5.15/virtiofs-add-fuse-protocol-validation.patch b/queue-5.15/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..b4b4511ac0 --- /dev/null +++ b/queue-5.15/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From 570fc35b81f84e568e692d97deb413c76ccf1769 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index ba8d5f5dbeb01..c375a5f001056 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -551,6 +551,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -561,10 +582,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct page *page; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -620,6 +637,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-5.15/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-5.15/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..71ba2d0319 --- /dev/null +++ b/queue-5.15/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From d9cdda163a3a54b469e460a40579cd43789d44d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 269e0bf1301a7..08e408b117930 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -1930,10 +1930,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-5.15/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-5.15/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..b421c1bbf4 --- /dev/null +++ b/queue-5.15/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From 9cdcd4dd4b278a2dc633b20d861c38a00ad8a915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index 6ba3a7975e1bf..9cdf7f1838b50 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -521,6 +521,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-5.15/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-5.15/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..6dabb26de6 --- /dev/null +++ b/queue-5.15/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From a9c151e7c93e87cb46a9a18d9ae388a4ae40c911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index a45a0246cab14..db692e928a048 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -326,6 +326,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index 66fe386ec9cc6..d29c8eeff318d 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-5.15/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-5.15/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..bfb7d9c3ea --- /dev/null +++ b/queue-5.15/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From fb0cf39187dcf56758858493262325d551c4375f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index 3a101aa139edf..4f79298803c2c 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -367,7 +367,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + vif = si->vif; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-6.1/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-6.1/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..0a6432ab65 --- /dev/null +++ b/queue-6.1/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From a3ad82fbc190e518fe21c8f6bd0138fec601b840 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index afa3b4ac367a3..b4817ac4e32d1 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1089,6 +1089,8 @@ static int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-6.1/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-6.1/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..b74ce11f27 --- /dev/null +++ b/queue-6.1/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From 49ff35b13c1781422066e98d0f03aaf87eff03b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index b4817ac4e32d1..7c1b5056c5497 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1290,16 +1290,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-6.1/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-6.1/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..79d063f0b8 --- /dev/null +++ b/queue-6.1/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From f6eebd5d515f7140f14b3eecd74a7c5520578b27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index b2bf7016e1b34..287f674b7af17 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -85,6 +85,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-6.1/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-6.1/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..c915eceb4b --- /dev/null +++ b/queue-6.1/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 1c11b00c39e2c2db6f4690edd33b908234ac6d56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 2d0f904aba00f..b94fd198b620e 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -1020,10 +1020,12 @@ static int onyx_i2c_probe(struct i2c_client *client, + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.1/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-6.1/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..9715b9ca75 --- /dev/null +++ b/queue-6.1/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From 0ed95118c17628059c5216c0c5a66d844cb9ad31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index ab89475b7715f..e4d86174a067d 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -908,6 +908,7 @@ static int tas_i2c_probe(struct i2c_client *client, + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.1/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-6.1/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..5a581e4a34 --- /dev/null +++ b/queue-6.1/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 242c125a0b92d622e72aeccb6dcd88722b09399f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index f1140a6bc996d..0a9fd2bbac70e 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -161,6 +161,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %d total %d bytes\n", + tstamp->byte_offset, tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-6.1/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..e85487a356 --- /dev/null +++ b/queue-6.1/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From c23070a32521ffcaccc2c7223a7bfda611092026 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c +index 7b276047f85a7..c897fc443467c 100644 +--- a/sound/hda/hdmi_chmap.c ++++ b/sound/hda/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-6.1/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-6.1/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..693eb02135 --- /dev/null +++ b/queue-6.1/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From 46cf8c21f44c9b46703de1ea90094e672d35dd27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 7be5f25612b95..367c1d102ecd6 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1756,6 +1756,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1768,8 +1771,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-6.1/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-6.1/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..0980c66ead --- /dev/null +++ b/queue-6.1/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From 98253f1bce0173497c28a5b0ea1a32dbf780a281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 21543ed58453b..8faaf06af78e5 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1191,6 +1191,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-6.1/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-6.1/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..0809f301d0 --- /dev/null +++ b/queue-6.1/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From 37232ca18482d4b782e70e887f9d3f23282eeb27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index a395b6c0aae2a..56f6d8327d5c8 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -218,8 +218,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -228,9 +229,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-6.1/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch b/queue-6.1/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch new file mode 100644 index 0000000000..0a3a21a3ea --- /dev/null +++ b/queue-6.1/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch @@ -0,0 +1,47 @@ +From 97f26da3aef4e47cc51a168ebae421864f1a63e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:45:53 +0200 +Subject: ASoC: amd: yc: Add MSI Vector A16 HX A8WHG to quirk table + +From: Ihor Uzlov + +[ Upstream commit 72dcd84938f5026dc44d0e7e1e68d9d571c113a0 ] + +Add the MSI Vector A16 HX A8WHG (board MS-15MM) to the DMI quirk table +to enable DMIC support. This laptop uses an AMD Ryzen 9 7945HX (Dragon +Range) with the ACP6x audio coprocessor (rev 0x62) and a Realtek ALC274 +codec. The built-in digital microphone is connected via the ACP PDM +interface and requires this DMI entry to be activated. + +Tested on MSI Vector A16 HX A8WHG with kernel 6.8.0-107 (Ubuntu 24.04). +DMIC capture device appears as 'acp6x' and records audio correctly. + +Signed-off-by: Ihor Uzlov +Link: https://patch.msgid.link/20260410094553.24654-1-igor.uzlov@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index ab80290e52637..3ad03901773ca 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -395,6 +395,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "83J3"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +-- +2.53.0 + diff --git a/queue-6.1/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-6.1/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..c3bfe2af59 --- /dev/null +++ b/queue-6.1/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From a94b215bdc45ca5a990d8df8838b3daba20e36bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index 4c7ebc7fb4001..e3f63f879cd66 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -853,9 +853,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.1/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-6.1/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..241e2b136f --- /dev/null +++ b/queue-6.1/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From d9182232d58d39e643492a3bdcb2f5dc351b29da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index 6af53a766c27d..1018a4f6e7c6a 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -289,6 +289,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.1/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-6.1/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..50886739ff --- /dev/null +++ b/queue-6.1/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 425ae7e93f97f6bcdd339e513a9d1bad19617bcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index b9990cb1181ff..b68443b61b84d 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -210,6 +210,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.1/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-6.1/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..41107367ae --- /dev/null +++ b/queue-6.1/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From 47a5735a9fe06caa77a7c4f8dcc6d54b96863923 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index ca47f6476b077..494a2b98f9bcc 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-6.1/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch b/queue-6.1/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch new file mode 100644 index 0000000000..3cb0806c49 --- /dev/null +++ b/queue-6.1/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch @@ -0,0 +1,46 @@ +From c6065fe2d3ddc8102733555cb84614f9623c5b1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 13:30:51 +0800 +Subject: ASoC: mxs-sgtl5000: disable MCLK on error paths of + mxs_sgtl5000_probe() + +From: Haoxiang Li + +[ Upstream commit c8ef13d692f19cdbbf195fb845421a5b71801704 ] + +Call mxs_saif_put_mclk() to disable MCLK on error +paths of mxs_sgtl5000_probe(). + +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260401053051.586290-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/mxs/mxs-sgtl5000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c +index 746f409386751..38c2fde2893f5 100644 +--- a/sound/soc/mxs/mxs-sgtl5000.c ++++ b/sound/soc/mxs/mxs-sgtl5000.c +@@ -158,13 +158,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); ++ mxs_saif_put_mclk(0); + return ret; + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) ++ if (ret) { ++ mxs_saif_put_mclk(0); + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-6.1/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..a8461c462d --- /dev/null +++ b/queue-6.1/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From 980c9f695186882a4299cd7e369db46d6e293a83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 3185bf13dc429..ff240bd999777 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1839,6 +1839,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + unsigned int reg_val = 0; + unsigned int pll_bit = 0; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + reg_val |= RT5640_SCLK_SRC_MCLK; +-- +2.53.0 + diff --git a/queue-6.1/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-6.1/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..e9450cb428 --- /dev/null +++ b/queue-6.1/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From 0511fafa5649dc320dba8ad059542a204da5c211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index 7923f9a031ed0..75f7e3242ae06 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -492,7 +492,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -501,7 +501,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -590,7 +590,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { +@@ -615,7 +615,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -628,7 +628,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-6.1/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-6.1/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..c8af85784d --- /dev/null +++ b/queue-6.1/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From 3b4f882e2aa5d6dfb04d6ad016be1d7b55c7384b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index c6ef8f92b25f1..bbde4f08937c5 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2529,6 +2529,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-6.1/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-6.1/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..f5c1e35f5f --- /dev/null +++ b/queue-6.1/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From d908b85f55a916a063e87d7c35102060f0eb8f61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 586982a2a61ff..631e377644aa7 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2828,7 +2828,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-6.1/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..2b6afcfdde --- /dev/null +++ b/queue-6.1/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From a739c3dd05da791398b26f0dcc13b86636d70a48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index de2ea589aa49b..80ed18dfd7e50 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -501,6 +501,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch b/queue-6.1/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch new file mode 100644 index 0000000000..19c1dd33f0 --- /dev/null +++ b/queue-6.1/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch @@ -0,0 +1,40 @@ +From ff995fdf287fb38f179c4d1930b64754810127e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:25:08 +0800 +Subject: Bluetooth: btmtk: improve mt79xx firmware setup retry flow + +From: Chris Lu + +[ Upstream commit 54f1f020e9f4a087779cc4d96a7c86f47d0c6797 ] + +If retries are exhausted, driver should not do futher operation. +During mt79xx firmware download process, if the retry count reaches0, +driver will return an -EIO error and release the firmware resources. + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index b77e337778a44..da222703f8438 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -126,6 +126,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, + } + } + ++ /* If retry exhausted goto err_release_fw */ ++ if (retry == 0) { ++ err = -EIO; ++ goto err_release_fw; ++ } ++ + fw_ptr += section_offset; + wmt_params.op = BTMTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch b/queue-6.1/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch new file mode 100644 index 0000000000..b0bb622103 --- /dev/null +++ b/queue-6.1/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch @@ -0,0 +1,43 @@ +From 31190f368d116db22497d4bbec80928ff8a00249 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:16 +0800 +Subject: Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is + not defined + +From: Shuai Zhang + +[ Upstream commit 7b75867803a8712bdf7683c31d71d3d5e28ce821 ] + +On platforms using an M.2 slot with both UART and USB support, bt_en is +pulled high by hardware. In this case, software-based power control +should be disabled. The current platforms are Lemans-EVK and Monaco-EVK. + +Add QCA_WCN7850 to the existing condition so that power_ctrl_enabled is +cleared when bt_en is not software-controlled (or absent), aligning its +behavior with WCN6750 and WCN6855 + +Signed-off-by: Shuai Zhang +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index fe50aa88d8316..8c749eddb8cad 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2280,7 +2280,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + if (!qcadev->bt_en && + (data->soc_type == QCA_WCN6750 || +- data->soc_type == QCA_WCN6855)) ++ data->soc_type == QCA_WCN6855 || ++ data->soc_type == QCA_WCN7850)) + power_ctrl_enabled = false; + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-6.1/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..ae3439eb19 --- /dev/null +++ b/queue-6.1/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From 55ab5d805c9513504f4c7ee2aad3142b8f1f4070 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 21f63ca434e3f..c19d9bcf7e879 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7708,6 +7708,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); +-- +2.53.0 + diff --git a/queue-6.1/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-6.1/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..648b710b1e --- /dev/null +++ b/queue-6.1/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From 63cef42091c9395daaf8b6cb9f561ce2641c8f3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 6924f86a8a3ff..c081bc0ddf981 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1866,12 +1866,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-6.1/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-6.1/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..da439a4644 --- /dev/null +++ b/queue-6.1/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 597ad2289c251bcbcfdfe6b57ff5d70c57408675 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index fe7aed6c5bdcf..7692709714dc7 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -414,10 +414,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + return avail; +-- +2.53.0 + diff --git a/queue-6.1/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-6.1/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..a9021bdac9 --- /dev/null +++ b/queue-6.1/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From 010c4863dc084ad89d83ad51783b59d22b625c42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index a47c8b4509969..8995da99e5e8b 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -549,6 +549,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-6.1/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-6.1/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..31c573bef1 --- /dev/null +++ b/queue-6.1/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From 884fbc41abd3f5c90dd7434f4dbcbb50e37a6305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 9e966e8876f58..76ab17c9ba8ba 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -262,7 +262,11 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -405,7 +409,11 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1458,7 +1466,11 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-6.1/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-6.1/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..9a9a88e557 --- /dev/null +++ b/queue-6.1/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 946b357b9b55aa9069eb8cd07d2ffa1703118885 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 1f9fbec887c03..60b314640be01 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -2933,7 +2933,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-6.1/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-6.1/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..4a814426b4 --- /dev/null +++ b/queue-6.1/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From 31fc87ce489362b35332aa979babda54ed36531e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 203ff9bbad431..57e3c2c3e5001 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3818,7 +3818,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-6.1/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..f4be9d07cc --- /dev/null +++ b/queue-6.1/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From d8455a9691cfa77462cd5261591f99b78f207e9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 3dc9356b711d5..4fa2b2e374252 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -769,6 +769,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-6.1/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-6.1/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..312c684db9 --- /dev/null +++ b/queue-6.1/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From 7ea0d63887555c9e98a54bd19f44e97574a77edc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index 348eeab0a906b..c495f529f07e1 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -338,13 +338,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-6.1/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-6.1/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..1b2dff3fca --- /dev/null +++ b/queue-6.1/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 88c4b5a7bc07b862682333cd19cefc9eb6066da6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index b23235d58a122..10780dfb7e385 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -2873,6 +2873,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-6.1/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..4a8caddc82 --- /dev/null +++ b/queue-6.1/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From e55f2eeda2125ab6313a2041a835e65d8111cee1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 9c112ab72cbaa..41346dfe2bcab 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1850,3 +1850,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 9c970fb8e5717..0f2fe5987e63a 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -143,6 +143,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e47033fc53106..e6dffe5fee915 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2936,6 +2936,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2952,6 +2955,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3523,7 +3540,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-6.1/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..e8366edd17 --- /dev/null +++ b/queue-6.1/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From b8fb830901c937c240b52e58427c6b2239956a95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index d8982aca8ef68..f0022cf92b420 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1930,7 +1930,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-display-merge-pipes-for-validate.patch b/queue-6.1/drm-amd-display-merge-pipes-for-validate.patch new file mode 100644 index 0000000000..a7a3d2c983 --- /dev/null +++ b/queue-6.1/drm-amd-display-merge-pipes-for-validate.patch @@ -0,0 +1,43 @@ +From 017b4703e3c02af724dd4e164b064423aebbcdae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:48:11 -0500 +Subject: drm/amd/display: Merge pipes for validate + +From: Harry Wentland + +[ Upstream commit 606f6b171326152ef08d0ef0ad49f52034edca07 ] + +Validation expects to operate on non-split pipes. This is +seen in dcn20_fast_validate_bw, which merges pipes for +validation. We weren't doing that in the non-fast path +which lead to validation failures when operating with +4-to-1 MPC and a writeback connector. + +Co-developed by Claude Sonnet 4.5 + +Assisted-by: Claude:claude-sonnet-4.5 +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Harry Wentland +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +index 6c58618f1b9ca..d75f699a01ce2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +@@ -1661,6 +1661,8 @@ noinline bool dcn30_internal_validate_bw( + if (!pipes) + return false; + ++ dcn20_merge_pipes_for_validate(dc, context); ++ + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-6.1/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..8fbf479a10 --- /dev/null +++ b/queue-6.1/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 554b98ea772f5e5d0ca128ed1314d75fa75f7c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 71433aa375d58..f7571597bd0a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1687,6 +1687,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-6.1/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-6.1/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..dc414e6ebe --- /dev/null +++ b/queue-6.1/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From b250be85f0f38fb3235ead965d2740b69bf44bb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 0acfda47f002f..9f78fa068dedc 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -607,6 +607,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -666,6 +681,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -711,30 +728,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch b/queue-6.1/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch new file mode 100644 index 0000000000..a07d83a284 --- /dev/null +++ b/queue-6.1/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch @@ -0,0 +1,60 @@ +From 41e4d4e3e429cf60f0dac545dcb88c4e0002ae08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:17:00 +0100 +Subject: drm/msm/dpu: fix vblank IRQ registration before atomic_mode_set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit 961c900628fef77ad07b4bc4c868e47b9a1269c7 ] + +dpu_encoder_toggle_vblank_for_crtc() can call control_vblank_irq() +at any time in response to a userspace vblank request, independently +of the atomic commit sequence. If this happens before the encoder's +first atomic_mode_set(), irq[INTR_IDX_RDPTR] is still zero. + +Passing irq_idx=0 to dpu_core_irq_register_callback() is treated as +invalid, and DPU_IRQ_REG(0) and DPU_IRQ_BIT(0) produce misleading +values of 134217727 and 31 respectively due to unsigned wraparound +in the (irq_idx - 1) macros, resulting in the confusing error: + + [dpu error]invalid IRQ=[134217727, 31] + +Since irq[INTR_IDX_RDPTR] will be properly populated by +atomic_mode_set() and registered by irq_enable() as part of the +normal modeset sequence, silently skip the vblank IRQ registration +when the index has not yet been initialized. This matches the +existing pattern of the master encoder check above it. + +Signed-off-by: Cédric Bellegarde +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/712752/ +Link: https://lore.kernel.org/r/20260318171700.394945-1-cedric.bellegarde@adishatz.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 7581e418418f1..8274ce776c44c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -252,6 +252,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + ++ /* IRQ not yet initialized */ ++ if (!phys_enc->irq[INTR_IDX_RDPTR]) { ++ ret = -EINVAL; ++ goto end; ++ } ++ + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.1/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-6.1/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..f55ac1e642 --- /dev/null +++ b/queue-6.1/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 69c9e058e6390bd9117cd8cdae565e3991fd3af1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index e9bf3054529f1..5ee19665ef939 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - const: marvell,armada7040 +-- +2.53.0 + diff --git a/queue-6.1/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-6.1/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..13c8692448 --- /dev/null +++ b/queue-6.1/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From 901c8bf0484eec5abffc9f36f85c88a76000e232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 2dc927ba067fe..aa1f88fa94bf5 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -573,6 +573,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-6.1/enic-add-v2-sr-iov-vf-device-id.patch b/queue-6.1/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..81fd7b3379 --- /dev/null +++ b/queue-6.1/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,54 @@ +From 7e8f38a526bdfa267dfcf3dec5a862ef08b62077 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index c76a91f85dac4..cb4809135b6c6 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,6 +66,7 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + #define RX_COPYBREAK_DEFAULT 256 + +@@ -74,6 +75,7 @@ static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -309,7 +311,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-6.1/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-6.1/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..3cba4a783d --- /dev/null +++ b/queue-6.1/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From 75b594c0526c708a995924c66d3ddd183b29bbed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-6.1/exfat-fix-bitwise-operation-having-different-size.patch b/queue-6.1/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..80761484e3 --- /dev/null +++ b/queue-6.1/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 15f8d0fd40e14e06d497f4575325a05770d9bf66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index e651ffb06a438..67b5076ae5ad5 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -263,7 +263,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-6.1/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-6.1/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..5acadb43ba --- /dev/null +++ b/queue-6.1/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From 3671979ec436590a89f720507be23c24239534aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index 3a6d6750dbeb6..f1cdee307b1ea 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -620,7 +620,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-6.1/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-6.1/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..6566665bc9 --- /dev/null +++ b/queue-6.1/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From d28cfa203072ead09af6a6476ee8870492c27f6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index e5362c376a7a5..7ccdd875da20b 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -634,7 +634,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-6.1/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch b/queue-6.1/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch new file mode 100644 index 0000000000..8e6de5181f --- /dev/null +++ b/queue-6.1/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch @@ -0,0 +1,98 @@ +From a253b381f7e51667e81157f19e7c055667574512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:29:14 +0530 +Subject: ext4: unmap invalidated folios from page tables in + mpage_release_unused_pages() + +From: Deepanshu Kartikey + +[ Upstream commit 9b25f381de6b8942645f43735cb0a4fb0ab3a6d1 ] + +When delayed block allocation fails (e.g., due to filesystem corruption +detected in ext4_map_blocks()), the writeback error handler calls +mpage_release_unused_pages(invalidate=true) which invalidates affected +folios by clearing their uptodate flag via folio_clear_uptodate(). + +However, these folios may still be mapped in process page tables. If a +subsequent operation (such as ftruncate calling ext4_block_truncate_page) +triggers a write fault, the existing page table entry allows access to +the now-invalidated folio. This leads to ext4_page_mkwrite() being called +with a non-uptodate folio, which then gets marked dirty, triggering: + + WARNING: CPU: 0 PID: 5 at mm/page-writeback.c:2960 + __folio_mark_dirty+0x578/0x880 + + Call Trace: + fault_dirty_shared_page+0x16e/0x2d0 + do_wp_page+0x38b/0xd20 + handle_pte_fault+0x1da/0x450 + +The sequence leading to this warning is: + +1. Process writes to mmap'd file, folio becomes uptodate and dirty +2. Writeback begins, but delayed allocation fails due to corruption +3. mpage_release_unused_pages(invalidate=true) is called: + - block_invalidate_folio() clears dirty flag + - folio_clear_uptodate() clears uptodate flag + - But folio remains mapped in page tables +4. Later, ftruncate triggers ext4_block_truncate_page() +5. This causes a write fault on the still-mapped folio +6. ext4_page_mkwrite() is called with folio that is !uptodate +7. block_page_mkwrite() marks buffers dirty +8. fault_dirty_shared_page() tries to mark folio dirty +9. block_dirty_folio() calls __folio_mark_dirty(warn=1) +10. WARNING triggers: WARN_ON_ONCE(warn && !uptodate && !dirty) + +Fix this by unmapping folios from page tables before invalidating them +using unmap_mapping_pages(). This ensures that subsequent accesses +trigger new page faults rather than reusing invalidated folios through +stale page table entries. + +Note that this results in data loss for any writes to the mmap'd region +that couldn't be written back, but this is expected behavior when +writeback fails due to filesystem corruption. The existing error message +already states "This should not happen!! Data will be lost". + +Reported-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Tested-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a +Suggested-by: Matthew Wilcox +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20251205055914.1393799-1-kartikey406@gmail.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 2d30d0a9473d6..ae42668d7d2b3 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1640,8 +1640,22 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd, + BUG_ON(!folio_test_locked(folio)); + BUG_ON(folio_test_writeback(folio)); + if (invalidate) { +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { + folio_clear_dirty_for_io(folio); ++ /* ++ * Unmap folio from page ++ * tables to prevent ++ * subsequent accesses through ++ * stale PTEs. This ensures ++ * future accesses trigger new ++ * page faults rather than ++ * reusing the invalidated ++ * folio. ++ */ ++ unmap_mapping_pages(folio->mapping, ++ folio->index, ++ folio_nr_pages(folio), false); ++ } + block_invalidate_folio(folio, 0, + folio_size(folio)); + folio_clear_uptodate(folio); +-- +2.53.0 + diff --git a/queue-6.1/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-6.1/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..839e84d89a --- /dev/null +++ b/queue-6.1/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From fa9fe67ba1811720914c2a43f8338e4de58718c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 687b2ce82c854..5f57066535fb1 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -870,6 +870,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-6.1/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-6.1/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..354ca3b583 --- /dev/null +++ b/queue-6.1/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From 5fa31dbb30aad797f88d05ea121647251542e873 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index 5ccddcfce7228..dc91d10209da2 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1119,7 +1119,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-6.1/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-6.1/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..606b39d939 --- /dev/null +++ b/queue-6.1/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From 02a9c2d54fb1a3555255770c3c6a26a447cac955 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index 78eee242fc992..98a03194d766c 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2323,6 +2323,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-6.1/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-6.1/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..3fde67f27e --- /dev/null +++ b/queue-6.1/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From 0d5609682f9e5a792ce292d8e79adf8b0fe2ac48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index beec5c8d4d083..015577966d031 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-6.1/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-6.1/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..041d1e4870 --- /dev/null +++ b/queue-6.1/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From d55b3f9254e1bb81a55d895dd846f1cfa3733283 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 1fef8a9b1a0fd..7b440835d2971 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-6.1/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-6.1/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..3d61138bc4 --- /dev/null +++ b/queue-6.1/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 796c735a4d24055dbad6b74005458eef7bd47aea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 3e3bf6fdc5ab6..ef56b1487cc7d 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-6.1/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-6.1/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..276e2b21e3 --- /dev/null +++ b/queue-6.1/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From e5d0778034d347979c2918c3e52704fad8b9f559 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index 2e4eea854bda5..98d926c6088c4 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1025,7 +1025,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-6.1/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-6.1/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..57a2c735cc --- /dev/null +++ b/queue-6.1/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From 11e199d934897bd7da5722bfe9f89e90be8671e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 35dd0018e2bd4..cdcb787a7db00 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1303,7 +1303,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-6.1/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..2a1c7dfb0f --- /dev/null +++ b/queue-6.1/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 03083c8c93038cb486f1eedf4aadccc2872da13e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 99bd7a06b2bcb..1223dcf469db6 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-6.1/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-6.1/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..00fa630a03 --- /dev/null +++ b/queue-6.1/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From 3de32a3205988ca939a667413d8d3271b98e7e11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 12c77089d0b4e..061539c2c0539 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -119,6 +119,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-6.1/fuse-validate-outarg-offset-and-size-in-notify-store.patch b/queue-6.1/fuse-validate-outarg-offset-and-size-in-notify-store.patch new file mode 100644 index 0000000000..1ff67b1525 --- /dev/null +++ b/queue-6.1/fuse-validate-outarg-offset-and-size-in-notify-store.patch @@ -0,0 +1,81 @@ +From bd3e74ebc9b5d24884345e0617fd0ae366fe9730 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:44:46 -0800 +Subject: fuse: validate outarg offset and size in notify store/retrieve + +From: Joanne Koong + +[ Upstream commit 65161470f95bb579a72673bf303ecf0800b9054b ] + +Add validation checking for outarg offset and outarg size values passed +in by the server. MAX_LFS_FILESIZE is the maximum file size supported. +The fuse_notify_store_out and fuse_notify_retrieve_out structs take in +a uint64_t offset. + +Add logic to ensure: +* outarg.offset is less than MAX_LFS_FILESIZE +* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE +* potential uint64_t overflow is fixed when adding outarg.offset and + outarg.size. + +Signed-off-by: Joanne Koong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 7e0d4f08a0cf5..d7c1120dc8d6e 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1585,7 +1585,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + if (size - sizeof(outarg) != outarg.size) + goto out_finish; + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + nodeid = outarg.nodeid; ++ num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset); + + down_read(&fc->killsb); + +@@ -1598,13 +1602,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + index = outarg.offset >> PAGE_SHIFT; + offset = outarg.offset & ~PAGE_MASK; + file_size = i_size_read(inode); +- end = outarg.offset + outarg.size; ++ end = outarg.offset + num; + if (end > file_size) { + file_size = end; +- fuse_write_update_attr(inode, file_size, outarg.size); ++ fuse_write_update_attr(inode, file_size, num); + } + +- num = outarg.size; + while (num) { + struct page *page; + unsigned int this_num; +@@ -1682,7 +1685,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, + num = min(outarg->size, fc->max_write); + if (outarg->offset > file_size) + num = 0; +- else if (outarg->offset + num > file_size) ++ else if (num > file_size - outarg->offset) + num = file_size - outarg->offset; + + num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -1758,6 +1761,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, + + fuse_copy_finish(cs); + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + down_read(&fc->killsb); + err = -ENOENT; + nodeid = outarg.nodeid; +-- +2.53.0 + diff --git a/queue-6.1/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-6.1/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..418417ec9b --- /dev/null +++ b/queue-6.1/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 4c93bd9391ac3aed437a590a8293d19e7dbb7921 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 9a4d55f703bb5..f0faac5796bbf 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.1/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-6.1/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..f93c4b9ac8 --- /dev/null +++ b/queue-6.1/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 3fc8650d63b70cddcd8d7405c276571455a3aa06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index 49446a030f108..672f0f5b1ee79 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-6.1/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-6.1/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..9c64672aca --- /dev/null +++ b/queue-6.1/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 6dc3dd2d7a29285f9ea8c460016a55c7ba5026bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 5c79ba1f229c4..6487ff529680e 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -55,7 +55,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.1/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-6.1/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..753e215b3f --- /dev/null +++ b/queue-6.1/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From b69a2f51de664e62f5004e8fe1f385aedfaee2de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 1e9d8262d0ffc..1157417a8b330 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -52,7 +52,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, +-- +2.53.0 + diff --git a/queue-6.1/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-6.1/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..e9314a7c0d --- /dev/null +++ b/queue-6.1/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 34c4b0c890a94e8b7115f343511d93d147fb8107 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index e55d28a8a66f2..a8ab97bf49770 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -283,7 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-6.1/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-6.1/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..c6a7d44fd1 --- /dev/null +++ b/queue-6.1/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From c2655cd73ebf24ccee4d3d7beae4f080145e1f93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 0a36b284de10e..bd6ee99a7160d 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -611,11 +611,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -627,7 +632,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-6.1/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..5b94b41a8f --- /dev/null +++ b/queue-6.1/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From fbbffadf869038c8601e34b865536912b64a8ebe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-6.1/hfsplus-fix-generic-642-failure.patch b/queue-6.1/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..cc39fb2cb2 --- /dev/null +++ b/queue-6.1/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From fa50250171d2045aea1fb240b70183a6970cde15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 1918544a78716..b26cd7504e113 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-6.1/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-6.1/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..d66b34f6eb --- /dev/null +++ b/queue-6.1/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From 19157594d1138197c41e9347d763799055ed9246 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 99fca77d16641..91ce2b6840144 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -222,7 +222,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-6.1/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-6.1/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..a8707115f5 --- /dev/null +++ b/queue-6.1/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From 7ce4c11b1052a8eceed748a72a1070aaf93ce427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 91ce2b6840144..9cbf99c67baa2 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -123,6 +123,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-6.1/hid-uclogic-fix-regression-of-input-name-assignment.patch b/queue-6.1/hid-uclogic-fix-regression-of-input-name-assignment.patch new file mode 100644 index 0000000000..d3a2751934 --- /dev/null +++ b/queue-6.1/hid-uclogic-fix-regression-of-input-name-assignment.patch @@ -0,0 +1,44 @@ +From 8c77776b9ba87b3fdc1bff081566f70b2c0859c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:33:16 +0200 +Subject: HID: uclogic: Fix regression of input name assignment + +From: Takashi Iwai + +[ Upstream commit 487359284509a6745e14b8c0518768bc277809b0 ] + +The previous fix for adding the devm_kasprintf() return check in the +commit bd07f751208b ("HID: uclogic: Add NULL check in +uclogic_input_configured()") changed the condition of hi->input->name +assignment, and it resulted in missing the proper input device name +when no custom suffix is defined. + +Restore the conditional to the original content to address the +regression. + +Fixes: bd07f751208b ("HID: uclogic: Add NULL check in uclogic_input_configured()") +Signed-off-by: Takashi Iwai +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-uclogic-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index 5b35f9f321d41..7658bd678e7e3 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -142,7 +142,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } else { ++ } ++ ++ if (suffix) { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); + if (!hi->input->name) +-- +2.53.0 + diff --git a/queue-6.1/i3c-master-move-bus_init-error-suppression.patch b/queue-6.1/i3c-master-move-bus_init-error-suppression.patch new file mode 100644 index 0000000000..cc4ba78981 --- /dev/null +++ b/queue-6.1/i3c-master-move-bus_init-error-suppression.patch @@ -0,0 +1,98 @@ +From e4f9ed5cbd0da1d767273caacdc40ccfb205e3f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:31 +0100 +Subject: i3c: master: Move bus_init error suppression + +From: Jorge Marques + +[ Upstream commit 49775afa983e3e5ce8e7d00ee241791073be214d ] + +Prepare to fix improper Mx positive error propagation in later commits +by handling Mx error codes where the i3c_ccc_cmd command is allocated. +The CCC DISEC to broadcast address is invoked with +i3c_master_enec_disec_locked() and yields error I3C_ERROR_M2 if there +are no devices active on the bus. This is expected at the bus +initialization stage, where it is not known yet that there are no active +devices on the bus. Add bool suppress_m2 argument to +i3c_master_enec_disec_locked() and update the call site at +i3c_master_bus_init() with the exact corner case to not require +propagating positive Mx error codes. Other call site should not suppress +the error code, for example, if a driver requests to peripheral to +disable events and the transfer is not acknowledged, this is an error +and should not proceed. + +Reviewed-by: Frank Li +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-3-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 74138c499642e..9c6ecb005e186 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -945,7 +945,8 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master) + EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); + + static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, +- u8 addr, bool enable, u8 evts) ++ u8 addr, bool enable, u8 evts, ++ bool suppress_m2) + { + struct i3c_ccc_events *events; + struct i3c_ccc_cmd_dest dest; +@@ -965,6 +966,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + i3c_ccc_cmd_dest_cleanup(&dest); + ++ if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2) ++ ret = 0; ++ + return ret; + } + +@@ -985,7 +989,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, false, evts); ++ return i3c_master_enec_disec_locked(master, addr, false, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + +@@ -1006,7 +1010,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, true, evts); ++ return i3c_master_enec_disec_locked(master, addr, true, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + +@@ -1879,11 +1883,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + +- /* Disable all slave events before starting DAA. */ +- ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, +- I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +- I3C_CCC_EVENT_HJ); +- if (ret && ret != I3C_ERROR_M2) ++ /* ++ * Disable all slave events before starting DAA. When no active device ++ * is on the bus, returns Mx error code M2, this error is ignored. ++ */ ++ ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false, ++ I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | ++ I3C_CCC_EVENT_HJ, true); ++ if (ret) + goto err_bus_cleanup; + + /* +-- +2.53.0 + diff --git a/queue-6.1/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-6.1/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..d163f00189 --- /dev/null +++ b/queue-6.1/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 85abd2f7e697b1074d553a7525e3ce7200f5ae5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index 9aa0437aa598e..cc097207cf97f 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -530,14 +530,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + int ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-6.1/iio-abi-fix-current_trigger-description.patch b/queue-6.1/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..bb220a1c03 --- /dev/null +++ b/queue-6.1/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From 0bbadc609e39996755767b030bcaf6c61f7af6ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index 6ba34c0d97897..32d17c2be6e19 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1300,7 +1300,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-6.1/io_uring-cancel-validate-opcode-for-ioring_async_can.patch b/queue-6.1/io_uring-cancel-validate-opcode-for-ioring_async_can.patch new file mode 100644 index 0000000000..f0596919d8 --- /dev/null +++ b/queue-6.1/io_uring-cancel-validate-opcode-for-ioring_async_can.patch @@ -0,0 +1,53 @@ +From 50134223355b3bd435456f4d5f2989427f143cb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:51:13 +0330 +Subject: io_uring/cancel: validate opcode for IORING_ASYNC_CANCEL_OP + +From: Amir Mohammad Jahangirzad + +[ Upstream commit 85a58309c0d5b5f5a4b65658312ceaf2c34c9bbf ] + +io_async_cancel_prep() reads the opcode selector from sqe->len and +stores it in cancel->opcode, which is an 8-bit field. Since sqe->len +is a 32-bit value, values larger than U8_MAX are implicitly truncated. + +This can cause unintended opcode matches when the truncated value +corresponds to a valid io_uring opcode. For example, submitting a value +such as 0x10b will be truncated to 0x0b (IORING_OP_TIMEOUT), allowing a +cancel request to match operations it did not intend to target. +Validate the opcode value before assigning it to the 8-bit field and +reject values outside the valid io_uring opcode range. + +Signed-off-by: Amir Mohammad Jahangirzad +Link: https://patch.msgid.link/20260331232113.615972-1-a.jahangirzad@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index bfaf8f9f1defc..bc1809c972068 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -145,9 +145,16 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + cancel->fd = READ_ONCE(sqe->fd); + } + if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ u32 op; ++ + if (cancel->flags & IORING_ASYNC_CANCEL_ANY) + return -EINVAL; +- cancel->opcode = READ_ONCE(sqe->len); ++ ++ op = READ_ONCE(sqe->len); ++ if (op >= IORING_OP_LAST) ++ return -EINVAL; ++ ++ cancel->opcode = op; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/ipv4-validate-ipv4_devconf-attributes-properly.patch b/queue-6.1/ipv4-validate-ipv4_devconf-attributes-properly.patch new file mode 100644 index 0000000000..270d2fd185 --- /dev/null +++ b/queue-6.1/ipv4-validate-ipv4_devconf-attributes-properly.patch @@ -0,0 +1,106 @@ +From c8d46f760ca38cf54eda3f47fad5a92fa7f470ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:26:37 +0100 +Subject: ipv4: validate IPV4_DEVCONF attributes properly + +From: Fernando Fernandez Mancera + +[ Upstream commit fa8fca88714c3a4a74f972ed37328e2f0bbef9fa ] + +As the IPV4_DEVCONF netlink attributes are not being validated, it is +possible to use netlink to set read-only values like mc_forwarding. In +addition, valid ranges are not being validated neither but that is less +relevant as they aren't in sysctl. + +To avoid similar situations in the future, define a NLA policy for +IPV4_DEVCONF attributes which are nested in IFLA_INET_CONF. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260312142637.5704-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 55 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index fee0a0b83d27b..f114a7fff4be1 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -1983,12 +1983,50 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { + [IFLA_INET_CONF] = { .type = NLA_NESTED }, + }; + ++static const struct nla_policy inet_devconf_policy[IPV4_DEVCONF_MAX + 1] = { ++ [IPV4_DEVCONF_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MC_FORWARDING] = { .type = NLA_REJECT }, ++ [IPV4_DEVCONF_PROXY_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SECURE_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SEND_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SHARED_MEDIA] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_RP_FILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BOOTP_RELAY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_LOG_MARTIANS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_TAG] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_ARPFILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MEDIUM_ID] = NLA_POLICY_MIN(NLA_S32, -1), ++ [IPV4_DEVCONF_NOXFRM] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_NOPOLICY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_FORCE_IGMP_VERSION] = NLA_POLICY_RANGE(NLA_U32, 0, 3), ++ [IPV4_DEVCONF_ARP_ANNOUNCE] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_IGNORE] = NLA_POLICY_RANGE(NLA_U32, 0, 8), ++ [IPV4_DEVCONF_PROMOTE_SECONDARIES] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_ACCEPT] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_NOTIFY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_LOCAL] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SRC_VMARK] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_PROXY_ARP_PVLAN] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ROUTE_LOCALNET] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BC_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_GRATUITOUS_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_EVICT_NOCARRIER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++}; ++ + static int inet_validate_link_af(const struct net_device *dev, + const struct nlattr *nla, + struct netlink_ext_ack *extack) + { +- struct nlattr *a, *tb[IFLA_INET_MAX+1]; +- int err, rem; ++ struct nlattr *tb[IFLA_INET_MAX + 1], *nested_tb[IPV4_DEVCONF_MAX + 1]; ++ int err; + + if (dev && !__in_dev_get_rtnl(dev)) + return -EAFNOSUPPORT; +@@ -1999,15 +2037,12 @@ static int inet_validate_link_af(const struct net_device *dev, + return err; + + if (tb[IFLA_INET_CONF]) { +- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { +- int cfgid = nla_type(a); ++ err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX, ++ tb[IFLA_INET_CONF], inet_devconf_policy, ++ extack); + +- if (nla_len(a) < 4) +- return -EINVAL; +- +- if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) +- return -EINVAL; +- } ++ if (err < 0) ++ return err; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-6.1/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..f6caaf1d9f --- /dev/null +++ b/queue-6.1/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From 12e36921bfec559d123d66fa5824b0e653cdc42e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index a1a2e785063c3..ad29fa708e9a9 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -60,6 +60,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -428,11 +430,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-6.1/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch b/queue-6.1/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch new file mode 100644 index 0000000000..9d880bf510 --- /dev/null +++ b/queue-6.1/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch @@ -0,0 +1,68 @@ +From 2f04828cca2f37920e67d682b914c0cd3a771c5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:32:29 +0800 +Subject: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 91840be8f710370607f949a627e070896faeddb8 ] + +On PREEMPT_RT, non-HARD irq_work runs in per-CPU kthreads via +run_irq_workd(), so irq_work_sync() uses rcuwait() to wait for BUSY==0. + +After irq_work_single() clears BUSY via atomic_cmpxchg(), it still +dereferences @work for irq_work_is_hard() and rcuwait_wake_up(). + +An irq_work_sync() caller on another CPU that enters after BUSY is cleared +can observe BUSY==0 immediately, return, and free the work before those +accesses complete — causing a use-after-free. + +Fix this by wrapping run_irq_workd() in guard(rcu)() so that the entire +irq_work_single() execution is within an RCU read-side critical +section. Then add synchronize_rcu() in irq_work_sync() after +rcuwait_wait_event() to ensure the caller waits for the RCU grace period +before returning, preventing premature frees. + +Fixes: 810979682ccc ("irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.") +Suggested-by: Sebastian Andrzej Siewior +Suggested-by: Steven Rostedt +Signed-off-by: Jiayuan Chen +Signed-off-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260330073234.303732-1-jiayuan.chen@linux.dev +Signed-off-by: Sasha Levin +--- + kernel/irq_work.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 7afa40fe5cc43..6a286b2681178 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -282,6 +282,12 @@ void irq_work_sync(struct irq_work *work) + !arch_irq_work_has_interrupt()) { + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), + TASK_UNINTERRUPTIBLE); ++ /* ++ * Ensure irq_work_single() does not access @work ++ * after removing IRQ_WORK_BUSY. It is always ++ * accessed within a RCU-read section. ++ */ ++ synchronize_rcu(); + return; + } + +@@ -292,6 +298,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); + + static void run_irq_workd(unsigned int cpu) + { ++ guard(rcu)(); + irq_work_run_list(this_cpu_ptr(&lazy_list)); + } + +-- +2.53.0 + diff --git a/queue-6.1/irqchip-ath79-cpu-remove-unused-function.patch b/queue-6.1/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..352c339e54 --- /dev/null +++ b/queue-6.1/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From 8885608a0085bd7090583ace80aab925550a6407 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-6.1/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-6.1/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..d8411b84df --- /dev/null +++ b/queue-6.1/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From 6d2ada0a75d54cc8cbdfe186e9ad3f2f70b6ec86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index 277f3175477ff..e8b6db6c4e231 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-6.1/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-6.1/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..6402e334c2 --- /dev/null +++ b/queue-6.1/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From 3bdc3b76da80a398d137c83df62005b8478b1b47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 93db6eec44655..8187aaceb7530 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4285,3 +4285,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index 1f2e452a76764..06bada49ab1e9 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-6.1/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-6.1/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..35cec6fb0b --- /dev/null +++ b/queue-6.1/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From 4f957a93a5de1be4c795872def400cd8d78b7ac3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 21d8d4a5c67a1..d0932fd0cbdb4 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -374,11 +374,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-6.1/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-6.1/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..56bcdd8816 --- /dev/null +++ b/queue-6.1/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 82556c2085784233668db88bb07041a4e4ab5a99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 2e8461ce74de6..ec9f2124bc00f 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -182,6 +182,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -294,7 +295,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index 42fb833ef2834..8624da023e28f 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-6.1/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-6.1/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..c4ab9d4d9e --- /dev/null +++ b/queue-6.1/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From 8e1abcd0141f6d07f0718d3577ffe2e2221abe6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 409fa6d92fce1..1ebfad9f6115e 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 805877ce50204..17e0490a24fb0 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 3e8b13e6aa01f..09cf081e985f4 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -97,6 +104,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-6.1/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-6.1/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..adc1c8c405 --- /dev/null +++ b/queue-6.1/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 505931d555f0828d220c291058cd497692cbf6e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 1ebfad9f6115e..bf81af8ac0e0b 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2174,8 +2174,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2190,12 +2188,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2219,8 +2215,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2272,8 +2267,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2284,6 +2277,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2296,9 +2290,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-6.1/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-6.1/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..b8fa158337 --- /dev/null +++ b/queue-6.1/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 9e42e9ff98954fa714466aa087998142a0c37285 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 2a33d54503bae..cd9f3520fef24 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -2816,7 +2816,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -2830,7 +2830,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-6.1/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-6.1/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..620458dc5b --- /dev/null +++ b/queue-6.1/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From ce6732f3f3b2841edaa1d8295ea1d1c6a7baa478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index cd9f3520fef24..5c7c797a1cd6e 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6987,7 +6987,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-6.1/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-6.1/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..4631ad65eb --- /dev/null +++ b/queue-6.1/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From cdb729ee3e4ef57fc07177e2b6a4ebf0671f11aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 626719b95badd..785c2cfc530c2 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-6.1/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-6.1/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..78fb13b351 --- /dev/null +++ b/queue-6.1/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 5d888e935c665a9874008c7c13d2ac280a96dd9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 785c2cfc530c2..49defb2f21b69 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-6.1/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-6.1/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..961dffac8a --- /dev/null +++ b/queue-6.1/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From 2a701634a7deda61b87797b27126dda84f4eec79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index a33a97c2abb65..e04707efd66b7 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-6.1/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-6.1/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..fba551c1fe --- /dev/null +++ b/queue-6.1/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From ff175ae2a0739ce3afb1f1649050f29f20f2aab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 7d63e2f1555a0..37926b4b205af 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -21,6 +21,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -73,9 +80,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -99,16 +105,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-6.1/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-6.1/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..b6204fe70a --- /dev/null +++ b/queue-6.1/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From 95ebdb5927e773b4770cd10dd2db1c1f99917f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 6675ca50259e0..a4060c106bc1b 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -4000,6 +4000,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-6.1/media-au0828-fix-green-screen-in-analog.patch b/queue-6.1/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..5dd0917b1c --- /dev/null +++ b/queue-6.1/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From 376f197e014c606625d70cbcec36e8170624df09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index eb303e94ccebf..27c5e74967a1c 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1675,6 +1675,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1768,8 +1789,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-6.1/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-6.1/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..3ed256bcc0 --- /dev/null +++ b/queue-6.1/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From af5ebe89d13f01283fb3cef621ad78086bcb45f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index c876ea851ed7c..eaafe7be148ce 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -803,9 +803,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-6.1/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-6.1/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..0933cb90ec --- /dev/null +++ b/queue-6.1/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From f785668783485cdee8f890da6e9219c5d254733f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index f1a978af82ef2..4948755d35e42 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-6.1/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch b/queue-6.1/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch new file mode 100644 index 0000000000..265ae07a1f --- /dev/null +++ b/queue-6.1/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch @@ -0,0 +1,111 @@ +From 68d68d773371158ae2c15e4bba18bd898387e1a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 16:50:24 +0100 +Subject: media: dw100: Fix kernel oops with PREEMPT_RT enabled + +From: Stefan Klug + +[ Upstream commit 557ec8cc29ade6c72ea768e59389db08cb7742c9 ] + +On kernels with PREEMPT_RT enabled, a "BUG: scheduling while atomic" +kernel oops occurs inside dw100_irq_handler -> vb2_buffer_done. This is +because vb2_buffer_done takes a spinlock which is not allowed within +interrupt context on PREEMPT_RT. + +The first attempt to fix this was to just drop the IRQF_ONESHOT so that +the interrupt is handled threaded on PREEMPT_RT systems. This introduced +a new issue. The dw100 has an internal timeout counter that is gated by +the DW100_BUS_CTRL_AXI_MASTER_ENABLE bit. Depending on the time it takes +for the threaded handler to run and the geometry of the data being +processed it is possible to reach the timeout resulting in +DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT being set and "dw100 +32e30000.dwe: Interrupt error: 0x1" errors in dmesg. + +To properly fix that, split the interrupt into two halves, reset the +DW100_BUS_CTRL_AXI_MASTER_ENABLE bit in the hard interrupt handler and +do the v4l2 buffer handling in the threaded half. The IRQF_ONESHOT can +still be dropped as the interrupt gets disabled in the hard handler and +will only be reenabled on the next dw100_device_run which will not be +called before the current job has finished. + +Signed-off-by: Stefan Klug +Reviewed-by: Xavier Roumegue +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260304-sklug-v6-16-topic-dw100-v3-1-dev-v5-3-1a7e1f721b50@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/nxp/dw100/dw100.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c +index f6d48c36f3860..49a754ccf82a6 100644 +--- a/drivers/media/platform/nxp/dw100/dw100.c ++++ b/drivers/media/platform/nxp/dw100/dw100.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,7 @@ struct dw100_device { + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; ++ bool frame_failed; + }; + + struct dw100_q_data { +@@ -1396,7 +1398,8 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + { + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; +- bool with_error = true; ++ ++ dw_dev->frame_failed = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; +@@ -1404,7 +1407,7 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); +- with_error = false; ++ dw_dev->frame_failed = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } +@@ -1417,7 +1420,14 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + +- dw100_job_finish(dw_dev, with_error); ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dw100_irq_thread_fn(int irq, void *dev_id) ++{ ++ struct dw100_device *dw_dev = dev_id; ++ ++ dw100_job_finish(dw_dev, dw_dev->frame_failed); + + return IRQ_HANDLED; + } +@@ -1567,8 +1577,9 @@ static int dw100_probe(struct platform_device *pdev) + + pm_runtime_put_sync(&pdev->dev); + +- ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, +- dev_name(&pdev->dev), dw_dev); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, dw100_irq_handler, ++ dw100_irq_thread_fn, 0, ++ dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + return ret; +-- +2.53.0 + diff --git a/queue-6.1/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-6.1/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..04cfe0bc61 --- /dev/null +++ b/queue-6.1/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From 3ad5a5200f2f3f76da177f28feb26ed4c19244af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index bae76023cf71d..467335baea979 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2707,10 +2707,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-6.1/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch b/queue-6.1/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch new file mode 100644 index 0000000000..d5b3f5a52a --- /dev/null +++ b/queue-6.1/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch @@ -0,0 +1,55 @@ +From 5ac47a6404961d29358341e19fb6754fb1b9238c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:32 -0500 +Subject: media: em28xx: remove tuner type from Hauppauge DVB DualHD + +From: Bradford Love + +[ Upstream commit a5dcbff7d50a89bf0376e7f2fb1ba3163a6dac0a ] + +This reverts a patch which was perhaps inadvertently added. + +This was changed during the 5.15-rc4 merge. The faulty commit appears +lost in the pull request somehow, I cannot find it to check the +explanation. + +commit c52e7b855b33 ("Merge tag 'v5.15-rc4' into media_tree") + +There was nothing wrong with this device and no reason to moodify the +board profile. The DVB capabilities are added via dvb_module_probe. +Additionally, the device contains *zero* analog inputs, so I'm not +sure why one was added. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 467335baea979..0776bd07dc051 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2498,17 +2498,12 @@ const struct em28xx_board em28xx_boards[] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, +- .tuner_type = TUNER_SI2157, ++ .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .has_dual_ts = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, +- .input = { { +- .type = EM28XX_VMUX_COMPOSITE, +- .vmux = TVP5150_COMPOSITE1, +- .amux = EM28XX_AMUX_LINE_IN, +- } }, + }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. +-- +2.53.0 + diff --git a/queue-6.1/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch b/queue-6.1/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch new file mode 100644 index 0000000000..47c74a41f4 --- /dev/null +++ b/queue-6.1/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch @@ -0,0 +1,47 @@ +From 9c282f0354ac397313c832e21ce1f5447de7b8c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:18:15 +0800 +Subject: media: i2c: ar0521: Check return value of devm_gpiod_get_optional() + in ar0521_probe() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chen Ni + +[ Upstream commit 46c2891cf12c767de031a248cbb1f96d203bd3f6 ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Acked-by: Krzysztof Hałasa +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ar0521.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c +index 1ede57958410c..06728363b8d75 100644 +--- a/drivers/media/i2c/ar0521.c ++++ b/drivers/media/i2c/ar0521.c +@@ -966,6 +966,9 @@ static int ar0521_probe(struct i2c_client *client) + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(sensor->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), ++ "failed to get reset gpio\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + +-- +2.53.0 + diff --git a/queue-6.1/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-6.1/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..970412622b --- /dev/null +++ b/queue-6.1/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From b053641d5e083bcc1e6cfe23412d02b459add961 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index b69db6fc82618..d4c9816462cc8 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1191,6 +1191,10 @@ static int mt9p031_probe(struct i2c_client *client, + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-6.1/media-pulse8-cec-handle-partial-deinit.patch b/queue-6.1/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..8752a4ad88 --- /dev/null +++ b/queue-6.1/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From 92425a0583698f2ec7f2cd7ec775dbea1edeb9fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 171366fe35443..90b8a968fed77 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-6.1/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-6.1/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..128e5a3064 --- /dev/null +++ b/queue-6.1/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From 2b3bc838908bb6fceba26488a6d7201817265178 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +index c0f1002f4ecf1..09a05e0a95827 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +@@ -172,7 +172,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-6.1/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..f89bd7e4ea --- /dev/null +++ b/queue-6.1/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From a43a8f00578294225d17a12a70b376828d09c9f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + .../media/platform/renesas/vsp1/vsp1_rwpf.c | 28 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 22a82d218152f..44335cb50bbca 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -182,6 +182,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *config; + struct v4l2_mbus_framefmt *format; +@@ -212,18 +214,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-6.1/media-saa7164-fix-rev2-firmware-filename.patch b/queue-6.1/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..b40c5f5616 --- /dev/null +++ b/queue-6.1/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 1104c47cd57a2a5e3040dcd057b948b8aa669286 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index 363689484c54a..c57d56678eb36 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-6.1/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-6.1/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..32f8866c36 --- /dev/null +++ b/queue-6.1/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From afd1d68799de2777e310b180ab38bf3b7e716c2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 75366a30ef612..c643483a7c905 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-6.1/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-6.1/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..4f721206b8 --- /dev/null +++ b/queue-6.1/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From 260921c109461d5e0c02d6acca62c5e3407fec58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 8157df4570d19..75366a30ef612 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -572,8 +572,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-6.1/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-6.1/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..bfa8b7263c --- /dev/null +++ b/queue-6.1/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From 0266bdf88cabb21761c91ac3ab47562b22fff5f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index 06be28b361f1a..571d11eddcbf7 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -447,9 +447,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-6.1/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch b/queue-6.1/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch new file mode 100644 index 0000000000..3e89865718 --- /dev/null +++ b/queue-6.1/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch @@ -0,0 +1,62 @@ +From 286f121d78fd5253b55a75ce7925740d78f63fdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 16:35:00 -0800 +Subject: memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5 + +From: Florian Fainelli + +[ Upstream commit a969a0835152984a0f556434eafdee0b84213670 ] + +The same limitations that apply to LPDDR4 also apply to LPDDR5. Expand +the check and rename accordingly. + +Signed-off-by: Florian Fainelli +Link: https://patch.msgid.link/20260122003501.1191059-1-florian.fainelli@broadcom.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/brcmstb_memc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c +index 233a53f5bce1f..89ea41bd4fc89 100644 +--- a/drivers/memory/brcmstb_memc.c ++++ b/drivers/memory/brcmstb_memc.c +@@ -13,6 +13,7 @@ + + #define REG_MEMC_CNTRLR_CONFIG 0x00 + #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 ++#define CNTRLR_CONFIG_LPDDR5_SHIFT 6 + #define CNTRLR_CONFIG_MASK 0xf + #define REG_MEMC_SRPD_CFG_21 0x20 + #define REG_MEMC_SRPD_CFG_20 0x34 +@@ -33,14 +34,15 @@ struct brcmstb_memc { + u32 srpd_offset; + }; + +-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc) ++static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc) + { + void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG; + u32 reg; + + reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK; + +- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT; ++ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT || ++ reg == CNTRLR_CONFIG_LPDDR5_SHIFT; + } + + static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc, +@@ -94,7 +96,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr, + * dynamic tuning process will also get affected by the inactivity + * timeout, thus making it non functional. + */ +- if (brcmstb_memc_uses_lpddr4(memc)) ++ if (brcmstb_memc_uses_lpddr45(memc)) + return -EOPNOTSUPP; + + ret = kstrtouint(buf, 10, &val); +-- +2.53.0 + diff --git a/queue-6.1/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch b/queue-6.1/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch new file mode 100644 index 0000000000..b71757bedc --- /dev/null +++ b/queue-6.1/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch @@ -0,0 +1,64 @@ +From e30eb2b9b99f7adb29fa3974b986a386227afd83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:35:52 +0800 +Subject: mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus + width + +From: Luke Wang + +[ Upstream commit e98f926e5a2d8023a74ec2ba7a973b5d76610f4e ] + +UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers +that lack relevant capability registers rely on paring properties provided +by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() +has been introduced to validate such configuration violations, let's also +add checks for UHS/DDR/HS200 modes. + +This fixes an issue where, if the HS200/HS400 property is set while only +a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually +performing the mode switch. Consequently, mmc_select_timing() proceeds +without falling back to mmc_select_hs(), leaving the eMMC device operating +in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). + +Signed-off-by: Luke Wang +[Shawn: reword the commit msg and rework the code] +Signed-off-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/host.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 67230d486c283..acccdb4254c95 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -597,12 +597,24 @@ static int mmc_validate_host_caps(struct mmc_host *host) + return -EINVAL; + } + ++ /* UHS/DDR/HS200 modes require at least 4-bit bus */ ++ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) && ++ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) { ++ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n"); ++ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR); ++ caps2 &= ~MMC_CAP2_HS200; ++ } ++ ++ /* HS400 and HS400ES modes require 8-bit bus */ + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); +- host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; ++ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400); + } + ++ host->caps = caps; ++ host->caps2 = caps2; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/module-override-eexist-module-return.patch b/queue-6.1/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..72c78076a0 --- /dev/null +++ b/queue-6.1/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From 922f9daac7962718d09e0e3d2d730f03384ec31b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index e83e84f699ded..43e58ddb4f1c1 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -2477,6 +2477,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-6.1/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-6.1/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..7d880613b1 --- /dev/null +++ b/queue-6.1/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From 0b5e906e7725d1a9b08d8684e34e011e322b33c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 87a252b13c5cf..eb2ed0dc9e85f 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7008,7 +7008,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-6.1/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-6.1/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..184a22ef79 --- /dev/null +++ b/queue-6.1/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From 6c9a820be93f3578bc376a2ff4df05b52f913646 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 51108bf65845d..3f0e63c7342bd 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1449,6 +1450,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1462,7 +1464,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1502,6 +1503,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1512,6 +1514,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1546,6 +1549,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1554,6 +1558,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1563,6 +1568,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1892,6 +1898,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.1/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-6.1/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..50d7329bc3 --- /dev/null +++ b/queue-6.1/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From ce32edfae26f8846611ba83bb4a5ce76fb086396 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index dbfcbdb8d751a..51108bf65845d 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1498,6 +1498,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-6.1/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-6.1/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..f7660f0708 --- /dev/null +++ b/queue-6.1/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From 1ad3d6bec7ee56bc61ee4986b6eed56f18f7d5e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 729a69007ec47..dbfcbdb8d751a 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -121,6 +121,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1447,10 +1449,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1504,6 +1506,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1554,6 +1557,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1882,6 +1886,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.1/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-6.1/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..95448bf068 --- /dev/null +++ b/queue-6.1/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From 7fc5ad48b2c6c8228f598b30a6df58c82f8a8ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index 06a0c00af99c7..75ab9b9668172 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1270,7 +1270,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1297,7 +1296,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-6.1/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-6.1/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..e15c8f45b0 --- /dev/null +++ b/queue-6.1/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From d1c1b649d51da2213d59e69858fd42165328d731 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index fe9d1461f6ea6..1f74e77250630 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2190,6 +2190,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* Stop PTP Clock driver */ + if (info->gptp) +-- +2.53.0 + diff --git a/queue-6.1/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-6.1/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..288417415f --- /dev/null +++ b/queue-6.1/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From 5c5854c0f48e58aa5bd790649b235ef7a756dee4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 83a16d10eedbc..a0c5215a12aa5 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -207,6 +207,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-6.1/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-6.1/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..a2c8756582 --- /dev/null +++ b/queue-6.1/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From a9fea792559cfd67f98a445d75eb65deb3119657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index a9184a78650b0..46073afb1874a 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1908,6 +1908,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-6.1/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-6.1/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..1b882df852 --- /dev/null +++ b/queue-6.1/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From 37f4bc1a78af8fe2a8e8330cb39b22067caba1e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 6c178b4742666..705390fdb2267 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2354,6 +2354,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + sk_refcnt_debug_inc(newsk); + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-6.1/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch b/queue-6.1/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch new file mode 100644 index 0000000000..8117f5d2d9 --- /dev/null +++ b/queue-6.1/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch @@ -0,0 +1,82 @@ +From 61e337e7c8828b6271b74dc37baf0e54df86a394 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 12:02:28 +0530 +Subject: net: lan743x: fix SGMII detection on PCI1xxxx B0+ during warm reset + +From: Thangaraj Samynathan + +[ Upstream commit e783e40fb689381caca31e03d28c39e10c82e722 ] + +A warm reset on boards using an EEPROM-only strap configuration (where +no MAC address is set in the image) can cause the driver to incorrectly +revert to RGMII mode. This occurs because the ENET_CONFIG_LOAD_STARTED +bit may not persist or behave as expected. + +Update pci11x1x_strap_get_status() to use revision-specific validation: + +- For PCI11x1x A0: Continue using the legacy check (config load started + or reset protection) to validate the SGMII strap. +- For PCI11x1x B0 and later: Use the newly available + STRAP_READ_USE_SGMII_EN_ bit in the upper strap register to validate + the lower SGMII_EN bit. + +This ensures the SGMII interface is correctly identified even after a +warm reboot. + +Signed-off-by: Thangaraj Samynathan +Link: https://patch.msgid.link/20260318063228.17110-1-thangaraj.s@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 15 +++++++++++---- + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 5dacc786db455..5fcc6f2890508 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -27,6 +27,12 @@ + + #define RFE_RD_FIFO_TH_3_DWORDS 0x3 + ++static bool pci11x1x_is_a0(struct lan743x_adapter *adapter) ++{ ++ u32 dev_rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_; ++ return dev_rev == ID_REV_CHIP_REV_PCI11X1X_A0_; ++} ++ + static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + { + u32 chip_rev; +@@ -46,10 +52,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); + lan743x_hs_syslock_release(adapter); + hw_cfg = lan743x_csr_read(adapter, HW_CFG); +- +- if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || +- hw_cfg & HW_CFG_RST_PROTECT_) { +- strap = lan743x_csr_read(adapter, STRAP_READ); ++ strap = lan743x_csr_read(adapter, STRAP_READ); ++ if ((pci11x1x_is_a0(adapter) && ++ (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || ++ hw_cfg & HW_CFG_RST_PROTECT_)) || ++ (strap & STRAP_READ_USE_SGMII_EN_)) { + if (strap & STRAP_READ_SGMII_EN_) + adapter->is_sgmii_en = true; + else +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index c0d209f36188a..2048480946229 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -26,6 +26,7 @@ + #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) + #define ID_REV_CHIP_REV_A0_ (0x00000000) + #define ID_REV_CHIP_REV_B0_ (0x00000010) ++#define ID_REV_CHIP_REV_PCI11X1X_A0_ (0x000000A0) + #define ID_REV_CHIP_REV_PCI11X1X_B0_ (0x000000B0) + + #define FPGA_REV (0x04) +-- +2.53.0 + diff --git a/queue-6.1/net-lan966x-avoid-unregistering-netdev-on-register-f.patch b/queue-6.1/net-lan966x-avoid-unregistering-netdev-on-register-f.patch new file mode 100644 index 0000000000..14ca84f5a8 --- /dev/null +++ b/queue-6.1/net-lan966x-avoid-unregistering-netdev-on-register-f.patch @@ -0,0 +1,65 @@ +From a6a354aaf33cb4522c7da82cf4545282900c3627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 21:43:11 +0900 +Subject: net: lan966x: avoid unregistering netdev on register failure + +From: Myeonghun Pak + +[ Upstream commit c4f3d6eb1fcf6cd9ce4644f604d5aad1ce594dfc ] + +lan966x_probe_port() stores the newly allocated net_device in the +port before calling register_netdev(). If register_netdev() fails, +the probe error path calls lan966x_cleanup_ports(), which sees +port->dev and calls unregister_netdev() for a device that was never +registered. + +Destroy the phylink instance created for this port and clear port->dev +before returning the registration error. The common cleanup path now skips +ports without port->dev before reaching the registered netdev cleanup, so +it only handles ports that reached the registered-netdev lifetime. + +This also avoids treating an uninitialized FDMA netdev and the failed port +as a NULL == NULL match in the common cleanup path. + +Fixes: d28d6d2e37d1 ("net: lan966x: add port module support") +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260506124331.31945-1-mhun512@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index 8c048ffde23d6..8347def40f9d4 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -688,11 +688,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) + + for (p = 0; p < lan966x->num_phys_ports; p++) { + port = lan966x->ports[p]; +- if (!port) ++ if (!port || !port->dev) + continue; + +- if (port->dev) +- unregister_netdev(port->dev); ++ unregister_netdev(port->dev); + + if (lan966x->fdma && lan966x->fdma_ndev == port->dev) + lan966x_fdma_netdev_deinit(lan966x, port->dev); +@@ -805,6 +804,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, + err = register_netdev(dev); + if (err) { + dev_err(lan966x->dev, "register_netdev failed\n"); ++ phylink_destroy(phylink); ++ port->phylink = NULL; ++ port->dev = NULL; + return err; + } + +-- +2.53.0 + diff --git a/queue-6.1/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch b/queue-6.1/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch new file mode 100644 index 0000000000..2a4e045eb8 --- /dev/null +++ b/queue-6.1/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch @@ -0,0 +1,41 @@ +From dc895ef140d34f03256616a8a3746441b6a1c353 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:09:23 +0300 +Subject: net/mlx5e: XSK, Increase size for chunk_size param + +From: Dragos Tatulea + +[ Upstream commit 1047e14b44edecbbab02a86514a083b8db9fde4d ] + +When 64K pages are used, chunk_size can take the 64K value +which doesn't fit in u16. This results in overflows that +are detected in mlx5e_mpwrq_log_wqe_sz(). + +Increase the type to u32 to fix this. + +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260403090927.139042-2-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/params.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +index 034debd140bce..ade74908c1da5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +@@ -8,7 +8,7 @@ + + struct mlx5e_xsk_param { + u16 headroom; +- u16 chunk_size; ++ u32 chunk_size; + bool unaligned; + }; + +-- +2.53.0 + diff --git a/queue-6.1/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-6.1/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..2ba7f15c6d --- /dev/null +++ b/queue-6.1/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From bf10f60c12f81058caf6a667035acfa10bba2dc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index eb4ebaa1c92ff..80b461cbbf88d 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5526,6 +5526,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5655,6 +5657,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-6.1/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-6.1/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..afb2952bdd --- /dev/null +++ b/queue-6.1/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From bdaec512845574ed4ab342c821cc4309b9ee88fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index 3831eb25e240a..50eb4340b2733 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -359,7 +359,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -460,7 +460,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-6.1/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-6.1/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..d2a22685b4 --- /dev/null +++ b/queue-6.1/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 4379f7e24afb34d11aa639ba5c1d54dcaf5b533a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 7caae93937ee9..0b272eaa88739 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -270,6 +270,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch b/queue-6.1/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch new file mode 100644 index 0000000000..455967962d --- /dev/null +++ b/queue-6.1/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch @@ -0,0 +1,58 @@ +From f84aac19690afd5be9e848ac7fa156314bc79476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 20:39:16 +0800 +Subject: net: sched: cls_u32: Avoid memcpy() false-positive warning in + u32_init_knode() + +From: Jiayuan Chen + +[ Upstream commit 34bd3c6b0bd383a76d987c8c45c4f309b681b255 ] + +Syzbot reported a warning in u32_init_knode() [1]. + +Similar to commit 7cba18332e36 ("net: sched: cls_u32: Avoid memcpy() +false-positive warning") which addressed the same issue in u32_change(), +use unsafe_memcpy() in u32_init_knode() to work around the compiler's +inability to see into composite flexible array structs. + +This silences the false-positive reported by syzbot: + + memcpy: detected field-spanning write (size 32) of single field + "&new->sel" at net/sched/cls_u32.c:855 (size 16) + +Since the memory is correctly allocated with kzalloc_flex() using +s->nkeys, this is purely a false positive and does not need a Fixes tag. + +[1] https://syzkaller.appspot.com/bug?extid=d5ace703ed883df56e42 + +Reported-by: syzbot+d5ace703ed883df56e42@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69a811b9.a70a0220.b118c.0019.GAE@google.com/T/ +Reviewed-by: Simon Horman +Acked-by: Gustavo A. R. Silva +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260309123917.402183-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_u32.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 5e85a8bf21237..4eb9cfff0b7a7 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -850,7 +850,10 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, + /* Similarly success statistics must be moved as pointers */ + new->pcpu_success = n->pcpu_success; + #endif +- memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); ++ unsafe_memcpy(&new->sel, s, struct_size(s, keys, s->nkeys), ++ /* A composite flex-array structure destination, ++ * which was correctly sized with kzalloc_flex(), ++ * above. */); + + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { + kfree(new); +-- +2.53.0 + diff --git a/queue-6.1/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch b/queue-6.1/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch new file mode 100644 index 0000000000..e2c37c2121 --- /dev/null +++ b/queue-6.1/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch @@ -0,0 +1,65 @@ +From c7fbf908a8a961aa918e5dba5aa3bd45164edf94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 15:26:40 -0700 +Subject: net/smc: avoid NULL deref of conn->lnk in smc_msg_event tracepoint + +From: Xiang Mei + +[ Upstream commit 7bf563badd37cb796df5477d2b78bb64148a1268 ] + +The smc_msg_event tracepoint class, shared by smc_tx_sendmsg and +smc_rx_recvmsg, unconditionally dereferences smc->conn.lnk: + + __string(name, smc->conn.lnk->ibname) + +conn->lnk is only set for SMC-R; for SMC-D it is NULL. Other code on +these paths already handles this (e.g. !conn->lnk in +SMC_STAT_RMB_TX_SIZE_SMALL()). With the tracepoint enabled, the first +sendmsg()/recvmsg() on an SMC-D socket crashes: + + Oops: general protection fault, probably for non-canonical address + KASAN: null-ptr-deref in range [...] + RIP: 0010:strlen+0x1e/0xa0 + Call Trace: + trace_event_raw_event_smc_msg_event (net/smc/smc_tracepoint.h:44) + smc_rx_recvmsg (net/smc/smc_rx.c:515) + smc_recvmsg (net/smc/af_smc.c:2859) + __sys_recvfrom (net/socket.c:2315) + __x64_sys_recvfrom (net/socket.c:2326) + do_syscall_64 + +The faulting address 0x3e0 is offsetof(struct smc_link, ibname), +confirming the NULL ->lnk deref. Enabling the tracepoint requires +root, but the trigger itself is unprivileged: socket(AF_SMC, ...) has +no capability check, and SMC-D negotiation needs no admin step on +s390 or on x86 with the loopback ISM device loaded. + +Log an empty device name for SMC-D instead of dereferencing NULL. + +Fixes: aff3083f10bf ("net/smc: Introduce tracepoints for tx and rx msg") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Dust Li +Reviewed-by: Sidraya Jayagond +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/smc_tracepoint.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/smc/smc_tracepoint.h b/net/smc/smc_tracepoint.h +index 9fc5e586d24ab..380451912c4f1 100644 +--- a/net/smc/smc_tracepoint.h ++++ b/net/smc/smc_tracepoint.h +@@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(smc_msg_event, + __field(const void *, smc) + __field(u64, net_cookie) + __field(size_t, len) +- __string(name, smc->conn.lnk->ibname) ++ __string(name, smc->conn.lnk ? smc->conn.lnk->ibname : "") + ), + + TP_fast_assign( +-- +2.53.0 + diff --git a/queue-6.1/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch b/queue-6.1/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch new file mode 100644 index 0000000000..21562a3b64 --- /dev/null +++ b/queue-6.1/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch @@ -0,0 +1,63 @@ +From 9dd9eedc74293d208bd3cac02ddf7ad34ee4108e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 23:21:38 -0700 +Subject: net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot + +From: Xiang Mei + +[ Upstream commit 277740023def559a4a2ddc3e8e784ee37a0f16a9 ] + +On the SMC-D client, slot 0 of ini->ism_dev[]/ini->ism_chid[] is +reserved for an SMC-Dv1 device. smc_find_ism_v2_device_clnt() +populates V2 entries starting at index 1, so when no V1 device is +selected slot 0 is left in its kzalloc()'ed state with ism_dev[0] == +NULL and ism_chid[0] == 0. + +smc_v2_determine_accepted_chid() then matches the peer's CHID against +the array starting from index 0 using the CHID alone. A malicious +peer replying to a SMC-Dv2-only proposal with d1.chid == 0 matches +the empty slot, ini->ism_selected becomes 0, and the subsequent +ism_dev[0]->lgr_lock dereference in smc_conn_create() faults at +offsetof(struct smcd_dev, lgr_lock) == 0x68: + + BUG: KASAN: null-ptr-deref in _raw_spin_lock_bh+0x79/0xe0 + Write of size 4 at addr 0000000000000068 by task exploit/144 + Call Trace: + _raw_spin_lock_bh + smc_conn_create (net/smc/smc_core.c:1997) + __smc_connect (net/smc/af_smc.c:1447) + smc_connect (net/smc/af_smc.c:1720) + __sys_connect + __x64_sys_connect + do_syscall_64 + +Require ism_dev[i] to be non-NULL before accepting a CHID match. + +Fixes: a7c9c5f4af7f ("net/smc: CLC accept / confirm V2") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260511062138.2839584-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index a609b220b215d..b0f8eca077b89 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1346,7 +1346,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm_v2 *aclc, + int i; + + for (i = 0; i < ini->ism_offered_cnt + 1; i++) { +- if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) { ++ if (ini->ism_dev[i] && ++ ini->ism_chid[i] == ntohs(aclc->d1.chid)) { + ini->ism_selected = i; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-6.1/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..2f5f188e90 --- /dev/null +++ b/queue-6.1/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 3d645848b8804d0405124258954d5aec6ea44e79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index ef7dda0915d33..a46f3cc4b3f14 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -801,11 +801,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-6.1/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-6.1/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..87e6899e4b --- /dev/null +++ b/queue-6.1/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From 025a05a065745e2336b8d10eff23c204ad347532 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index a46f3cc4b3f14..de85e26d9675d 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -790,21 +790,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-arptables-allow-xtables-nft-only-builds.patch b/queue-6.1/netfilter-arptables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..5f8d84aed1 --- /dev/null +++ b/queue-6.1/netfilter-arptables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,82 @@ +From d12ec130f6e0eee21d2eb7ba270bd526edfa1fa1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Jan 2024 16:42:48 +0100 +Subject: netfilter: arptables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 4654467dc7e111e84f43ed1b70322873ae77e7be ] + +Allows to build kernel that supports the arptables mangle target +via nftables' compat infra but without the arptables get/setsockopt +interface or the old arptables filter interpreter. + +IOW, setting IP_NF_ARPFILTER=n will break arptables-legacy, but +arptables-nft will continue to work as long as nftables compat +support is enabled. + +Signed-off-by: Florian Westphal +Reviewed-by: Phil Sutter +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index aab384126f61f..483778f379d44 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -323,36 +323,34 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate "ARP tables support" +- select NETFILTER_XTABLES +- select NETFILTER_FAMILY_ARP +- depends on NETFILTER_ADVANCED +- help +- arptables is a general, extensible packet identification framework. +- The ARP packet filtering and mangling (manipulation)subsystems +- use this: say Y or M here if you want to use either of those. +- +- To compile it as a module, choose M here. If unsure, say N. ++ tristate + +-if IP_NF_ARPTABLES ++config NFT_COMPAT_ARP ++ tristate ++ depends on NF_TABLES_ARP && NFT_COMPAT ++ default m if NFT_COMPAT=m ++ default y if NFT_COMPAT=y + + config IP_NF_ARPFILTER +- tristate "ARP packet filtering" ++ tristate "arptables-legacy packet filtering support" ++ select IP_NF_ARPTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +- local output. On a bridge, you can also specify filtering rules +- for forwarded ARP packets. See the man page for arptables(8). ++ local output. This is only needed for arptables-legacy(8). ++ Neither arptables-nft nor nftables need this to work. + + To compile it as a module, choose M here. If unsure, say N. + + config IP_NF_ARP_MANGLE + tristate "ARP payload mangling" ++ depends on IP_NF_ARPTABLES || NFT_COMPAT_ARP + help + Allows altering the ARP packet payload: source and destination + hardware and network addresses. + +-endif # IP_NF_ARPTABLES ++ This option is needed by both arptables-legacy and arptables-nft. ++ It is not used by nftables. + + endmenu + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-arptables-select-netfilter_family_arp-when.patch b/queue-6.1/netfilter-arptables-select-netfilter_family_arp-when.patch new file mode 100644 index 0000000000..8919fb7005 --- /dev/null +++ b/queue-6.1/netfilter-arptables-select-netfilter_family_arp-when.patch @@ -0,0 +1,112 @@ +From 5be487a50a8ab0aa6b959e3600dbe3ce3210fcd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Mar 2024 21:15:52 -0700 +Subject: netfilter: arptables: Select NETFILTER_FAMILY_ARP when building + arp_tables.c + +From: Kuniyuki Iwashima + +[ Upstream commit 15fba562f7a9f04322b8bfc8f392e04bb93d81be ] + +syzkaller started to report a warning below [0] after consuming the +commit 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only +builds"). + +The change accidentally removed the dependency on NETFILTER_FAMILY_ARP +from IP_NF_ARPTABLES. + +If NF_TABLES_ARP is not enabled on Kconfig, NETFILTER_FAMILY_ARP will +be removed and some code necessary for arptables will not be compiled. + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + CONFIG_NETFILTER_FAMILY_ARP=y + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + + $ make olddefconfig + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + +So, when nf_register_net_hooks() is called for arptables, it will +trigger the splat below. + +Now IP_NF_ARPTABLES is only enabled by IP_NF_ARPFILTER, so let's +restore the dependency on NETFILTER_FAMILY_ARP in IP_NF_ARPFILTER. + +[0]: +WARNING: CPU: 0 PID: 242 at net/netfilter/core.c:316 nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Modules linked in: +CPU: 0 PID: 242 Comm: syz-executor.0 Not tainted 6.8.0-12821-g537c2e91d354 #10 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 +RIP: 0010:nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Code: 83 fd 04 0f 87 bc 00 00 00 e8 5b 84 83 fd 4d 8d ac ec a8 0b 00 00 e8 4e 84 83 fd 4c 89 e8 5b 5d 41 5c 41 5d c3 e8 3f 84 83 fd <0f> 0b e8 38 84 83 fd 45 31 ed 5b 5d 4c 89 e8 41 5c 41 5d c3 e8 26 +RSP: 0018:ffffc90000b8f6e8 EFLAGS: 00010293 +RAX: 0000000000000000 RBX: 0000000000000003 RCX: ffffffff83c42164 +RDX: ffff888106851180 RSI: ffffffff83c42321 RDI: 0000000000000005 +RBP: 0000000000000000 R08: 0000000000000005 R09: 000000000000000a +R10: 0000000000000003 R11: ffff8881055c2f00 R12: ffff888112b78000 +R13: 0000000000000000 R14: ffff8881055c2f00 R15: ffff8881055c2f00 +FS: 00007f377bd78800(0000) GS:ffff88811b000000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000496068 CR3: 000000011298b003 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + __nf_register_net_hook+0xcd/0x7a0 net/netfilter/core.c:428 + nf_register_net_hook+0x116/0x170 net/netfilter/core.c:578 + nf_register_net_hooks+0x5d/0xc0 net/netfilter/core.c:594 + arpt_register_table+0x250/0x420 net/ipv4/netfilter/arp_tables.c:1553 + arptable_filter_table_init+0x41/0x60 net/ipv4/netfilter/arptable_filter.c:39 + xt_find_table_lock+0x2e9/0x4b0 net/netfilter/x_tables.c:1260 + xt_request_find_table_lock+0x2b/0xe0 net/netfilter/x_tables.c:1285 + get_info+0x169/0x5c0 net/ipv4/netfilter/arp_tables.c:808 + do_arpt_get_ctl+0x3f9/0x830 net/ipv4/netfilter/arp_tables.c:1444 + nf_getsockopt+0x76/0xd0 net/netfilter/nf_sockopt.c:116 + ip_getsockopt+0x17d/0x1c0 net/ipv4/ip_sockglue.c:1777 + tcp_getsockopt+0x99/0x100 net/ipv4/tcp.c:4373 + do_sock_getsockopt+0x279/0x360 net/socket.c:2373 + __sys_getsockopt+0x115/0x1e0 net/socket.c:2402 + __do_sys_getsockopt net/socket.c:2412 [inline] + __se_sys_getsockopt net/socket.c:2409 [inline] + __x64_sys_getsockopt+0xbd/0x150 net/socket.c:2409 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0x4f/0x110 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x46/0x4e +RIP: 0033:0x7f377beca6fe +Code: 1f 44 00 00 48 8b 15 01 97 0a 00 f7 d8 64 89 02 b8 ff ff ff ff eb b8 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 37 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 0a c3 66 0f 1f 84 00 00 00 00 00 48 8b 15 c9 +RSP: 002b:00000000005df728 EFLAGS: 00000246 ORIG_RAX: 0000000000000037 +RAX: ffffffffffffffda RBX: 00000000004966e0 RCX: 00007f377beca6fe +RDX: 0000000000000060 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 000000000042938a R08: 00000000005df73c R09: 00000000005df800 +R10: 00000000004966e8 R11: 0000000000000246 R12: 0000000000000003 +R13: 0000000000496068 R14: 0000000000000003 R15: 00000000004bc9d8 + + +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Reported-by: syzkaller +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Simon Horman +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 0f60a740d117d..6146ef5fc728f 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -343,6 +343,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ select NETFILTER_FAMILY_ARP + depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of +-- +2.53.0 + diff --git a/queue-6.1/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-6.1/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..087516c7a5 --- /dev/null +++ b/queue-6.1/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From 65bfc47888ee6edad1ee573743f1de8db45954d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index ec286e54229b7..ca426e49ea1a1 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2583,19 +2583,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-ebtables-allow-xtables-nft-only-builds.patch b/queue-6.1/netfilter-ebtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..c1d249ef62 --- /dev/null +++ b/queue-6.1/netfilter-ebtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,84 @@ +From a912777fab4eafeaa0372ecfe671648bd5b6737b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:12 +0100 +Subject: netfilter: ebtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 7ad269787b6615ca56bb161063331991fce51abf ] + +Same patch as previous one, but for ebtables. + +To build a kernel that only supports ebtables-nft, the builtin tables +need to be disabled, i.e.: + +CONFIG_BRIDGE_EBT_BROUTE=n +CONFIG_BRIDGE_EBT_T_FILTER=n +CONFIG_BRIDGE_EBT_T_NAT=n + +The ebtables specific extensions can then be used nftables' +NFT_COMPAT interface. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 7 +++++++ + net/bridge/netfilter/Makefile | 2 +- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 7f304a19ac1bf..104c0125e32e8 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -39,6 +39,10 @@ config NF_CONNTRACK_BRIDGE + + To compile it as a module, choose M here. If unsure, say N. + ++# old sockopt interface and eval loop ++config BRIDGE_NF_EBTABLES_LEGACY ++ tristate ++ + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" + depends on BRIDGE && NETFILTER && NETFILTER_XTABLES +@@ -55,6 +59,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -65,6 +70,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -74,6 +80,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile +index 1c9ce49ab6513..b9a1303da9771 100644 +--- a/net/bridge/netfilter/Makefile ++++ b/net/bridge/netfilter/Makefile +@@ -9,7 +9,7 @@ obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o + # connection tracking + obj-$(CONFIG_NF_CONNTRACK_BRIDGE) += nf_conntrack_bridge.o + +-obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o ++obj-$(CONFIG_BRIDGE_NF_EBTABLES_LEGACY) += ebtables.o + + # tables + obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o +-- +2.53.0 + diff --git a/queue-6.1/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-6.1/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..589a758a2f --- /dev/null +++ b/queue-6.1/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From 57f82e014da400ce9ff0638a2a8e4869199e6ade Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 33d8640d21ac1..43c808e525e87 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index fdb988c24916a..f76d45dfe9b46 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -93,18 +93,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 8b981b2041b5d..af0732e2f889d 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -93,16 +93,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.1/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-6.1/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..41efd871e5 --- /dev/null +++ b/queue-6.1/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From ec055d46ccc78c6593e79e95401f030ac955d9c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 8f19253024b0a..33d8640d21ac1 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 278f324e67524..fdb988c24916a 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 9066f7f376d57..8b981b2041b5d 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index f99e348c8f37f..ec286e54229b7 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2556,11 +2560,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-exclude-legacy-tables-on-preempt_rt.patch b/queue-6.1/netfilter-exclude-legacy-tables-on-preempt_rt.patch new file mode 100644 index 0000000000..d5e0855be9 --- /dev/null +++ b/queue-6.1/netfilter-exclude-legacy-tables-on-preempt_rt.patch @@ -0,0 +1,335 @@ +From 0f5ee0030fa111de255bd9dd9152c5dbed0b1b21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Jun 2025 17:44:23 +0200 +Subject: netfilter: Exclude LEGACY TABLES on PREEMPT_RT. + +From: Pablo Neira Ayuso + +[ Upstream commit 9fce66583f06c212e95e4b76dd61d8432ffa56b6 ] + +The seqcount xt_recseq is used to synchronize the replacement of +xt_table::private in xt_replace_table() against all readers such as +ipt_do_table() + +To ensure that there is only one writer, the writing side disables +bottom halves. The sequence counter can be acquired recursively. Only the +first invocation modifies the sequence counter (signaling that a writer +is in progress) while the following (recursive) writer does not modify +the counter. +The lack of a proper locking mechanism for the sequence counter can lead +to live lock on PREEMPT_RT if the high prior reader preempts the +writer. Additionally if the per-CPU lock on PREEMPT_RT is removed from +local_bh_disable() then there is no synchronisation for the per-CPU +sequence counter. + +The affected code is "just" the legacy netfilter code which is replaced +by "netfilter tables". That code can be disabled without sacrificing +functionality because everything is provided by the newer +implementation. This will only requires the usage of the "-nft" tools +instead of the "-legacy" ones. +The long term plan is to remove the legacy code so lets accelerate the +progress. + +Relax dependencies on iptables legacy, replace select with depends on, +this should cause no harm to existing kernel configs and users can still +toggle IP{6}_NF_IPTABLES_LEGACY in any case. +Make EBTABLES_LEGACY, IPTABLES_LEGACY and ARPTABLES depend on +NETFILTER_XTABLES_LEGACY. Hide xt_recseq and its users, +xt_register_table() and xt_percpu_counter_alloc() behind +NETFILTER_XTABLES_LEGACY. Let NETFILTER_XTABLES_LEGACY depend on +!PREEMPT_RT. + +This will break selftest expecing the legacy options enabled and will be +addressed in a following patch. + +Co-developed-by: Florian Westphal +Co-developed-by: Sebastian Andrzej Siewior +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 10 +++++----- + net/ipv4/netfilter/Kconfig | 24 ++++++++++++------------ + net/ipv6/netfilter/Kconfig | 19 +++++++++---------- + net/netfilter/Kconfig | 10 ++++++++++ + net/netfilter/x_tables.c | 16 +++++++++++----- + 5 files changed, 47 insertions(+), 32 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index f16bbbbb94817..60f28e4fb5c0a 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -42,8 +42,8 @@ config NF_CONNTRACK_BRIDGE + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY + tristate "Legacy EBTABLES support" +- depends on BRIDGE && NETFILTER_XTABLES +- default n ++ depends on BRIDGE && NETFILTER_XTABLES_LEGACY ++ default n + help + Legacy ebtables packet/frame classifier. + This is not needed if you are using ebtables over nftables +@@ -65,7 +65,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -76,7 +76,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -86,7 +86,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 1d0a89a67acf5..ffb1f193a8bd5 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -13,8 +13,8 @@ config NF_DEFRAG_IPV4 + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY + tristate "Legacy IP tables support" +- default n +- select NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + iptables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -182,8 +182,8 @@ config IP_NF_MATCH_TTL + # `filter', generic and specific targets + config IP_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -220,10 +220,10 @@ config IP_NF_TARGET_SYNPROXY + config IP_NF_NAT + tristate "iptables NAT support" + depends on NF_CONNTRACK ++ depends on IP_NF_IPTABLES_LEGACY + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -263,8 +263,8 @@ endif # IP_NF_NAT + # mangle + specific targets + config IP_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -313,7 +313,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -327,7 +327,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -339,8 +339,8 @@ endif # IP_NF_IPTABLES + # ARP tables + config IP_NF_ARPTABLES + tristate "Legacy ARPTABLES support" +- depends on NETFILTER_XTABLES +- default n ++ depends on NETFILTER_XTABLES_LEGACY ++ default n + help + arptables is a legacy packet classifier. + This is not needed if you are using arptables over nftables +@@ -356,7 +356,7 @@ config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES + select NETFILTER_FAMILY_ARP +- depends on NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index e087a8e97ba78..276860f65baae 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -9,9 +9,8 @@ menu "IPv6: Netfilter Configuration" + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY + tristate "Legacy IP6 tables support" +- depends on INET && IPV6 +- select NETFILTER_XTABLES +- default n ++ depends on INET && IPV6 && NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + ip6tables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -196,8 +195,8 @@ config IP6_NF_TARGET_HL + + config IP6_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + tristate + help + Packet filtering defines a table `filter', which has a series of +@@ -233,8 +232,8 @@ config IP6_NF_TARGET_SYNPROXY + + config IP6_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -244,7 +243,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -258,7 +257,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -269,8 +268,8 @@ config IP6_NF_NAT + tristate "ip6tables NAT support" + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED ++ depends on IP6_NF_IPTABLES_LEGACY + select NF_NAT +- select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 344c287aa3f41..4937f32bcd6e7 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -760,6 +760,16 @@ config NETFILTER_XTABLES_COMPAT + + If unsure, say N. + ++config NETFILTER_XTABLES_LEGACY ++ bool "Netfilter legacy tables support" ++ depends on !PREEMPT_RT ++ help ++ Say Y here if you still require support for legacy tables. This is ++ required by the legacy tools (iptables-legacy) and is not needed if ++ you use iptables over nftables (iptables-nft). ++ Legacy support is not limited to IP, it also includes EBTABLES and ++ ARPTABLES. ++ + comment "Xtables combined modules" + + config NETFILTER_XT_MARK +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 650cb725ba271..be786cd704508 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1339,12 +1339,13 @@ void xt_compat_unlock(u_int8_t af) + EXPORT_SYMBOL_GPL(xt_compat_unlock); + #endif + +-DEFINE_PER_CPU(seqcount_t, xt_recseq); +-EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); +- + struct static_key xt_tee_enabled __read_mostly; + EXPORT_SYMBOL_GPL(xt_tee_enabled); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY ++DEFINE_PER_CPU(seqcount_t, xt_recseq); ++EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); ++ + static int xt_jumpstack_alloc(struct xt_table_info *i) + { + unsigned int size; +@@ -1536,6 +1537,7 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++#endif + + #ifdef CONFIG_PROC_FS + static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) +@@ -1919,6 +1921,7 @@ void xt_proto_fini(struct net *net, u_int8_t af) + } + EXPORT_SYMBOL_GPL(xt_proto_fini); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY + /** + * xt_percpu_counter_alloc - allocate x_tables rule counter + * +@@ -1973,6 +1976,7 @@ void xt_percpu_counter_free(struct xt_counters *counters) + free_percpu((void __percpu *)pcnt); + } + EXPORT_SYMBOL_GPL(xt_percpu_counter_free); ++#endif + + static int __net_init xt_net_init(struct net *net) + { +@@ -2005,8 +2009,10 @@ static int __init xt_init(void) + unsigned int i; + int rv; + +- for_each_possible_cpu(i) { +- seqcount_init(&per_cpu(xt_recseq, i)); ++ if (IS_ENABLED(CONFIG_NETFILTER_XTABLES_LEGACY)) { ++ for_each_possible_cpu(i) { ++ seqcount_init(&per_cpu(xt_recseq, i)); ++ } + } + + xt = kcalloc(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-6.1/netfilter-make-legacy-configs-user-selectable.patch b/queue-6.1/netfilter-make-legacy-configs-user-selectable.patch new file mode 100644 index 0000000000..3cf83660ae --- /dev/null +++ b/queue-6.1/netfilter-make-legacy-configs-user-selectable.patch @@ -0,0 +1,104 @@ +From beaccc6625231c38327827f7fe021aae40489f18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 02:58:54 -0700 +Subject: netfilter: Make legacy configs user selectable + +From: Breno Leitao + +[ Upstream commit 6c959fd5e17387201dba3619b2e6af213939a0a7 ] + +This option makes legacy Netfilter Kconfig user selectable, giving users +the option to configure iptables without enabling any other config. + +Make the following KConfig entries user selectable: + * BRIDGE_NF_EBTABLES_LEGACY + * IP_NF_ARPTABLES + * IP_NF_IPTABLES_LEGACY + * IP6_NF_IPTABLES_LEGACY + +Signed-off-by: Breno Leitao +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 8 +++++++- + net/ipv4/netfilter/Kconfig | 16 ++++++++++++++-- + net/ipv6/netfilter/Kconfig | 9 ++++++++- + 3 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 104c0125e32e8..f16bbbbb94817 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -41,7 +41,13 @@ config NF_CONNTRACK_BRIDGE + + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY +- tristate ++ tristate "Legacy EBTABLES support" ++ depends on BRIDGE && NETFILTER_XTABLES ++ default n ++ help ++ Legacy ebtables packet/frame classifier. ++ This is not needed if you are using ebtables over nftables ++ (iptables-nft). + + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 6146ef5fc728f..1d0a89a67acf5 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -12,7 +12,13 @@ config NF_DEFRAG_IPV4 + + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP tables support" ++ default n ++ select NETFILTER_XTABLES ++ help ++ iptables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" +@@ -332,7 +338,13 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate ++ tristate "Legacy ARPTABLES support" ++ depends on NETFILTER_XTABLES ++ default n ++ help ++ arptables is a legacy packet classifier. ++ This is not needed if you are using arptables over nftables ++ (iptables-nft). + + config NFT_COMPAT_ARP + tristate +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index f3c8e2d918e13..e087a8e97ba78 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -8,7 +8,14 @@ menu "IPv6: Netfilter Configuration" + + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP6 tables support" ++ depends on INET && IPV6 ++ select NETFILTER_XTABLES ++ default n ++ help ++ ip6tables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" +-- +2.53.0 + diff --git a/queue-6.1/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-6.1/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..6a7c1412db --- /dev/null +++ b/queue-6.1/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From d8e532f9f92d34b309969940aae6d337bd39b806 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e8..c593113557333 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -78,7 +78,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -787,6 +790,9 @@ static void dump_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-6.1/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..213a835b87 --- /dev/null +++ b/queue-6.1/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From 454dd5e33dde014123b80c50dfbdcaac9e7f878a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 5897f3dbaf7c3..df2022fe440b0 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -310,6 +310,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 132b0e4a6d4df..13593391d6058 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 8b8885a73c764..c6d5b927830dd 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 564054123772a..9b905c6562313 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1581,15 +1581,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index a6208efcfccfc..7c6b21f8174a3 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1791,14 +1791,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1953,7 +1945,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index c03c1a4ea7cab..fb85745793ba5 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -61,7 +61,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 6a51e61b35562..6259bcf178bba 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -95,7 +95,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 12ca666d6e2c1..ca6964b957ead 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -129,6 +129,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 33330e13ea18d..c7b91b2042dc6 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -53,7 +53,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 2b89adc1e5751..81175c20ccbe8 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -50,7 +50,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index b844e519da1b4..1324413fb29c3 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1797,14 +1797,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1960,7 +1952,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 16a38d56b2e54..982900920e730 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -60,7 +60,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 39f0716667131..475361aa81310 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -88,7 +88,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 52d597b16b658..bef2d309369bc 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -131,6 +131,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 01def8aa7a2e8..a99879f173b4a 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -52,7 +52,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 66018b169b010..c44834d93fc79 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -49,7 +49,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index be786cd704508..6a4bca66a0ae6 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1537,6 +1537,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-6.1/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-6.1/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..b5290d144b --- /dev/null +++ b/queue-6.1/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From 719819d16db14d4f8696812c440586c4a7ba82b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index df2022fe440b0..706f08839050a 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -309,8 +309,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 9b905c6562313..f9dd18244f251 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1583,7 +1582,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 7c6b21f8174a3..0ff9b7c9dc59c 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1706,12 +1706,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1720,6 +1718,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1793,7 +1792,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index ca6964b957ead..87d934b12bcb6 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -119,8 +119,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 1324413fb29c3..baa1c094faf48 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1715,12 +1715,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1729,6 +1727,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1799,7 +1798,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index bef2d309369bc..cf260d8ebdb70 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -121,8 +121,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 6a4bca66a0ae6..cba2b8d2f9069 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1521,23 +1524,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1547,6 +1533,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1556,6 +1550,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1566,6 +1561,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2012,8 +2051,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2022,8 +2063,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-6.1/netfilter-x_tables-close-dangling-table-module-init-.patch b/queue-6.1/netfilter-x_tables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..08e0fef5c7 --- /dev/null +++ b/queue-6.1/netfilter-x_tables-close-dangling-table-module-init-.patch @@ -0,0 +1,406 @@ +From 5aa837f85a2c12d5c9167824e94a141d64c1467c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:20 +0200 +Subject: netfilter: x_tables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 16bc4b6686b2c112c10e67d6b493adc3607256d3 ] + +Similar to the previous ebtables patch: +template add exposes the table to userspace, we must do this last to +rnsure the pernet ops are set up (contain the destructors). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_mangle.c | 25 +++++++++++++------------ + net/ipv4/netfilter/iptable_raw.c | 22 +++++++++++----------- + net/ipv4/netfilter/iptable_security.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_filter.c | 22 +++++++++++----------- + net/ipv6/netfilter/ip6table_mangle.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_raw.c | 20 ++++++++++---------- + net/ipv6/netfilter/ip6table_security.c | 23 ++++++++++++----------- + 9 files changed, 105 insertions(+), 99 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 382345567a600..370b635e3523b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = { + + static int __init arptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- arptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); +- if (IS_ERR(arpfilter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(arpfilter_ops)) + return PTR_ERR(arpfilter_ops); +- } + + ret = register_pernet_subsys(&arptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ arptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(arpfilter_ops); +- return ret; ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(arpfilter_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index fb85745793ba5..409e96c72164b 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = { + + static int __init iptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- iptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&iptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ iptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_filter_net_ops); ++ goto err_free; + } + + return 0; ++err_free: ++ kfree(filter_ops); ++ return ret; + } + + static void __exit iptable_filter_fini(void) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 6259bcf178bba..b8618bdf5fdc4 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -110,25 +110,26 @@ static struct pernet_operations iptable_mangle_net_ops = { + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); +- ret = PTR_ERR(mangle_ops); +- return ret; +- } ++ if (IS_ERR(mangle_ops)) ++ return PTR_ERR(mangle_ops); + + ret = register_pernet_subsys(&iptable_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ iptable_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index c7b91b2042dc6..94ad7fad3a1f3 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, +- iptable_raw_table_init); +- if (ret < 0) +- return ret; +- + rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&iptable_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ++ iptable_raw_table_init); + if (ret < 0) { +- xt_unregister_template(table); +- kfree(rawtable_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 81175c20ccbe8..491894511c544 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = { + + static int __init iptable_security_init(void) + { +- int ret = xt_register_template(&security_table, +- iptable_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&iptable_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ iptable_security_table_init); + if (ret < 0) { +- xt_unregister_template(&security_table); +- kfree(sectbl_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 982900920e730..f444071346859 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = { + + static int __init ip6table_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- ip6table_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&ip6table_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ip6table_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(filter_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 475361aa81310..dbc64e4428403 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -103,25 +103,26 @@ static struct pernet_operations ip6table_mangle_net_ops = { + + static int __init ip6table_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- ip6table_mangle_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); ++ if (IS_ERR(mangle_ops)) + return PTR_ERR(mangle_ops); +- } + + ret = register_pernet_subsys(&ip6table_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ ip6table_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index a99879f173b4a..1eadf553c746e 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, ip6table_raw_table_init); +- if (ret < 0) +- return ret; +- + /* Register hooks */ + rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&ip6table_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ip6table_raw_table_init); + if (ret < 0) { +- kfree(rawtable_ops); +- xt_unregister_template(table); +- return ret; ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index c44834d93fc79..4bd5d97b8ab65 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = { + + static int __init ip6table_security_init(void) + { +- int ret = xt_register_template(&security_table, +- ip6table_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&ip6table_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ ip6table_security_table_init); + if (ret < 0) { +- kfree(sectbl_ops); +- xt_unregister_template(&security_table); +- return ret; ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-x_tables-unregister-the-templates-first.patch b/queue-6.1/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..c038e9e995 --- /dev/null +++ b/queue-6.1/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From cb9c35aca507cfc5742178c7b47de3fa7f269d19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 78cd5ee24448f..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -82,8 +82,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index b9062f4552ace..c03c1a4ea7cab 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -101,8 +101,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 3abb430af9e6f..6a51e61b35562 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -134,8 +134,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index ca5e5b21587cd..33330e13ea18d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -100,9 +100,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index d885443cb2679..2b89adc1e5751 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -89,9 +89,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index df785ebda0ca4..16a38d56b2e54 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -100,8 +100,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index a88b2ce4a3cb8..39f0716667131 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -127,8 +127,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 08861d5d1f4db..01def8aa7a2e8 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -98,8 +98,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 4df14a9bae782..66018b169b010 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -88,8 +88,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xtables-allow-xtables-nft-only-builds.patch b/queue-6.1/netfilter-xtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..e48303c31d --- /dev/null +++ b/queue-6.1/netfilter-xtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,315 @@ +From ec158547a2473d41bc985b1446022cc4b30b7318 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:11 +0100 +Subject: netfilter: xtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit a9525c7f6219cee9284c0031c5930e8d41384677 ] + +Add hidden IP(6)_NF_IPTABLES_LEGACY symbol. + +When any of the "old" builtin tables are enabled the "old" iptables +interface will be supported. + +To disable the old set/getsockopt interface the existing options +for the builtin tables need to be turned off: + +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER is not set +CONFIG_IP_NF_NAT is not set +CONFIG_IP_NF_MANGLE is not set +CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_SECURITY is not set + +Same for CONFIG_IP6_NF_ variants. + +This allows to build a kernel that only supports ip(6)tables-nft +(iptables-over-nftables api). + +In the future the _LEGACY symbol will become visible and the select +statements will be turned into 'depends on', but for now be on safe side +so "make oldconfig" won't break things. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 15 ++++++++++++--- + net/ipv4/netfilter/Makefile | 2 +- + net/ipv6/netfilter/Kconfig | 20 ++++++++++++++------ + net/ipv6/netfilter/Makefile | 2 +- + net/netfilter/Kconfig | 12 ++++++------ + 5 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 483778f379d44..5ee86c7ae4dcb 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -10,6 +10,10 @@ config NF_DEFRAG_IPV4 + tristate + default n + ++# old sockopt interface and eval loop ++config IP_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" + help +@@ -152,7 +156,7 @@ config IP_NF_MATCH_ECN + config IP_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP_NF_MANGLE || IP_NF_RAW ++ depends on IP_NF_MANGLE || IP_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -173,6 +177,7 @@ config IP_NF_MATCH_TTL + config IP_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -182,7 +187,7 @@ config IP_NF_FILTER + + config IP_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP_NF_FILTER ++ depends on IP_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV4 + default m if NETFILTER_ADVANCED=n + help +@@ -212,6 +217,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT ++ select IP6_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -252,6 +258,7 @@ endif # IP_NF_NAT + config IP_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -275,7 +282,7 @@ config IP_NF_TARGET_CLUSTERIP + + config IP_NF_TARGET_ECN + tristate "ECN target support" +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `ECN' target, which can be used in the iptables mangle +@@ -300,6 +307,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -313,6 +321,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile +index 93bad11842517..2e606a13ee5ff 100644 +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -25,7 +25,7 @@ obj-$(CONFIG_NFT_FIB_IPV4) += nft_fib_ipv4.o + obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o + + # generic IP tables +-obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o ++obj-$(CONFIG_IP_NF_IPTABLES_LEGACY) += ip_tables.o + + # the three instances of ip_tables + obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index 0ba62f4868f97..f3c8e2d918e13 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -6,6 +6,10 @@ + menu "IPv6: Netfilter Configuration" + depends on INET && IPV6 && NETFILTER + ++# old sockopt interface and eval loop ++config IP6_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" + help +@@ -147,7 +151,7 @@ config IP6_NF_MATCH_MH + config IP6_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP6_NF_MANGLE || IP6_NF_RAW ++ depends on IP6_NF_MANGLE || IP6_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -186,6 +190,8 @@ config IP6_NF_TARGET_HL + config IP6_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY ++ tristate + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -195,7 +201,7 @@ config IP6_NF_FILTER + + config IP6_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP6_NF_FILTER ++ depends on IP6_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV6 + default m if NETFILTER_ADVANCED=n + help +@@ -221,6 +227,7 @@ config IP6_NF_TARGET_SYNPROXY + config IP6_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -230,6 +237,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -243,6 +251,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -254,6 +263,7 @@ config IP6_NF_NAT + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED + select NF_NAT ++ select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +@@ -262,25 +272,23 @@ config IP6_NF_NAT + + To compile it as a module, choose M here. If unsure, say N. + +-if IP6_NF_NAT +- + config IP6_NF_TARGET_MASQUERADE + tristate "MASQUERADE target support" + select NETFILTER_XT_TARGET_MASQUERADE ++ depends on IP6_NF_NAT + help + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE. + + config IP6_NF_TARGET_NPT + tristate "NPT (Network Prefix translation) target support" ++ depends on IP6_NF_NAT || NFT_COMPAT + help + This option adds the `SNPT' and `DNPT' target, which perform + stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. + + To compile it as a module, choose M here. If unsure, say N. + +-endif # IP6_NF_NAT +- + endif # IP6_NF_IPTABLES + endmenu + +diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile +index b8d6dc9aeeb6f..66ce6fa5b2f52 100644 +--- a/net/ipv6/netfilter/Makefile ++++ b/net/ipv6/netfilter/Makefile +@@ -4,7 +4,7 @@ + # + + # Link order matters here. +-obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o ++obj-$(CONFIG_IP6_NF_IPTABLES_LEGACY) += ip6_tables.o + obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o + obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o + obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 4b8d04640ff32..344c287aa3f41 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -816,7 +816,7 @@ config NETFILTER_XT_TARGET_AUDIT + + config NETFILTER_XT_TARGET_CHECKSUM + tristate "CHECKSUM target support" +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `CHECKSUM' target, which can be used in the iptables mangle +@@ -867,7 +867,7 @@ config NETFILTER_XT_TARGET_CONNSECMARK + config NETFILTER_XT_TARGET_CT + tristate '"CT" target support' + depends on NF_CONNTRACK +- depends on IP_NF_RAW || IP6_NF_RAW ++ depends on IP_NF_RAW || IP6_NF_RAW || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This options adds a `CT' target, which allows to specify initial +@@ -878,7 +878,7 @@ config NETFILTER_XT_TARGET_CT + + config NETFILTER_XT_TARGET_DSCP + tristate '"DSCP" and "TOS" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `DSCP' target, which allows you to manipulate +@@ -894,7 +894,7 @@ config NETFILTER_XT_TARGET_DSCP + + config NETFILTER_XT_TARGET_HL + tristate '"HL" hoplimit target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds the "HL" (for IPv6) and "TTL" (for IPv4) +@@ -1078,7 +1078,7 @@ config NETFILTER_XT_TARGET_TPROXY + depends on NETFILTER_ADVANCED + depends on IPV6 || IPV6=n + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + select NF_DEFRAG_IPV4 + select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n + select NF_TPROXY_IPV4 +@@ -1145,7 +1145,7 @@ config NETFILTER_XT_TARGET_TCPMSS + + config NETFILTER_XT_TARGET_TCPOPTSTRIP + tristate '"TCPOPTSTRIP" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a "TCPOPTSTRIP" target, which allows you to strip +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xtables-fix-up-kconfig-dependencies.patch b/queue-6.1/netfilter-xtables-fix-up-kconfig-dependencies.patch new file mode 100644 index 0000000000..8d68b84607 --- /dev/null +++ b/queue-6.1/netfilter-xtables-fix-up-kconfig-dependencies.patch @@ -0,0 +1,58 @@ +From 5060ec68f6ca3ec8167b565a4f977ecc83789205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Feb 2024 14:55:53 +0100 +Subject: netfilter: xtables: fix up kconfig dependencies + +From: Florian Westphal + +[ Upstream commit 749d4ef0868c5d8a98e07073791b2198178c93b4 ] + +Randy Dunlap reports arptables build failure: +arp_tables.c:(.text+0x20): undefined reference to `xt_find_table' + +... because recent change removed a 'select' on the xtables core. +Add a "depends" clause on arptables to resolve this. + +Kernel test robot reports another build breakage: +iptable_nat.c:(.text+0x8): undefined reference to `ipt_unregister_table_exit' + +... because of a typo, the nat table selected ip6tables. + +Reported-by: kernel test robot +Reported-by: Randy Dunlap +Closes: https://lore.kernel.org/netfilter-devel/d0dfbaef-046a-4c42-9daa-53636664bf6d@infradead.org/ +Fixes: a9525c7f6219 ("netfilter: xtables: allow xtables-nft only builds") +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Acked-by: Randy Dunlap +Tested-by: Randy Dunlap # build-tested +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 5ee86c7ae4dcb..0f60a740d117d 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -217,7 +217,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP6_NF_IPTABLES_LEGACY ++ select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -343,6 +343,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +-- +2.53.0 + diff --git a/queue-6.1/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-6.1/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..0a323cef89 --- /dev/null +++ b/queue-6.1/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From f396ee831eb240583635026e6ba9549eb859f5c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index 8ceef90ee5a50..a7a3bc500d387 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1482,6 +1482,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-6.1/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch b/queue-6.1/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch new file mode 100644 index 0000000000..0c02676075 --- /dev/null +++ b/queue-6.1/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch @@ -0,0 +1,56 @@ +From b31e5056d9743553face813615256a7c5eed6e9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:57:57 +0200 +Subject: ntfs3: fix OOB write in attr_wof_frame_info() + +From: 0xkato <0xkkato@gmail.com> + +[ Upstream commit 859d777646b56dd878b136392f3d03fb8153b559 ] + +In attr_wof_frame_info(), the offset-table read range for a nonresident +WofCompressedData stream is: + + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ... + ntfs_read_run(sbi, run, addr, from, to - from); + +A crafted image sets WofCompressedData.nres.data_size to 0xfff while the +file is large enough to request frame 1024 (offset 0x400000). This gives +from=0x1000, to=0xfff. The unsigned (to - from) wraps to 0xffffffffffffffff +and ntfs_read_write_run() overflows the single-page offs_folio via memcpy. + +Triggered by pread() on a mounted NTFS image. Depending on adjacent +memory layout at the time of the overflow, KASAN reports this as +slab-out-of-bounds, use-after-free, or slab-use-after-free all at +ntfs_read_write_run(). Secondary corruption/panic paths were also observed. + +Reject the read when the offset-table page is outside the stream. + +Signed-off-by: 0xkato <0xkkato@gmail.com> +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index f4573d276a2cc..17e01c8eba485 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1452,6 +1452,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr, + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ++ if (from >= wof_size) { ++ _ntfs_bad_inode(&ni->vfs_inode); ++ err = -EINVAL; ++ goto out1; ++ } ++ + err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME, + ARRAY_SIZE(WOF_NAME), run, + from, to); +-- +2.53.0 + diff --git a/queue-6.1/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-6.1/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..715a6c64ad --- /dev/null +++ b/queue-6.1/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From a3933653d0549718b9872ca98b8b82da3e3777bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index b8ac0943e9325..8b63b7cace0a6 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -422,6 +422,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-6.1/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-6.1/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..91832dfae4 --- /dev/null +++ b/queue-6.1/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 90eef66a92e4ae1ece6a28a99ed576c083bbeb92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index a355db38edc81..4c9e2f675ec7c 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3955,3 +3955,4 @@ module_init(nvme_fc_init_module); + module_exit(nvme_fc_exit_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 47fbf561c01e6..ed2ae0f08e989 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2472,3 +2472,4 @@ module_init(nvme_rdma_init_module); + module_exit(nvme_rdma_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 441cacad4498b..1190985127339 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2786,3 +2786,4 @@ module_init(nvme_tcp_init_module); + module_exit(nvme_tcp_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-6.1/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-6.1/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..2d63cec8f0 --- /dev/null +++ b/queue-6.1/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From a3c1ce01a2a1a1d66d75a48c4f0f1d83ff38ad8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 660e8fbb18136..7e6f5874af1cf 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3558,6 +3558,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-6.1/nvme-core-fix-parameter-name-in-comment.patch b/queue-6.1/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..9cd348e4c2 --- /dev/null +++ b/queue-6.1/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From e5fe69e26c71bbf535c81a1618b22a43148ed5ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 28f54f414e9c0..98346566a0078 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2753,7 +2753,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-6.1/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch b/queue-6.1/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch new file mode 100644 index 0000000000..e7da97913b --- /dev/null +++ b/queue-6.1/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch @@ -0,0 +1,48 @@ +From 53ae2862931b77c34cbc745d0318139e116e9ed0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:56:58 -0400 +Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error + path + +From: Shivam Kumar + +[ Upstream commit 4606467a75cfc16721937272ed29462a750b60c8 ] + +In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, +nvmet_req_uninit() is called unconditionally. However, if the command +arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() +had returned false and percpu_ref_tryget_live() was never executed. The +unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a +refcount underflow, leading to a WARNING in +percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and +eventually a permanent workqueue deadlock. + +Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling +nvmet_req_uninit(), matching the existing pattern in +nvmet_tcp_execute_request(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Shivam Kumar +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 01d685499b97d..de983facf8fed 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1231,7 +1231,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + queue->idx, cmd->req.cmd->common.command_id, + queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), + le32_to_cpu(cmd->exp_ddgst)); +- nvmet_req_uninit(&cmd->req); ++ if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) ++ nvmet_req_uninit(&cmd->req); + nvmet_tcp_free_cmd_buffers(cmd); + nvmet_tcp_fatal_error(queue); + ret = -EPROTO; +-- +2.53.0 + diff --git a/queue-6.1/nvmet-tcp-don-t-free-sq-on-authentication-success.patch b/queue-6.1/nvmet-tcp-don-t-free-sq-on-authentication-success.patch new file mode 100644 index 0000000000..56c2522290 --- /dev/null +++ b/queue-6.1/nvmet-tcp-don-t-free-sq-on-authentication-success.patch @@ -0,0 +1,59 @@ +From 336f912f2c1a529bae4838cb8fae263d33fdc678 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 15:17:53 +1000 +Subject: nvmet-tcp: Don't free SQ on authentication success + +From: Alistair Francis + +[ Upstream commit 2e6eb6b277f593b98f151ea8eff1beb558bbea3b ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +This patch ensures we don't free the TLS key on success as we might need +it again in the future. + +Signed-off-by: Alistair Francis +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Wilfred Mallawa +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/fabrics-cmd-auth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c +index e0dc22fea086d..421f0f21fa126 100644 +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -345,9 +345,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) + goto complete; + } + /* Final states, clear up variables */ +- nvmet_auth_sq_free(req->sq); +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { ++ nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); ++ } + + complete: + nvmet_req_complete(req, status); +@@ -527,9 +528,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) + status = nvmet_copy_to_sgl(req, 0, d, al); + kfree(d); + done: +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) +- nvmet_auth_sq_free(req->sq); +- else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { + nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); + } +-- +2.53.0 + diff --git a/queue-6.1/orangefs-validate-getxattr-response-length.patch b/queue-6.1/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..3cab1c1dce --- /dev/null +++ b/queue-6.1/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From bcf9f4ca3c5d74ebef7976c838a559fac6d584e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index 2d2d16caf9190..f12143db195b5 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-6.1/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch b/queue-6.1/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch new file mode 100644 index 0000000000..24bf689dac --- /dev/null +++ b/queue-6.1/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch @@ -0,0 +1,78 @@ +From 0fba9f724be2585e2acd0b72db7acda41c329ba9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 18:07:25 -0400 +Subject: orangefs_readahead: don't overflow the bufmap slot. + +From: Mike Marshall + +[ Upstream commit 415e507cdefc510c01de8ab6644163327ee9a5d0 ] + +generic/340 showed that this caller of wait_for_direct_io was +sometimes asking for more than a bufmap slot could hold. This splits +the calls up if needed. + +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/inode.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index cc81ff6ac735e..e247cb4ebc4ef 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -254,6 +254,8 @@ static void orangefs_readahead(struct readahead_control *rac) + loff_t new_start = readahead_pos(rac); + int ret; + size_t new_len = 0; ++ size_t this_size; ++ size_t remaining; + + loff_t bytes_remaining = inode->i_size - readahead_pos(rac); + loff_t pages_remaining = bytes_remaining / PAGE_SIZE; +@@ -269,17 +271,33 @@ static void orangefs_readahead(struct readahead_control *rac) + offset = readahead_pos(rac); + i_pages = &rac->mapping->i_pages; + +- iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); ++ iov_iter_xarray(&iter, ITER_DEST, i_pages, ++ offset, readahead_length(rac)); + +- /* read in the pages. */ +- if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, +- &offset, &iter, readahead_length(rac), +- inode->i_size, NULL, NULL, rac->file)) < 0) +- gossip_debug(GOSSIP_FILE_DEBUG, +- "%s: wait_for_direct_io failed. \n", __func__); +- else +- ret = 0; ++ remaining = readahead_length(rac); ++ while (remaining) { ++ if (remaining > 4194304) ++ this_size = 4194304; ++ else ++ this_size = remaining; ++ ++ /* read in the pages. */ ++ if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, ++ &offset, &iter, this_size, ++ inode->i_size, NULL, NULL, rac->file)) < 0) { ++ gossip_debug(GOSSIP_FILE_DEBUG, ++ "%s: wait_for_direct_io failed. :%d: \n", ++ __func__, ret); ++ goto cleanup; ++ } else { ++ ret = 0; ++ } ++ ++ remaining -= this_size; ++ offset += this_size; ++ } + ++cleanup: + /* clean up. */ + while ((page = readahead_page(rac))) { + page_endio(page, false, ret); +-- +2.53.0 + diff --git a/queue-6.1/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-6.1/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..ca0ce7d3f6 --- /dev/null +++ b/queue-6.1/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From 73bfd06c30c86a1c43a6d4c5a22d5d5d38b0c495 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index 4042d87d539dd..73d2144e64e8d 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -78,7 +78,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index 7f4bcf359b917..a8c6f7be7e04d 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -43,6 +43,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -74,7 +83,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -167,7 +177,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -189,7 +200,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -223,6 +235,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -287,7 +309,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 8b13be1633db1..301bb11e8cf8e 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -71,12 +71,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-6.1/pci-avoid-flr-for-amd-npu-device.patch b/queue-6.1/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..918318eeda --- /dev/null +++ b/queue-6.1/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From fac9a5241dca5d33ed35dc032fde180431abfb55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 9a325e1128ed6..f8aa7cda5a695 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5458,6 +5458,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * +@@ -5470,6 +5471,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-6.1/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..e29352cb1b --- /dev/null +++ b/queue-6.1/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From b819149982f43cfe85c2fe9a96ef055b6fff3393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 076d44c7c46ba..d003fdeb7a917 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -47,6 +47,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1436,6 +1437,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-6.1/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-6.1/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..440ed4354f --- /dev/null +++ b/queue-6.1/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 93a1803b6a5c22c674b572891bd514ad82bcf199 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/pci/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c +index 5a696078b382b..7a675fbc293a7 100644 +--- a/drivers/pci/vgaarb.c ++++ b/drivers/pci/vgaarb.c +@@ -1164,6 +1164,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1195,7 +1196,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists... */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-6.1/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-6.1/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..2e9ad91287 --- /dev/null +++ b/queue-6.1/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From 9c04142aa993107ab0efabd42dfd48e5c3adeb06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 8c385e231e070..7d69e2840569d 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -413,6 +413,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-6.1/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..2e9040eddc --- /dev/null +++ b/queue-6.1/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From b92e78f3d9962c934ec900682d54f9d9c4d15048 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 2b6d996e393e0..c4d6f874fa5b6 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1183,6 +1183,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-6.1/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-6.1/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..21d0a7758c --- /dev/null +++ b/queue-6.1/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From 4b2817639cd41b07b30152540a4cf412d37c1911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 71ec8f74f8359..2cf219ae6bbbf 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-6.1/powerpc-time-remove-redundant-preempt_disable-enable.patch b/queue-6.1/powerpc-time-remove-redundant-preempt_disable-enable.patch new file mode 100644 index 0000000000..4a7ce4fe44 --- /dev/null +++ b/queue-6.1/powerpc-time-remove-redundant-preempt_disable-enable.patch @@ -0,0 +1,98 @@ +From 1dd4e40dded1ed376af095ad4d854c220a12a990 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:13 +0530 +Subject: powerpc/time: Remove redundant preempt_disable|enable() calls from + arch_irq_work_raise() + +From: Sayali Patil + +[ Upstream commit 31467b23823ffec1f6fff407f8e3ca9af8b7491a ] + +A kernel panic is observed when handling machine check exceptions from +real mode. + + BUG: Unable to handle kernel data access on read at 0xc00000006be21300 + Oops: Kernel access of bad area, sig: 11 [#1] + MSR: 8000000000001003 CR: 88222248 XER: 00000005 + CFAR: c00000000003ffc4 DAR: c00000006be21300 DSISR: 40000000 IRQMASK: 0 + NIP [c000000000029e40] arch_irq_work_raise+0x10/0x70 + LR [c00000000003ffc8] machine_check_queue_event+0xa8/0x150 + Call Trace: + [c0000000179d3c70] [c00000000003ff64] machine_check_queue_event+0x44/0x150 + [c0000000179d3d30] [c0000000000084e0] machine_check_early_common+0x1f0/0x2c0 + +The crash occurs because arch_irq_work_raise() calls preempt_disable() +from machine check exception (MCE) handlers running in real mode. In +this context, accessing the preempt_count can fault, leading to the panic. + +The preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +was originally added by commit 0fe1ac48bef0 ("powerpc/perf_event: Fix +oops due to perf_event_do_pending call") to avoid races while raising +irq work from exception context. + +Later, commit 471ba0e686cb ("irq_work: Do not raise an IPI when +queueing work on the local CPU") added preemption protection in +irq_work_queue() path, while commit 20b876918c06 ("irq_work: Use per +cpu atomics instead of regular atomics") added equivalent +protection in irq_work_queue_on() before reaching arch_irq_work_raise(): + + irq_work_queue() / irq_work_queue_on() + -> preempt_disable() + -> __irq_work_queue_local() + -> irq_work_raise() + -> arch_irq_work_raise() + +As a result, callers other than mce_irq_work_raise() already execute +with preemption disabled, making the additional +preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +redundant. + +The arch_irq_work_raise() function executes in NMI context when called +from MCE handler. Hence we will not be preempted or scheduled out since +we are in NMI context with MSR[EE]=0. Therefore, it is safe to remove +the preempt_disable()/preempt_enable() calls from here. + +Remove it to avoid accessing preempt_count from real mode context. + +Fixes: cc15ff327569 ("powerpc/mce: Avoid using irq_work_queue() in realmode") +Suggested-by: Mahesh Salgaonkar +Acked-by: Shrikanth Hegde +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Sayali Patil +[Maddy: Fixed the commit title] +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260513081413.222490-1-sayalip@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/time.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index 285159e65a3ba..6628b65b9ecad 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -454,6 +454,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); + + #endif /* 32 vs 64 bit */ + ++/* ++ * Must be called with preemption disabled since it updates ++ * per-CPU irq_work state and programs the local CPU decrementer. ++ */ + void arch_irq_work_raise(void) + { + /* +@@ -467,10 +471,8 @@ void arch_irq_work_raise(void) + * which could get tangled up if we're messing with the same state + * here. + */ +- preempt_disable(); + set_irq_work_pending_flag(); + set_dec(1); +- preempt_enable(); + } + + static void set_dec_or_work(u64 val) +-- +2.53.0 + diff --git a/queue-6.1/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-6.1/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..4aad1f8552 --- /dev/null +++ b/queue-6.1/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From 9e87bb042aa20ef86f95fc168ce7b4904de2cabc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index df72070a3879d..e6ec53facfe95 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3005,12 +3005,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-6.1/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-6.1/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..3681d6063a --- /dev/null +++ b/queue-6.1/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 71bbcd3dbac8aea239d3ca4a04f24e9c21f79d12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index d29740be4833e..ad37c0584c23b 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -204,6 +204,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-6.1/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-6.1/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..2abbb85e41 --- /dev/null +++ b/queue-6.1/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From b7434b7c73f2479876f246422e648148bb5aef0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 020349f8979d8..99c50a0cc247b 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -26,7 +26,6 @@ + #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MD_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -78,7 +77,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -144,9 +143,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id) + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -154,6 +155,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id) + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-6.1/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch b/queue-6.1/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch new file mode 100644 index 0000000000..e880d76262 --- /dev/null +++ b/queue-6.1/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch @@ -0,0 +1,50 @@ +From 4304e3098f96c29812589e8949d297c87e71237c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:47:40 +0530 +Subject: rtc: ti-k3: Add support to resume from IO DDR low power mode + +From: Akashdeep Kaur + +[ Upstream commit 0e9b12ee74c57617bb362deb3c82e35fe49694b5 ] + +Restore the RTC HW context which may be lost when system enters +certain low power mode (IO+DDR mode). +Check if the RTC registers are locked which would indicate loss of +context (reset) and restore the context as needed. + +Signed-off-by: Akashdeep Kaur +Reviewed-by: Vignesh Raghavendra +Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-ti-k3.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c +index 0d90fe9233550..3c7e0f277f57d 100644 +--- a/drivers/rtc/rtc-ti-k3.c ++++ b/drivers/rtc/rtc-ti-k3.c +@@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) + static int __maybe_unused ti_k3_rtc_resume(struct device *dev) + { + struct ti_k3_rtc *priv = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (k3rtc_check_unlocked(priv)) { ++ /* RTC locked implies low power mode exit where RTC loses context */ ++ ret = k3rtc_configure(dev); ++ if (ret) ++ return ret; ++ } + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); +- return 0; ++ return ret; + } + + static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); +-- +2.53.0 + diff --git a/queue-6.1/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch b/queue-6.1/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch new file mode 100644 index 0000000000..2aecd02ccb --- /dev/null +++ b/queue-6.1/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch @@ -0,0 +1,101 @@ +From 6480485a9bb16eb507503ad7c49ebe56940651d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 19:59:29 +0800 +Subject: sched: Fix incorrect schedstats for rt and dl thread + +From: Dengjun Su + +[ Upstream commit c0e1832ba6dad7057acf3f485a87e0adccc23141 ] + +For RT and DL thread, only 'set_next_task_(rt/dl)' will call +'update_stats_wait_end_(rt/dl)' to update schedstats information. +However, during the migration process, +'update_stats_wait_start_(rt/dl)' will be called twice, which +will cause the values of wait_max and wait_sum to be incorrect. +The specific output as follows: +$ cat /proc/6046/task/6046/sched | grep wait +wait_start : 0.000000 +wait_max : 496717.080029 +wait_sum : 7921540.776553 + +A complete schedstats information update flow of migrate should be +__update_stats_wait_start() [enter queue A, stage 1] -> +__update_stats_wait_end() [leave queue A, stage 2] -> +__update_stats_wait_start() [enter queue B, stage 3] -> +__update_stats_wait_end() [start running on queue B, stage 4] + + Stage 1: prev_wait_start is 0, and in the end, wait_start records the + time of entering the queue. + Stage 2: task_on_rq_migrating(p) is true, and wait_start is updated to + the waiting time on queue A. + Stage 3: prev_wait_start is the waiting time on queue A, wait_start is + the time of entering queue B, and wait_start is expected to be greater + than prev_wait_start. Under this condition, wait_start is updated to + (the moment of entering queue B) - (the waiting time on queue A). + Stage 4: the final wait time = (time when starting to run on queue B) + - (time of entering queue B) + (waiting time on queue A) = waiting + time on queue B + waiting time on queue A. + +The current problem is that stage 2 does not call __update_stats_wait_end +to update wait_start, which causes the final computed wait time = waiting +time on queue B + the moment of entering queue A, leading to incorrect +wait_max and wait_sum. + +Add 'update_stats_wait_end_(rt/dl)' in 'update_stats_dequeue_(rt/dl)' to +update schedstats information when dequeue_task. + +Signed-off-by: Dengjun Su +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260204115959.3183567-1-dengjun.su@mediatek.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 4 ++++ + kernel/sched/rt.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 62a7c4ed86753..19b789c6efcf5 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -1595,10 +1595,14 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, + int flags) + { + struct task_struct *p = dl_task_of(dl_se); ++ struct rq *rq = rq_of_dl_rq(dl_rq); + + if (!schedstat_enabled()) + return; + ++ if (p != rq->curr) ++ update_stats_wait_end_dl(dl_rq, dl_se); ++ + if ((flags & DEQUEUE_SLEEP)) { + unsigned int state; + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 99e5d37b3f6eb..ad1a65a47a42b 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1410,13 +1410,18 @@ update_stats_dequeue_rt(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, + int flags) + { + struct task_struct *p = NULL; ++ struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!schedstat_enabled()) + return; + +- if (rt_entity_is_task(rt_se)) ++ if (rt_entity_is_task(rt_se)) { + p = rt_task_of(rt_se); + ++ if (p != rq->curr) ++ update_stats_wait_end_rt(rt_rq, rt_se); ++ } ++ + if ((flags & DEQUEUE_SLEEP) && p) { + unsigned int state; + +-- +2.53.0 + diff --git a/queue-6.1/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-6.1/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..3b0f547e5b --- /dev/null +++ b/queue-6.1/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From 3072335c56065619062c6d6e76c3ed0b3d90382f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-6.1/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch b/queue-6.1/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch new file mode 100644 index 0000000000..b3b46bd1e7 --- /dev/null +++ b/queue-6.1/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch @@ -0,0 +1,117 @@ +From bf3ae129b25445da928947b48db080a052310f01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:03 -0800 +Subject: scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in + lpfc_sli_abort_ring() + +From: Justin Tee + +[ Upstream commit 2da10bcaa58a389ca60f8e788180e0dca00739bc ] + +When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is +cleared but the phba->txcmplq_cnt is not reset to zero. This can +sometimes result in a phba->txcmplq_cnt that never reaches zero, which +hangs the cleanup process. + +Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also +ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_sli.c | 66 +++++++++++++----------------------- + 1 file changed, 24 insertions(+), 42 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 90213058b8356..9758652996b61 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -4554,59 +4554,41 @@ void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { + LIST_HEAD(tx_completions); +- LIST_HEAD(txcmplq_completions); ++ spinlock_t *plock; /* for transmit queue access */ + struct lpfc_iocbq *iocb, *next_iocb; + int offline; + +- if (pring->ringno == LPFC_ELS_RING) { ++ if (phba->sli_rev >= LPFC_SLI_REV4) ++ plock = &pring->ring_lock; ++ else ++ plock = &phba->hbalock; ++ ++ if (pring->ringno == LPFC_ELS_RING) + lpfc_fabric_abort_hba(phba); +- } ++ + offline = pci_channel_offline(phba->pcidev); + +- /* Error everything on txq and txcmplq +- * First do the txq. +- */ +- if (phba->sli_rev >= LPFC_SLI_REV4) { +- spin_lock_irq(&pring->ring_lock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; ++ /* Cancel everything on txq */ ++ spin_lock_irq(plock); ++ list_splice_init(&pring->txq, &tx_completions); ++ pring->txq_cnt = 0; + +- if (offline) { +- list_splice_init(&pring->txcmplq, +- &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&pring->ring_lock); ++ if (offline) { ++ /* Cancel everything on txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; ++ list_splice_init(&pring->txcmplq, &tx_completions); ++ pring->txcmplq_cnt = 0; + } else { +- spin_lock_irq(&phba->hbalock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; +- +- if (offline) { +- list_splice_init(&pring->txcmplq, &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&phba->hbalock); ++ /* Issue ABTS for everything on the txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + } ++ spin_unlock_irq(plock); + +- if (offline) { +- /* Cancel all the IOCBs from the completions list */ +- lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, +- IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); +- } else { +- /* Make sure HBA is alive */ ++ if (!offline) + lpfc_issue_hb_tmo(phba); +- } ++ + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); +-- +2.53.0 + diff --git a/queue-6.1/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-6.1/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..dc12d74651 --- /dev/null +++ b/queue-6.1/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 4d501fa703ddce11d054307eeb9c8bcc77477d6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index d5165655fc053..9c06e9d4352b4 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1123,6 +1123,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1133,22 +1153,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-6.1/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-6.1/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..db97cb1f8f --- /dev/null +++ b/queue-6.1/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From 55082684b9c614426ad4bc413f3ff1c390fedb41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index 543a35e5c9dfe..231618a5c2272 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -981,6 +981,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-6.1/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-6.1/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..eb5e0732db --- /dev/null +++ b/queue-6.1/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 965a105ec1f37fa39437912a9fd1021745f34897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index d6f682ed15811..ffe6801df802a 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -140,6 +140,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + }; +@@ -241,7 +242,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1113,11 +1114,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 88776c115d..4a57951be1 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -830,3 +830,194 @@ drm-gma500-oaktrail_lvds-fix-hang-on-init-failure.patch drm-gma500-oaktrail_lvds-fix-i2c-adapter-leaks-on-init.patch io-wq-check-that-the-predecessor-is-hashed-in-io_wq_remove_pending.patch net-rds-reset-op_nents-when-zerocopy-page-pin-fails.patch +hid-uclogic-fix-regression-of-input-name-assignment.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-arptables-allow-xtables-nft-only-builds.patch +netfilter-xtables-allow-xtables-nft-only-builds.patch +netfilter-ebtables-allow-xtables-nft-only-builds.patch +netfilter-xtables-fix-up-kconfig-dependencies.patch +netfilter-arptables-select-netfilter_family_arp-when.patch +netfilter-make-legacy-configs-user-selectable.patch +netfilter-exclude-legacy-tables-on-preempt_rt.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-x_tables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +net-lan966x-avoid-unregistering-netdev-on-register-f.patch +irqchip-ath79-cpu-remove-unused-function.patch +irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +powerpc-time-remove-redundant-preempt_disable-enable.patch +net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +nvmet-tcp-don-t-free-sq-on-authentication-success.patch +io_uring-cancel-validate-opcode-for-ioring_async_can.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch +ipv4-validate-ipv4_devconf-attributes-properly.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-mlx5e-xsk-increase-size-for-chunk_size-param.patch +wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +pci-avoid-flr-for-amd-npu-device.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch +drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +drm-amd-display-merge-pipes-for-validate.patch +asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-validate-outarg-offset-and-size-in-notify-store.patch +fuse-mark-dax-inode-releases-as-blocking.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-validate-getxattr-response-length.patch +orangefs_readahead-don-t-overflow-the-bufmap-slot.patch +ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +i3c-master-move-bus_init-error-suppression.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +thunderbolt-disable-clx-on-titan-ridge-based-devices.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +ntfs3-fix-oob-write-in-attr_wof_frame_info.patch +scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +iio-abi-fix-current_trigger-description.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch +nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +rculist-add-list_splice_rcu-for-private-lists.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-6.1/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-6.1/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..5f1d95c8f2 --- /dev/null +++ b/queue-6.1/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From 0bb5d395fbb346753899d3923dd6be0338b49808 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index 8bcecd19e901c..e1480c6227168 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -5064,6 +5064,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + return rc; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + npages = DIV_ROUND_UP(len, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-6.1/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-6.1/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..d2fc2ceced --- /dev/null +++ b/queue-6.1/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From a53dd79c16940eb88b1cace69c64074742988652 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 207d578547cd9..b4883c365ba33 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -375,7 +375,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-6.1/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-6.1/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..7243a448ea --- /dev/null +++ b/queue-6.1/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From c2e734adc26587ba1a33ea364cd9027b9aa6ffe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 965330eec80a8..d0b43d50b83ce 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-6.1/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-6.1/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..d8e7feba37 --- /dev/null +++ b/queue-6.1/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From 89e8d02005819660decd70a38d35cd6d3ca2dd67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index dc32a3d8ef874..a275ab5321a96 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1112,7 +1112,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-6.1/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch b/queue-6.1/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch new file mode 100644 index 0000000000..c12e0fc326 --- /dev/null +++ b/queue-6.1/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch @@ -0,0 +1,53 @@ +From 8ceaa78629b12e5196e49e2ff7729e4967e10445 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:25:57 -0800 +Subject: thunderbolt: Disable CLx on Titan Ridge-based devices with old + firmware + +From: Rene Sapiens + +[ Upstream commit 59b03d12b1f6d14d936a3ebec225f8d914dc3b70 ] + +Thunderbolt 3 devices based on Titan Ridge routers with NVM firmware +version < 0x65 have been observed to become unstable when CL states are +enabled. This can lead to link disconnect events and the device failing +to enumerate. + +Enable CLx on Titan Ridge only when the running NVM firmware version +is >= 0x65. + +Signed-off-by: Rene Sapiens +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +--- + drivers/thunderbolt/quirks.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c +index e81de9c30eac9..9f7914ac2f48c 100644 +--- a/drivers/thunderbolt/quirks.c ++++ b/drivers/thunderbolt/quirks.c +@@ -23,6 +23,9 @@ static void quirk_dp_credit_allocation(struct tb_switch *sw) + + static void quirk_clx_disable(struct tb_switch *sw) + { ++ if (tb_switch_is_titan_ridge(sw) && sw->nvm && sw->nvm->major >= 0x65) ++ return; ++ + sw->quirks |= QUIRK_NO_CLX; + tb_sw_dbg(sw, "disabling CL states\n"); + } +@@ -61,6 +64,10 @@ static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link }, + { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link }, ++ ++ /* Intel Titan Ridge CLx is unstable on early firmware versions */ ++ { 0x8086, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE, 0x0000, 0x0000, ++ quirk_clx_disable }, + /* + * Intel Goshen Ridge NVM 27 and before report wrong number of + * DP buffers. +-- +2.53.0 + diff --git a/queue-6.1/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-6.1/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..517fafd369 --- /dev/null +++ b/queue-6.1/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 1bcd8bf00310037dec7aed68e9a7630d1863abdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index be3668d37d654..a29b529a50adb 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1492,6 +1492,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1499,7 +1502,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-6.1/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-6.1/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..06b4f3b7a1 --- /dev/null +++ b/queue-6.1/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From dcac50ab93317a292e065d2420381083b26836a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 47e59664dbde6..8fa81bc896397 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1417,9 +1417,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1546,8 +1546,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-6.1/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch b/queue-6.1/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch new file mode 100644 index 0000000000..e387628888 --- /dev/null +++ b/queue-6.1/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch @@ -0,0 +1,60 @@ +From 4f2a32eee07022c6bc6b98a386dc104dcfb8927d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:20:42 -0700 +Subject: um: Disable GCOV_PROFILE_ALL on 32-bit UML with Clang 20/21 + +From: Kees Cook + +[ Upstream commit 6522fe5c1b007c376fc5f2de1016c99a18b0af8e ] + +Clang 20 and 21 miscompute __builtin_object_size() when -fprofile-arcs +is active on 32-bit UML targets, which passes incorrect object size +calculations for local variables through always_inline copy_to_user() +and check_copy_size(), causing spurious compile-time errors: + + include/linux/ucopysize.h:52:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small + +The regression was introduced in LLVM commit 02b8ee281947 ("[llvm] +Improve llvm.objectsize computation by computing GEP, alloca and malloc +parameters bound"), which shipped in Clang 20. It was fixed in LLVM +by commit 45b697e610fd ("[MemoryBuiltins] Consider index type size +when aggregating gep offsets"), which was backported to the LLVM 22.x +release branch. + +The bug requires 32-bit UML + GCOV_PROFILE_ALL (which uses -fprofile-arcs), +though the exact trigger depends on optimizer decisions influenced by other +enabled configs. + +Prevent the bad combination by disabling UML's ARCH_HAS_GCOV_PROFILE_ALL +on 32-bit when using Clang 20.x or 21.x. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604030531.O6FveVgn-lkp@intel.com/ +Suggested-by: Nathan Chancellor +Assisted-by: Claude:claude-opus-4-6[1m] +Signed-off-by: Kees Cook +Link: https://patch.msgid.link/20260409052038.make.995-kees@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/Kconfig | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/um/Kconfig b/arch/um/Kconfig +index 82709bc36df7d..28acb2455d79f 100644 +--- a/arch/um/Kconfig ++++ b/arch/um/Kconfig +@@ -8,7 +8,9 @@ config UML + select ARCH_EPHEMERAL_INODES + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +- select ARCH_HAS_GCOV_PROFILE_ALL ++ # Clang 20 & 21 miscompute __builtin_object_size() under -fprofile-arcs ++ # on 32-bit, causing spurious compile-time errors in check_copy_size(). ++ select ARCH_HAS_GCOV_PROFILE_ALL if !(!64BIT && CLANG_VERSION >= 200000 && CLANG_VERSION < 220100) + select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER +-- +2.53.0 + diff --git a/queue-6.1/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-6.1/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..05d90816c8 --- /dev/null +++ b/queue-6.1/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From 7ff223e3f9619689455d6c0a9bfe428241606018 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index fa88f210ecd57..fd0fde581bd08 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-6.1/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-6.1/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..124ad10c03 --- /dev/null +++ b/queue-6.1/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From e1466f18bb6ff52bfdd5f25ca4077f4e55cfcf40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index db9a5d97003fe..da352706f02c2 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -673,7 +673,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -681,11 +681,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.1/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-6.1/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..ee474afe9f --- /dev/null +++ b/queue-6.1/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From a1c5af55957b98ea0f5fe56c7efec1fcb2e176ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index da352706f02c2..622de45427c46 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -781,6 +781,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-6.1/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-6.1/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..b171110743 --- /dev/null +++ b/queue-6.1/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From fa1146435e05091bdf8709c113dd2390cd6873b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index d6dbd038af67b..db9a5d97003fe 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -676,7 +676,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -707,14 +707,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-6.1/virtiofs-add-fuse-protocol-validation.patch b/queue-6.1/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..db8cb37035 --- /dev/null +++ b/queue-6.1/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From 3e84827f7ba046ddaafe24f5466e0e9b7d1cc003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index 9e4f2ba0ef9d2..ab410ebe7c304 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -564,6 +564,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -574,10 +595,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct page *page; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -633,6 +650,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-6.1/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-6.1/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..52c069c6b1 --- /dev/null +++ b/queue-6.1/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From bc845f0255b8ae40260308b6cb6b875d928bf55b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 86b913d5ac5b7..67b680aa475b1 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -2007,10 +2007,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-6.1/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch b/queue-6.1/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch new file mode 100644 index 0000000000..62a3c3bc6a --- /dev/null +++ b/queue-6.1/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch @@ -0,0 +1,45 @@ +From 93a0649305b10bbe70bf0f94e1739a64a01c9422 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:43 +0200 +Subject: wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending + +From: Emmanuel Grumbach + +[ Upstream commit 5562b3bbeede8be25092064720e4a942e9fd3e3e ] + +Otherwise we may send garbage. + +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.2d494b0f4692.I9afd0fa6b2ea5a27118144ac4e3bbbedc2089c10@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index 4706df3ae81bb..2cf5bf2e7dcab 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -863,7 +863,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) + + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + { +- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; ++ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; + struct iwl_geo_tx_power_profiles_resp *resp; + u16 len; + int ret; +@@ -915,7 +915,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) + { + u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); +- union iwl_geo_tx_power_profiles_cmd cmd; ++ union iwl_geo_tx_power_profiles_cmd cmd = {}; + u16 len; + u32 n_bands; + u32 n_profiles; +-- +2.53.0 + diff --git a/queue-6.1/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch b/queue-6.1/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch new file mode 100644 index 0000000000..d5beff92cb --- /dev/null +++ b/queue-6.1/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch @@ -0,0 +1,51 @@ +From 2d60783a3abd29ef5c20cc336d2f78244b0fcbbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:17:22 +0530 +Subject: wifi: mac80211: use ap_addr for 4-address NULL frame destination + +From: Tamizh Chelvam Raja + +[ Upstream commit 594be50a3f0a6b7389f40f7acbf0dd731beb5204 ] + +Currently ieee80211_send_4addr_nullfunc() uses deflink.u.mgd.bssid +for addr1 and addr3 fields. In MLO configurations, deflink.u.mgd.bssid +represents link 0's BSSID and is not updated when link 0 is not an +assoc link. This causes 4-address NULL frames to be sent to the +wrong address, preventing WDS AP_VLAN interface creation on the peer AP. + +To fix this use sdata->vif.cfg.ap_addr instead, which contains the AP's MLD +address populated during authentication/association and remains +valid regardless of which links are active. + +This ensures 4-address NULL frames reach the correct AP, allowing +proper WDS operation over MLO connections. + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Tamizh Chelvam Raja +Link: https://patch.msgid.link/20260326164723.553927-3-tamizh.raja@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 30db27df6b793..f216b6dd38b3d 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -1668,9 +1668,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; +- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +-- +2.53.0 + diff --git a/queue-6.1/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-6.1/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..b52f6980f8 --- /dev/null +++ b/queue-6.1/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From 6953e55f99682bddb0c4bb41aeae5dc4b39681c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index e9c5e85ec07c2..35ab3d2ac4c72 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -525,6 +525,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-6.1/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-6.1/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..1ae8f58336 --- /dev/null +++ b/queue-6.1/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From a57010d3c758bdbb31b61addf9e555ce29d99ba9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index 80ad871f028c3..80fa692aa4ae6 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -421,7 +437,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index 66fe386ec9cc6..d29c8eeff318d 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-6.1/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-6.1/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..2b0f66d86f --- /dev/null +++ b/queue-6.1/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From dee6333ce1a4240537de32be02555c6c2baeadad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index 05e6911a40447..44a64ec69ef37 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -397,7 +397,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + vif = si->vif; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-6.1/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch b/queue-6.1/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch new file mode 100644 index 0000000000..54a16d57f7 --- /dev/null +++ b/queue-6.1/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch @@ -0,0 +1,78 @@ +From b0035c9251036bc4ee1789567f2bd30b52e819c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:21:55 +0000 +Subject: wifi: rtw89: retry efuse physical map dump on transient failure + +From: Christian Hewitt + +[ Upstream commit d92f6ad6483e6d430c8273eeb7be97ce85244bd5 ] + +On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse +physical map dump intermittently fails with -EBUSY during probe. +The failure occurs in rtw89_dump_physical_efuse_map_ddv() where +read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY +bit after 1 second. + +The root cause is a timing race during boot: the WiFi driver's +chip initialization (firmware download via PCIe) overlaps with +Bluetooth firmware download to the same combo chip via USB. This +can leave the efuse controller temporarily unavailable when the +WiFi driver attempts to read the efuse map. + +The firmware download path retries up to 5 times, but the efuse +read that follows has no similar logic. Address this by adding +retry loop logic (also up to 5 attempts) around physical efuse +map dump. + +Signed-off-by: Christian Hewitt +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260317112155.1939569-1-christianshewitt@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/efuse.c | 23 ++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c +index 7bd4f8558e03b..9e188dbd7b06f 100644 +--- a/drivers/net/wireless/realtek/rtw89/efuse.c ++++ b/drivers/net/wireless/realtek/rtw89/efuse.c +@@ -153,8 +153,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + +-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, +- u32 dump_addr, u32 dump_size, bool dav) ++static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) + { + int ret; + +@@ -176,6 +176,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + ++static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) ++{ ++ int retry; ++ int ret; ++ ++ for (retry = 0; retry < 5; retry++) { ++ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr, ++ dump_size, dav); ++ if (!ret) ++ return 0; ++ ++ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n", ++ dav, retry); ++ } ++ ++ return ret; ++} ++ + #define invalid_efuse_header(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) + #define invalid_efuse_content(word_en, i) \ +-- +2.53.0 + diff --git a/queue-6.12/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch b/queue-6.12/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch new file mode 100644 index 0000000000..89d1100dfa --- /dev/null +++ b/queue-6.12/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch @@ -0,0 +1,117 @@ +From 56a1b36bf88b55c830c5cde1233caf9d4ccafdb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 23:30:22 +0800 +Subject: 9p/trans_xen: make cleanup idempotent after dataring alloc errors + +From: Yufan Chen + +[ Upstream commit 72cb9ee4f6d80962df17c9763b14e62e28fd85a2 ] + +xen_9pfs_front_alloc_dataring() tears down resources on failure but +leaves ring fields stale. If xen_9pfs_front_init() later jumps to the +common error path, xen_9pfs_front_free() may touch the same resources +again, causing duplicate/invalid gnttab_end_foreign_access() calls and +potentially dereferencing a freed intf pointer. + +Initialize dataring sentinels before allocation, gate teardown on those +sentinels, and clear ref/intf/data/irq immediately after each release. + +This keeps cleanup idempotent for partially initialized rings and +prevents repeated teardown during init failure handling. + +Signed-off-by: Yufan Chen +Reviewed-by: Stefano Stabellini +Message-ID: <20260324153023.86853-2-ericterminal@gmail.com> +Signed-off-by: Dominique Martinet +Signed-off-by: Sasha Levin +--- + net/9p/trans_xen.c | 51 +++++++++++++++++++++++++++++++++------------- + 1 file changed, 37 insertions(+), 14 deletions(-) + +diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c +index 068d57515dd58..e072cffebaa7d 100644 +--- a/net/9p/trans_xen.c ++++ b/net/9p/trans_xen.c +@@ -280,25 +280,33 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv) + + cancel_work_sync(&ring->work); + +- if (!priv->rings[i].intf) ++ if (!ring->intf) + break; +- if (priv->rings[i].irq > 0) +- unbind_from_irqhandler(priv->rings[i].irq, ring); +- if (priv->rings[i].data.in) { +- for (j = 0; +- j < (1 << priv->rings[i].intf->ring_order); ++ if (ring->irq >= 0) { ++ unbind_from_irqhandler(ring->irq, ring); ++ ring->irq = -1; ++ } ++ if (ring->data.in) { ++ for (j = 0; j < (1 << ring->intf->ring_order); + j++) { + grant_ref_t ref; + +- ref = priv->rings[i].intf->ref[j]; ++ ref = ring->intf->ref[j]; + gnttab_end_foreign_access(ref, NULL); ++ ring->intf->ref[j] = INVALID_GRANT_REF; + } +- free_pages_exact(priv->rings[i].data.in, +- 1UL << (priv->rings[i].intf->ring_order + +- XEN_PAGE_SHIFT)); ++ free_pages_exact(ring->data.in, ++ 1UL << (ring->intf->ring_order + ++ XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; + } +- gnttab_end_foreign_access(priv->rings[i].ref, NULL); +- free_page((unsigned long)priv->rings[i].intf); ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } + kfree(priv->rings); + } +@@ -331,6 +339,12 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + int ret = -ENOMEM; + void *bytes = NULL; + ++ ring->intf = NULL; ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ ring->ref = INVALID_GRANT_REF; ++ ring->irq = -1; ++ + init_waitqueue_head(&ring->wq); + spin_lock_init(&ring->lock); + INIT_WORK(&ring->work, p9_xen_response); +@@ -376,9 +390,18 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + for (i--; i >= 0; i--) + gnttab_end_foreign_access(ring->intf->ref[i], NULL); + free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; ++ } ++ if (ring->intf) { ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } +- gnttab_end_foreign_access(ring->ref, NULL); +- free_page((unsigned long)ring->intf); ++ ring->irq = -1; + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch b/queue-6.12/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch new file mode 100644 index 0000000000..4fd079c84d --- /dev/null +++ b/queue-6.12/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch @@ -0,0 +1,78 @@ +From 69a127b8f0bc4470ee4b4fff369ceaa4303a70ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 12:39:01 -0700 +Subject: accel/qaic: Add overflow check to remap_pfn_range during mmap + +From: Zack McKevitt + +[ Upstream commit aa16b2bc0f02709919e2435f531406531e5bcc69 ] + +The call to remap_pfn_range in qaic_gem_object_mmap is susceptible to +(re)mapping beyond the VMA if the BO is too large. This can cause use +after free issues when munmap() unmaps only the VMA region and not the +additional mappings. To prevent this, check the remaining size of the +VMA before remapping and truncate the remapped length if sg->length is +too large. + +Reported-by: Lukas Maar +Fixes: ff13be830333 ("accel/qaic: Add datapath") +Reviewed-by: Karol Wachowski +Signed-off-by: Zack McKevitt +Reviewed-by: Jeff Hugo +[jhugo: fix braces from checkpatch --strict] +Signed-off-by: Jeff Hugo +Link: https://patch.msgid.link/20260430193858.1178641-1-zachary.mckevitt@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/accel/qaic/qaic_data.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c +index 265eeb4e156fc..aa89571b37f0e 100644 +--- a/drivers/accel/qaic/qaic_data.c ++++ b/drivers/accel/qaic/qaic_data.c +@@ -605,8 +605,11 @@ static const struct vm_operations_struct drm_vm_ops = { + static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) + { + struct qaic_bo *bo = to_qaic_bo(obj); ++ unsigned long remap_start; + unsigned long offset = 0; ++ unsigned long remap_end; + struct scatterlist *sg; ++ unsigned long length; + int ret = 0; + + if (obj->import_attach) +@@ -614,11 +617,27 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc + + for (sg = bo->sgt->sgl; sg; sg = sg_next(sg)) { + if (sg_page(sg)) { ++ /* if sg is too large for the VMA, so truncate it to fit */ ++ if (check_add_overflow(vma->vm_start, offset, &remap_start)) ++ return -EINVAL; ++ if (check_add_overflow(remap_start, sg->length, &remap_end)) ++ return -EINVAL; ++ ++ if (remap_end > vma->vm_end) { ++ if (check_sub_overflow(vma->vm_end, remap_start, &length)) ++ return -EINVAL; ++ } else { ++ length = sg->length; ++ } ++ ++ if (length == 0) ++ goto out; ++ + ret = remap_pfn_range(vma, vma->vm_start + offset, page_to_pfn(sg_page(sg)), +- sg->length, vma->vm_page_prot); ++ length, vma->vm_page_prot); + if (ret) + goto out; +- offset += sg->length; ++ offset += length; + } + } + +-- +2.53.0 + diff --git a/queue-6.12/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-6.12/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..f4ac0697ce --- /dev/null +++ b/queue-6.12/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From b2a1a23e9c896daeeed38a4e2720183a2a472589 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index b524cf27213d4..b377afe11e699 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1087,6 +1087,8 @@ static int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-6.12/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-6.12/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..15c3d8bde5 --- /dev/null +++ b/queue-6.12/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From ad2953b0f2d563e1e1d6b446616125f5e998d62c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index b377afe11e699..f45758207512c 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1289,16 +1289,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-6.12/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-6.12/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..806a45b71f --- /dev/null +++ b/queue-6.12/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From be1b4d758693c8ca89aaf6f30906aa3e692ffe04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index bd40d5f088104..10d5c08252ffe 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -117,6 +117,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-6.12/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-6.12/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..f4c393291b --- /dev/null +++ b/queue-6.12/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From a8bc7a9b73194e4c66103c093481d44e33c767b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 7400a5aa47ca6..feb0995056662 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -980,10 +980,12 @@ static int onyx_i2c_probe(struct i2c_client *client) + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.12/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-6.12/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..51352334f1 --- /dev/null +++ b/queue-6.12/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From ce973fc3f8dd2a0a68a602e1600d5c1a60a8e133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index 70216aa059650..84c6fcce9be1c 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client) + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.12/alsa-asihpi-detect-truncated-control-names.patch b/queue-6.12/alsa-asihpi-detect-truncated-control-names.patch new file mode 100644 index 0000000000..b6abba469d --- /dev/null +++ b/queue-6.12/alsa-asihpi-detect-truncated-control-names.patch @@ -0,0 +1,93 @@ +From bac47e3bfcaf0aef3ecd4ca12a14e1b641369e13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 18:28:08 +0800 +Subject: ALSA: asihpi: detect truncated control names + +From: Pengpeng Hou + +[ Upstream commit 18d4969e22cc3ff738257e1d7738aafc65a6d2d2 ] + +asihpi_ctl_init() builds mixer control names in the fixed 44-byte +hpi_ctl->name buffer with sprintf(). + +This is not only a defensive cleanup. The current in-tree name tables and +format strings can already exceed 44 bytes. For example, + + "Bitstream 0 Internal 0 Monitor Playback Volume" + +is 46 characters before the trailing NUL, so the current sprintf() call +writes past the end of hpi_ctl->name. + +The generated control name is used as the ALSA control element key, so +blindly truncating it is not sufficient. Switch the formatting to +snprintf() and emit an error if truncation happens, showing the +truncated name while still keeping the write bounded to hpi_ctl->name. + +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260328102808.33969-1-pengpeng@iscas.ac.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/asihpi/asihpi.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c +index fdd4fe16225fc..93981cb91bce9 100644 +--- a/sound/pci/asihpi/asihpi.c ++++ b/sound/pci/asihpi/asihpi.c +@@ -1362,6 +1362,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + struct hpi_control *hpi_ctl, + char *name) + { ++ int len; + char *dir; + memset(snd_control, 0, sizeof(*snd_control)); + snd_control->name = hpi_ctl->name; +@@ -1384,23 +1385,30 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + dir = "Playback "; /* PCM Playback source, or output node */ + + if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) +- sprintf(hpi_ctl->name, "%s %d %s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + else if (hpi_ctl->dst_node_type) { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + } else { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ dir, name); + } ++ ++ if (len >= sizeof(hpi_ctl->name)) ++ pr_err("asihpi: truncated control name: %s\n", ++ hpi_ctl->name); + } + + /*------------------------------------------------------------ +-- +2.53.0 + diff --git a/queue-6.12/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-6.12/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..ac753f6a17 --- /dev/null +++ b/queue-6.12/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 32cf8a710e3a996f8a001560efaea1ec832734e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index d81a890b60c65..31d6cbf790eb9 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -160,6 +160,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %d total %d bytes\n", + tstamp->byte_offset, tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-6.12/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..4443a2ff7a --- /dev/null +++ b/queue-6.12/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From cfb3e37b1fa4834cef8e799fa6c575dfa063e8ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c +index 7b276047f85a7..c897fc443467c 100644 +--- a/sound/hda/hdmi_chmap.c ++++ b/sound/hda/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch b/queue-6.12/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch new file mode 100644 index 0000000000..70efba050b --- /dev/null +++ b/queue-6.12/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch @@ -0,0 +1,62 @@ +From 5e86e00b376fb3557d50b1a6359ff271d1c6a1ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:25:15 +0000 +Subject: ALSA: hda: cs35l41: Fix boost type for HP Dragonfly 13.5 inch G4 + +From: Leonard Lausen + +[ Upstream commit 6389dbd5c4a2d819ec342f89bd65883ab021278e ] + +The HP Dragonfly 13.5 inch G4 (SSID 103C8B63) has _DSD properties in +ACPI firmware with valid reset-gpios and cs-gpios for the four CS35L41 +amplifiers on SPI. + +However, the _DSD specifies cirrus,boost-type as Internal (0), while +the hardware requires External Boost. With Internal Boost configured, +the amplifiers trigger "Amp short error" when audio is played at +moderate-to-high volume, eventually shutting down entirely. + +Add a configuration table entry to override the boost type to +External, similar to the existing workaround for 103C89C6. All GPIO +indices are set to -1 since the _DSD provides valid reset-gpios and +cs-gpios. + +Confirmed on BIOS V90 01.11.00 (January 2026), the latest available. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=219520 +Originally-by: Nicholas Wang +Signed-off-by: Leonard Lausen +Link: https://patch.msgid.link/db84dcf91bc8dbd217b35572b177d967655ff903@lausen.nl +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/cs35l41_hda_property.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c +index d8249d997c2a0..b02da00fd686b 100644 +--- a/sound/pci/hda/cs35l41_hda_property.c ++++ b/sound/pci/hda/cs35l41_hda_property.c +@@ -55,6 +55,11 @@ static const struct cs35l41_config cs35l41_config_table[] = { + { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 }, ++/* ++ * Device 103C8B63 has _DSD with valid reset-gpios and cs-gpios, however the ++ * boost type is incorrectly set to Internal. Override to External Boost. ++ */ ++ { "103C8B63", 4, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, -1, -1, -1, 0, 0, 0 }, + { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, +@@ -473,6 +478,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { + { "CSC3551", "103C8A30", generic_dsd_config }, + { "CSC3551", "103C8A31", generic_dsd_config }, + { "CSC3551", "103C8A6E", generic_dsd_config }, ++ { "CSC3551", "103C8B63", generic_dsd_config }, + { "CSC3551", "103C8BB3", generic_dsd_config }, + { "CSC3551", "103C8BB4", generic_dsd_config }, + { "CSC3551", "103C8BDD", generic_dsd_config }, +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch b/queue-6.12/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch new file mode 100644 index 0000000000..7787d5a2e9 --- /dev/null +++ b/queue-6.12/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch @@ -0,0 +1,48 @@ +From 570ba86d67b0f6b355fc29160b18d09c7ca8f3ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:12:38 +0800 +Subject: ALSA: hda: cs35l41: Put ACPI device on missing physical node + +From: Shuhao Fu + +[ Upstream commit fca7401fe37f7abc6e54147ea560f37279231137 ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers must balance it with acpi_dev_put(). + +cs35l41_hda_read_acpi() stores the returned ACPI device in +cs35l41->dacpi. That reference is normally released by the later +probe cleanup or the remove path, but the NULL-check on +physdev exits before either of those paths can run. + +Drop the lookup reference before returning -ENODEV. + +Fixes: c34b04cc6178 ("ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_hda_read_acpi()") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428081238.GA1659932@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/pci/hda/cs35l41_hda.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index e115b9bd7ce3d..42c576d9f1179 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -1865,8 +1865,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i + + cs35l41->dacpi = adev; + physdev = get_device(acpi_get_first_physical_node(adev)); +- if (!physdev) ++ if (!physdev) { ++ acpi_dev_put(adev); + return -ENODEV; ++ } + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch b/queue-6.12/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch new file mode 100644 index 0000000000..23383f33e1 --- /dev/null +++ b/queue-6.12/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch @@ -0,0 +1,44 @@ +From b70fcd3948c02394d64ee9081f9b07a1a55dfb9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:01:39 +0800 +Subject: ALSA: hda: cs35l56: Put ACPI device after setting companion + +From: Shuhao Fu + +[ Upstream commit aa2fbece1b07954ef26488c800d126a36a8ab93e ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers are expected to balance it with acpi_dev_put(). + +When no companion is already attached, cs35l56_hda_read_acpi() looks +up an ACPI device and sets it with ACPI_COMPANION_SET(), but leaves +the lookup reference held. + +ACPI_COMPANION_SET() does not take ownership of that reference, so +drop it with acpi_dev_put() after attaching the companion. + +Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428080139.GA1649104@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/pci/hda/cs35l56_hda.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c +index ee5387140ae48..5c0c4b79f5197 100644 +--- a/sound/pci/hda/cs35l56_hda.c ++++ b/sound/pci/hda/cs35l56_hda.c +@@ -953,6 +953,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); ++ acpi_dev_put(adev); + } + + /* Initialize things that could be overwritten by a fixup */ +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch b/queue-6.12/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch new file mode 100644 index 0000000000..ee9328123f --- /dev/null +++ b/queue-6.12/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch @@ -0,0 +1,36 @@ +From 2672626e629c39f0a49281b9ae09d455ed9bb90a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 15:20:25 -0600 +Subject: ALSA: hda/realtek: Add quirk for Acer PT316-51S headset mic + +From: Faye Nichols + +[ Upstream commit a7b56be59b47f4195ddc79ecab238c4401a60bbb ] + +The Acer PT316-51S (PCI SSID 1025:160e) with ALC287 codec does not +detect the headset microphone due to missing BIOS pin configuration +for pin 0x19. Apply ALC2XX_FIXUP_HEADSET_MIC to enable it. + +Signed-off-by: Faye Nichols +Link: https://patch.msgid.link/20260413212645.117119-1-faye.opensource@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index b0ee9b58e0570..a5cbbd9bf60bf 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10698,6 +10698,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch b/queue-6.12/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch new file mode 100644 index 0000000000..1a55e12c6d --- /dev/null +++ b/queue-6.12/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch @@ -0,0 +1,47 @@ +From 221ded89116bf5e9b12825b98f9e7edd5740b726 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:18:54 +0800 +Subject: ALSA: hda/realtek: Add quirk for HP Spectre x360 14-ea + +From: songxiebing + +[ Upstream commit 882321ccaeea52dd645dff98bfea2f92b286e673 ] + +HP Spectre x360 Convertible 14-ea0xxx (2021 model or so) +doesn't make produce sound,The Bang & Olufsen speaker amplifier +is not enabled. + +Root causing: +The PCI subsystem ID is 103c:0000 (HP left it unset), while the codec +subsystem ID is 103c:885b. The vendor-wide catch-all +SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED) matches +103c:0000 before the codec SSID fallback is reached, so +ALC245_FIXUP_HP_X360_AMP never applies. + +So add the quirk in alc269_fixup_tbl. + +Reported-by: dzidmail +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221341 +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260413011854.96520-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index a5cbbd9bf60bf..a653daf6f9533 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10928,6 +10928,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), ++ HDA_CODEC_QUIRK(0x103c, 0x885b, "HP Spectre x360 14-ea", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +-- +2.53.0 + diff --git a/queue-6.12/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-6.12/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..a7644a9143 --- /dev/null +++ b/queue-6.12/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From c4f7a051b7746dd0baa8f2d2d08c9a67dba23490 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 23708dc02401f..1fd47d013a262 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1761,6 +1761,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1773,8 +1776,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-6.12/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch b/queue-6.12/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch new file mode 100644 index 0000000000..89d0de8822 --- /dev/null +++ b/queue-6.12/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch @@ -0,0 +1,60 @@ +From 555ba0592e4807ba025d69de1882231a6473fd43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 20:02:21 -0300 +Subject: ALSA: pcm: Use pcm_lib_apply_appl_ptr() in x32 sync_ptr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1e512ac1254c8e370dd18efe9da4dfc92492cdc5 ] + +snd_pcm_ioctl_sync_ptr_x32() still handles incoming appl_ptr updates +differently from the other SYNC_PTR paths. The native handler and the +32-bit compat handler both pass appl_ptr through pcm_lib_apply_appl_ptr(), +but the x32 handler still writes control->appl_ptr directly. + +That direct assignment skips the common appl_ptr validation against +runtime->boundary and also bypasses the substream ack() callback. +This makes the x32 ioctl path behave differently from the native and +compat32 cases, and it can miss the driver notification that explicit +appl_ptr synchronization relies on. + +Use pcm_lib_apply_appl_ptr() for x32 too, so appl_ptr updates are +validated consistently and drivers relying on ack() notifications +see the same behavior. + +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260321-alsa-pcm-x32-sync-ptr-v1-1-02ce655657c6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_compat.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index c1c64da2eabd0..2ab3c4155fed1 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -434,11 +434,13 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, + if (!boundary) + boundary = 0x7fffffff; + scoped_guard(pcm_stream_lock_irq, substream) { +- /* FIXME: we should consider the boundary for the sync from app */ +- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) +- control->appl_ptr = scontrol.appl_ptr; +- else ++ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { ++ err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr); ++ if (err < 0) ++ return err; ++ } else { + scontrol.appl_ptr = control->appl_ptr % boundary; ++ } + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else +-- +2.53.0 + diff --git a/queue-6.12/alsa-scarlett2-add-missing-error-check-when-initiali.patch b/queue-6.12/alsa-scarlett2-add-missing-error-check-when-initiali.patch new file mode 100644 index 0000000000..919f51a28d --- /dev/null +++ b/queue-6.12/alsa-scarlett2-add-missing-error-check-when-initiali.patch @@ -0,0 +1,41 @@ +From 515e19863358f9c2f12e9cf01194da494c91e775 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 10:39:14 +0700 +Subject: ALSA: scarlett2: Add missing error check when initialise Autogain + Status + +From: Robertus Diawan Chris + +[ Upstream commit c0e4fffc0f474b7ed10adee4ab2bc1a66d36fc72 ] + +When initialise new control with scarlett2_add_new_ctl() function for +Autogain Status, scarlett2_add_new_ctl() might throw an error. So, add +error check after initialise new control for Autogain Status. + +This is reported by Coverity Scan with CID 1598781 as UNUSED_VALUE. + +Fixes: 0a995e38dc44 ("ALSA: scarlett2: Add support for software-controllable input gain") +Signed-off-by: Robertus Diawan Chris +Link: https://patch.msgid.link/20260508033914.111596-1-robertusdchris@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index ef5945aa40e4a..d767a89e452d1 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -6956,6 +6956,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_status_ctl, + i, 1, s, &private->autogain_status_ctls[i]); ++ if (err < 0) ++ return err; + } + + /* Add autogain target controls */ +-- +2.53.0 + diff --git a/queue-6.12/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-6.12/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..082af83a59 --- /dev/null +++ b/queue-6.12/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From fb96a2dcc26875322f2a0032f4d5413a46b2a7fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index fd7a766331c7d..6b7053e19f6c7 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1191,6 +1191,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-6.12/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-6.12/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..8404bcb70e --- /dev/null +++ b/queue-6.12/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From a3e10a20a8fe8f9f4dc16cd71e77593b68a12f1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index a395b6c0aae2a..56f6d8327d5c8 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -218,8 +218,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -228,9 +229,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-6.12/arm64-tegra-fix-snps-blen-properties.patch b/queue-6.12/arm64-tegra-fix-snps-blen-properties.patch new file mode 100644 index 0000000000..a5d04e5596 --- /dev/null +++ b/queue-6.12/arm64-tegra-fix-snps-blen-properties.patch @@ -0,0 +1,52 @@ +From cdbb19dad29801ab33bc9162eee59d59825d92b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 15:33:04 +0100 +Subject: arm64: tegra: Fix snps,blen properties + +From: Thierry Reding + +[ Upstream commit 51f10c527a63dc4a71bce4b40fc53eee78bbbd52 ] + +The snps,blen property of stmmac-axi-config nodes needs to have 7 +entries in total, with unsupported burst lengths listed as 0. + +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/nvidia/tegra234.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +index 2601b43b2d8ca..ab3319e727986 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +@@ -3545,7 +3545,7 @@ ethernet@6800000 { + snps,axi-config = <&mgbe0_axi_setup>; + + mgbe0_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3587,7 +3587,7 @@ ethernet@6900000 { + snps,axi-config = <&mgbe1_axi_setup>; + + mgbe1_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3629,7 +3629,7 @@ ethernet@6a00000 { + snps,axi-config = <&mgbe2_axi_setup>; + + mgbe2_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +-- +2.53.0 + diff --git a/queue-6.12/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch b/queue-6.12/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch new file mode 100644 index 0000000000..8474054aa7 --- /dev/null +++ b/queue-6.12/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch @@ -0,0 +1,47 @@ +From 70d056cf6946020c77df9193d74e5aaabce93269 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:45:53 +0200 +Subject: ASoC: amd: yc: Add MSI Vector A16 HX A8WHG to quirk table + +From: Ihor Uzlov + +[ Upstream commit 72dcd84938f5026dc44d0e7e1e68d9d571c113a0 ] + +Add the MSI Vector A16 HX A8WHG (board MS-15MM) to the DMI quirk table +to enable DMIC support. This laptop uses an AMD Ryzen 9 7945HX (Dragon +Range) with the ACP6x audio coprocessor (rev 0x62) and a Realtek ALC274 +codec. The built-in digital microphone is connected via the ACP PDM +interface and requires this DMI entry to be activated. + +Tested on MSI Vector A16 HX A8WHG with kernel 6.8.0-107 (Ubuntu 24.04). +DMIC capture device appears as 'acp6x' and records audio correctly. + +Signed-off-by: Ihor Uzlov +Link: https://patch.msgid.link/20260410094553.24654-1-igor.uzlov@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index e2ad7113c916c..46e2fe7fc32c1 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -493,6 +493,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +-- +2.53.0 + diff --git a/queue-6.12/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch b/queue-6.12/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch new file mode 100644 index 0000000000..5afbf3c0e5 --- /dev/null +++ b/queue-6.12/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch @@ -0,0 +1,65 @@ +From 065a230cad62671c42c0ceee07c59dea9d391a23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:34:08 +0800 +Subject: ASoC: aw88395: Fix kernel panic caused by invalid GPIO error pointer + +From: wangdicheng + +[ Upstream commit 241ee17ecb6be210f7b231b2a81bfb68871950d0 ] + +In aw88395_i2c_probe(), if `devm_gpiod_get_optional()` fails, it returns +an ERR_PTR() error pointer. The current code only prints a message and +continues execution, leaving `aw88395->reset_gpio` as an invalid pointer. + +Later, in `aw88395_hw_reset()`, this invalid pointer is passed to +`gpiod_set_value_cansleep()`, which dereferences it and causes a kernel +panic. + +For optional GPIOs, `devm_gpiod_get_optional()` returns NULL if the GPIO +is not defined in the DT, which is safe. If it returns an ERR_PTR, it +means a real error occurred (e.g., -EPROBE_DEFER) and the probe must be +aborted. + +Also, since the GPIO is optional, remove the dev_err() log in +aw88395_hw_reset() when the GPIO is missing to match the optional +semantics. This also fixes a potential NULL pointer dereference as +aw_pa is not initialized when aw88395_hw_reset() is called. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428023408.46420-1-wangdich9700@163.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/aw88395/aw88395.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c +index aea44a199b98e..c5296fb71e375 100644 +--- a/sound/soc/codecs/aw88395/aw88395.c ++++ b/sound/soc/codecs/aw88395/aw88395.c +@@ -458,8 +458,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); + gpiod_set_value_cansleep(aw88395->reset_gpio, 1); + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); +- } else { +- dev_err(aw88395->aw_pa->dev, "%s failed", __func__); + } + } + +@@ -524,9 +522,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) + i2c_set_clientdata(i2c, aw88395); + + aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(aw88395->reset_gpio)) +- dev_info(&i2c->dev, "reset gpio not defined\n"); +- ++ if (IS_ERR(aw88395->reset_gpio)) { ++ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), ++ "failed to get reset gpio\n"); ++ } + /* hardware reset */ + aw88395_hw_reset(aw88395); + +-- +2.53.0 + diff --git a/queue-6.12/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-6.12/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..87f15be877 --- /dev/null +++ b/queue-6.12/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From bb81c352950d1ab854876659ee9ec688f6f7759b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index d96e23ec43d4c..cf09b66eb2873 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -848,9 +848,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch b/queue-6.12/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch new file mode 100644 index 0000000000..7ddc9f8146 --- /dev/null +++ b/queue-6.12/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch @@ -0,0 +1,88 @@ +From 23e5cd99d3016fb524d942c845d16c856530ed83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:32:21 +0530 +Subject: ASoC: codecs: wcd937x: fix AUX PA sequencing and mixer controls + +From: Ajay Kumar Nandam + +[ Upstream commit 74c876bfd71b1023029a483d7213015201f62b53 ] + +Enable AUX PA sequencing during AUX DAC DAPM events and keep the +AUX-specific RX supplies enabled while the path is active. + +Add the missing AUX-related mixer controls, including CLSH PA and +DSD left/right switches, so AUX playback can be routed from userspace. + +Signed-off-by: Ajay Kumar Nandam +Link: https://patch.msgid.link/20260420180221.785113-1-ajay.nandam@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd937x.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c +index 17ddd91eac5fc..a416dfac3fe1a 100644 +--- a/sound/soc/codecs/wcd937x.c ++++ b/sound/soc/codecs/wcd937x.c +@@ -548,6 +548,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), BIT(2)); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), BIT(4)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(2), BIT(2)); +@@ -564,6 +567,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), 0x00); + break; + } + +@@ -732,10 +738,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); ++ /* Enable AUX PA related RX supplies */ ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), BIT(6)); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), BIT(7)); + enable_irq(wcd937x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->aux_pdm_wd_int); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(2000, 2010); +@@ -2056,7 +2075,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), +- ++ SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, +-- +2.53.0 + diff --git a/queue-6.12/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-6.12/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..be285c5eed --- /dev/null +++ b/queue-6.12/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 1912c8648fe1f3837bc1a88ab1cc6d477265af89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index d6991864c5a49..e1c30a227c0cf 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -289,6 +289,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.12/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-6.12/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..dfbbb713c4 --- /dev/null +++ b/queue-6.12/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From c734f59c599bf7bbb942f32a117d6436d6b8d54c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index 6860ac41e6b32..3f410af0c7ee3 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -210,6 +210,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.12/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-6.12/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..6436ec9c89 --- /dev/null +++ b/queue-6.12/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From 5534cb88c3faf660a62d9143c107787dde6a6d3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index c6c469d51243e..b1ce969dd555e 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-6.12/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch b/queue-6.12/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch new file mode 100644 index 0000000000..5b7cab0873 --- /dev/null +++ b/queue-6.12/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch @@ -0,0 +1,46 @@ +From 278fc98065b2e5663a6a2bba31c549ca32f8b350 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 13:30:51 +0800 +Subject: ASoC: mxs-sgtl5000: disable MCLK on error paths of + mxs_sgtl5000_probe() + +From: Haoxiang Li + +[ Upstream commit c8ef13d692f19cdbbf195fb845421a5b71801704 ] + +Call mxs_saif_put_mclk() to disable MCLK on error +paths of mxs_sgtl5000_probe(). + +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260401053051.586290-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/mxs/mxs-sgtl5000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c +index a41a13ae38a50..8ad54458f1bf3 100644 +--- a/sound/soc/mxs/mxs-sgtl5000.c ++++ b/sound/soc/mxs/mxs-sgtl5000.c +@@ -157,13 +157,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); ++ mxs_saif_put_mclk(0); + return ret; + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) ++ if (ret) { ++ mxs_saif_put_mclk(0); + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-qcom-x1e80100-limit-speaker-volumes.patch b/queue-6.12/asoc-qcom-x1e80100-limit-speaker-volumes.patch new file mode 100644 index 0000000000..9724820b91 --- /dev/null +++ b/queue-6.12/asoc-qcom-x1e80100-limit-speaker-volumes.patch @@ -0,0 +1,75 @@ +From 59ab53e725c27264e24e142677205742a185ef42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 15:30:59 +0200 +Subject: ASoC: qcom: x1e80100: limit speaker volumes + +From: Tobias Heider + +[ Upstream commit 0a5ee0e520eff98ee2b4568194562870877b050f ] + +Limit the digital gain and PA volumes to a combined -3 dB in the machine +driver to reduce the risk of speaker damage until we have active speaker +protection in place (or higher safe levels have been established). + +Based on commit c481016bb4f8 ("ASoC: qcom: sc8280xp: limit speaker +volumes") which addressed the same issue on the sc8280x SoC with some +minor changes as explained below. + +The Digital Volume behaves almost identical to sc8280x since both use +the same lpass-wsa-macro, but x1e80100 has two sets of controls prefixed +with WSA and WSA2. +For PA x1e80100 machines use wsa884x amplifiers which expose a linear +scale from -9 dB to 9 dB with a 1.5 dB step size giving us +0 dB = -9 dB + 6 * 1.5 dB. + +On x1e80100 there are two different speaker topologies we need to handle: + 2-Speakers: SpkrLeft, Spkr Right + 4-Speakers: WooferLeft, WooferRight, TweeterLeft, TweeterRight + +Signed-off-by: Tobias Heider +Tested-by: Srinivas Kandagatla +Reviewed-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260422-x1e80100-audio-limit-v2-1-333258b97697@canonical.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/x1e80100.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c +index 3645fafcd45a5..dabcb06d6e321 100644 +--- a/sound/soc/qcom/x1e80100.c ++++ b/sound/soc/qcom/x1e80100.c +@@ -28,10 +28,29 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) + { + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_card *card = rtd->card; + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; + + switch (cpu_dai->id) { ++ case WSA_CODEC_DMA_RX_0: ++ case WSA_CODEC_DMA_RX_1: ++ /* ++ * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume ++ * to reduce the risk of speaker damage until we have active ++ * speaker protection in place. ++ */ ++ snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "SpkrRight PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferRight PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterRight PA Volume", 6); ++ break; + case DISPLAY_PORT_RX_0: + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; +-- +2.53.0 + diff --git a/queue-6.12/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-6.12/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..c2fd0fcb7f --- /dev/null +++ b/queue-6.12/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From 37b7106cd95f5ce6b2ea0b4c848c98a25626884e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index c366ae2275e86..89d820983c72f 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1838,6 +1838,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + unsigned int pll_bit = 0; + int ret; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + ret = clk_set_rate(rt5640->mclk, freq); +-- +2.53.0 + diff --git a/queue-6.12/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-6.12/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..9c2ed50670 --- /dev/null +++ b/queue-6.12/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From 2d3c0bfb7c25fca05e9386794717ba085cdd0a01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index 684d52ec66006..c14014fb61561 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -490,7 +490,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -499,7 +499,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -588,7 +588,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { +@@ -613,7 +613,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -626,7 +626,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-6.12/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-6.12/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..8173256005 --- /dev/null +++ b/queue-6.12/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From ae11a96377be523e6d14e6b9e8e28b1f93ab6b0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index a0b8cca31cba0..36f9696fd608b 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2528,6 +2528,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-6.12/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-6.12/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..079c8ee71c --- /dev/null +++ b/queue-6.12/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From 34629b218a64a0a5f559210c52373e18cabbd16f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 59788a34871a1..b5c907cf39f3f 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2988,7 +2988,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-6.12/blk-integrity-enable-p2p-source-and-destination.patch b/queue-6.12/blk-integrity-enable-p2p-source-and-destination.patch new file mode 100644 index 0000000000..e265112433 --- /dev/null +++ b/queue-6.12/blk-integrity-enable-p2p-source-and-destination.patch @@ -0,0 +1,89 @@ +From b71ff5a42e1305c55f6372c71b54f9da5cd7169c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Sep 2025 12:33:16 -0700 +Subject: blk-integrity: enable p2p source and destination + +From: Keith Busch + +[ Upstream commit 05ceea5d3ec9a1b1d6858ffd4739fdb0ed1b8eaf ] + +Set the extraction flags to allow p2p pages for the metadata buffer if +the block device allows it. Similar to data payloads, ensure the bio +does not use merging if we see a p2p page. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Martin K. Petersen +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Stable-dep-of: 8582792cf23b ("block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()") +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index a7788bbe35979..2a02222f4298c 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -268,7 +268,8 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, + } + + static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, +- int nr_vecs, ssize_t bytes, ssize_t offset) ++ int nr_vecs, ssize_t bytes, ssize_t offset, ++ bool *is_p2p) + { + unsigned int nr_bvecs = 0; + int i, j; +@@ -289,6 +290,9 @@ static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + bytes -= next; + } + ++ if (is_pci_p2pdma_page(pages[i])) ++ *is_p2p = true; ++ + bvec_set_page(&bvec[nr_bvecs], pages[i], size, offset); + offset = 0; + nr_bvecs++; +@@ -302,10 +306,11 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; ++ iov_iter_extraction_t extraction_flags = 0; + size_t offset, bytes = iter->count; ++ bool copy, is_p2p = false; + unsigned int nr_bvecs; + int ret, nr_vecs; +- bool copy; + + if (bio_integrity(bio)) + return -EINVAL; +@@ -324,15 +329,23 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + + copy = iov_iter_alignment(iter) & + blk_lim_dma_alignment_and_pad(&q->limits); +- ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs, 0, &offset); ++ ++ if (blk_queue_pci_p2pdma(q)) ++ extraction_flags |= ITER_ALLOW_P2PDMA; ++ ++ ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs, ++ extraction_flags, &offset); + if (unlikely(ret < 0)) + goto free_bvec; + +- nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset); ++ nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, ++ &is_p2p); + if (pages != stack_pages) + kvfree(pages); + if (nr_bvecs > queue_max_integrity_segments(q)) + copy = true; ++ if (is_p2p) ++ bio->bi_opf |= REQ_NOMERGE; + + if (copy) + ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes); +-- +2.53.0 + diff --git a/queue-6.12/blk-integrity-remove-seed-for-user-mapped-buffers.patch b/queue-6.12/blk-integrity-remove-seed-for-user-mapped-buffers.patch new file mode 100644 index 0000000000..375e0e1fbd --- /dev/null +++ b/queue-6.12/blk-integrity-remove-seed-for-user-mapped-buffers.patch @@ -0,0 +1,230 @@ +From f2d8ad366d5a32328fafc9f76370b1dd87b27860 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Oct 2024 13:13:09 -0700 +Subject: blk-integrity: remove seed for user mapped buffers + +From: Keith Busch + +[ Upstream commit 133008e84b99e4f5f8cf3d8b768c995732df9406 ] + +The seed is only used for kernel generation and verification. That +doesn't happen for user buffers, so passing the seed around doesn't +accomplish anything. + +Signed-off-by: Keith Busch +Reviewed-by: Christoph Hellwig +Reviewed-by: Anuj Gupta +Reviewed-by: Kanchan Joshi +Link: https://lore.kernel.org/r/20241016201309.1090320-1-kbusch@meta.com +Signed-off-by: Jens Axboe +Stable-dep-of: 637ad3a56a3b ("block: don't overwrite bip_vcnt in bio_integrity_copy_user()") +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 13 +++++-------- + block/blk-integrity.c | 4 ++-- + drivers/nvme/host/ioctl.c | 17 ++++++++--------- + include/linux/bio-integrity.h | 4 ++-- + include/linux/blk-integrity.h | 5 ++--- + 5 files changed, 19 insertions(+), 24 deletions(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 6641ecbf69678..ab58f44058e96 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -197,7 +197,7 @@ EXPORT_SYMBOL(bio_integrity_add_page); + + static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + int nr_vecs, unsigned int len, +- unsigned int direction, u32 seed) ++ unsigned int direction) + { + bool write = direction == ITER_SOURCE; + struct bio_integrity_payload *bip; +@@ -245,7 +245,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + } + + bip->bip_flags |= BIP_COPY_USER; +- bip->bip_iter.bi_sector = seed; + bip->bip_vcnt = nr_vecs; + return 0; + free_bip: +@@ -256,7 +255,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + } + + static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, +- int nr_vecs, unsigned int len, u32 seed) ++ int nr_vecs, unsigned int len) + { + struct bio_integrity_payload *bip; + +@@ -265,7 +264,6 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, + return PTR_ERR(bip); + + memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec)); +- bip->bip_iter.bi_sector = seed; + bip->bip_iter.bi_size = len; + bip->bip_vcnt = nr_vecs; + return 0; +@@ -301,8 +299,7 @@ static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + return nr_bvecs; + } + +-int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, +- u32 seed) ++int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes) + { + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + unsigned int align = blk_lim_dma_alignment_and_pad(&q->limits); +@@ -348,9 +345,9 @@ int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, + + if (copy) + ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, +- direction, seed); ++ direction); + else +- ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes, seed); ++ ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes); + if (ret) + goto release_pages; + if (bvec != stack_vec) +diff --git a/block/blk-integrity.c b/block/blk-integrity.c +index 3fe0681399f6e..013469faa5e7c 100644 +--- a/block/blk-integrity.c ++++ b/block/blk-integrity.c +@@ -113,9 +113,9 @@ int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) + EXPORT_SYMBOL(blk_rq_map_integrity_sg); + + int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf, +- ssize_t bytes, u32 seed) ++ ssize_t bytes) + { +- int ret = bio_integrity_map_user(rq->bio, ubuf, bytes, seed); ++ int ret = bio_integrity_map_user(rq->bio, ubuf, bytes); + + if (ret) + return ret; +diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c +index 64ae8af01d9a4..930521c633d23 100644 +--- a/drivers/nvme/host/ioctl.c ++++ b/drivers/nvme/host/ioctl.c +@@ -114,7 +114,7 @@ static struct request *nvme_alloc_user_request(struct request_queue *q, + + static int nvme_map_user_request(struct request *req, u64 ubuffer, + unsigned bufflen, void __user *meta_buffer, unsigned meta_len, +- u32 meta_seed, struct io_uring_cmd *ioucmd, unsigned int flags) ++ struct io_uring_cmd *ioucmd, unsigned int flags) + { + struct request_queue *q = req->q; + struct nvme_ns *ns = q->queuedata; +@@ -164,8 +164,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + bio_set_dev(bio, bdev); + + if (has_metadata) { +- ret = blk_rq_integrity_map_user(req, meta_buffer, meta_len, +- meta_seed); ++ ret = blk_rq_integrity_map_user(req, meta_buffer, meta_len); + if (ret) + goto out_unmap; + } +@@ -182,7 +181,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + + static int nvme_submit_user_cmd(struct request_queue *q, + struct nvme_command *cmd, u64 ubuffer, unsigned bufflen, +- void __user *meta_buffer, unsigned meta_len, u32 meta_seed, ++ void __user *meta_buffer, unsigned meta_len, + u64 *result, unsigned timeout, unsigned int flags) + { + struct nvme_ns *ns = q->queuedata; +@@ -199,7 +198,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, + req->timeout = timeout; + if (ubuffer && bufflen) { + ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer, +- meta_len, meta_seed, NULL, flags); ++ meta_len, NULL, flags); + if (ret) + return ret; + } +@@ -280,7 +279,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) + c.rw.lbatm = cpu_to_le16(io.appmask); + + return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata, +- meta_len, lower_32_bits(io.slba), NULL, 0, 0); ++ meta_len, NULL, 0, 0); + } + + static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl, +@@ -334,7 +333,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, + + status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, + cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), +- cmd.metadata_len, 0, &result, timeout, 0); ++ cmd.metadata_len, &result, timeout, 0); + + if (status >= 0) { + if (put_user(result, &ucmd->result)) +@@ -381,7 +380,7 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, + + status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, + cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), +- cmd.metadata_len, 0, &cmd.result, timeout, flags); ++ cmd.metadata_len, &cmd.result, timeout, flags); + + if (status >= 0) { + if (put_user(cmd.result, &ucmd->result)) +@@ -511,7 +510,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, + if (d.addr && d.data_len) { + ret = nvme_map_user_request(req, d.addr, + d.data_len, nvme_to_user_ptr(d.metadata), +- d.metadata_len, 0, ioucmd, vec); ++ d.metadata_len, ioucmd, vec); + if (ret) + return ret; + } +diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h +index dd831c269e994..dbf0f74c15291 100644 +--- a/include/linux/bio-integrity.h ++++ b/include/linux/bio-integrity.h +@@ -72,7 +72,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp, + unsigned int nr); + int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len, + unsigned int offset); +-int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len, u32 seed); ++int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len); + void bio_integrity_unmap_user(struct bio *bio); + bool bio_integrity_prep(struct bio *bio); + void bio_integrity_advance(struct bio *bio, unsigned int bytes_done); +@@ -99,7 +99,7 @@ static inline void bioset_integrity_free(struct bio_set *bs) + } + + static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf, +- ssize_t len, u32 seed) ++ ssize_t len) + { + return -EINVAL; + } +diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h +index 676f8f860c474..c7eae0bfb013f 100644 +--- a/include/linux/blk-integrity.h ++++ b/include/linux/blk-integrity.h +@@ -28,7 +28,7 @@ static inline bool queue_limits_stack_integrity_bdev(struct queue_limits *t, + int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); + int blk_rq_count_integrity_sg(struct request_queue *, struct bio *); + int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf, +- ssize_t bytes, u32 seed); ++ ssize_t bytes); + + static inline bool + blk_integrity_queue_supports_integrity(struct request_queue *q) +@@ -104,8 +104,7 @@ static inline int blk_rq_map_integrity_sg(struct request *q, + } + static inline int blk_rq_integrity_map_user(struct request *rq, + void __user *ubuf, +- ssize_t bytes, +- u32 seed) ++ ssize_t bytes) + { + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.12/blk-integrity-use-simpler-alignment-check.patch b/queue-6.12/blk-integrity-use-simpler-alignment-check.patch new file mode 100644 index 0000000000..55149551a0 --- /dev/null +++ b/queue-6.12/blk-integrity-use-simpler-alignment-check.patch @@ -0,0 +1,48 @@ +From 750cd4c019807d59a26f1bd564dea37b98065d27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Aug 2025 07:12:57 -0700 +Subject: blk-integrity: use simpler alignment check + +From: Keith Busch + +[ Upstream commit 69d7ed5b9ef661230264bfa0db4c96fa25b8efa4 ] + +We're checking length and addresses against the same alignment value, so +use the more simple iterator check. + +Signed-off-by: Keith Busch +Reviewed-by: Hannes Reinecke +Reviewed-by: Martin K. Petersen +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Stable-dep-of: 8582792cf23b ("block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()") +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 6801754838bc1..a7788bbe35979 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -300,7 +300,6 @@ static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + { + struct request_queue *q = bdev_get_queue(bio->bi_bdev); +- unsigned int align = blk_lim_dma_alignment_and_pad(&q->limits); + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; + size_t offset, bytes = iter->count; +@@ -323,7 +322,8 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + pages = NULL; + } + +- copy = !iov_iter_is_aligned(iter, align, align); ++ copy = iov_iter_alignment(iter) & ++ blk_lim_dma_alignment_and_pad(&q->limits); + ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs, 0, &offset); + if (unlikely(ret < 0)) + goto free_bvec; +-- +2.53.0 + diff --git a/queue-6.12/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch b/queue-6.12/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch new file mode 100644 index 0000000000..90059d0217 --- /dev/null +++ b/queue-6.12/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch @@ -0,0 +1,215 @@ +From a016390171337218c530c22c0ed6899c6992ac80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:05:09 +0000 +Subject: blk-iocost: fix busy_level reset when no IOs complete + +From: Jialin Wang + +[ Upstream commit f91ffe89b2016d280995a9c28d73288b02d83615 ] + +When a disk is saturated, it is common for no IOs to complete within a +timer period. Currently, in this case, rq_wait_pct and missed_ppm are +calculated as 0, the iocost incorrectly interprets this as meeting QoS +targets and resets busy_level to 0. + +This reset prevents busy_level from reaching the threshold (4) needed +to reduce vrate. On certain cloud storage, such as Azure Premium SSD, +we observed that iocost may fail to reduce vrate for tens of seconds +during saturation, failing to mitigate noisy neighbor issues. + +Fix this by tracking the number of IO completions (nr_done) in a period. +If nr_done is 0 and there are lagging IOs, the saturation status is +unknown, so we keep busy_level unchanged. + +The issue is consistently reproducible on Azure Standard_D8as_v5 (Dasv5) +VMs with 512GB Premium SSD (P20) using the script below. It was not +observed on GCP n2d VMs (with 100G pd-ssd and 1.5T local-ssd), and no +regressions were found with this patch. In this script, cgA performs +large IOs with iodepth=128, while cgB performs small IOs with iodepth=1 +rate_iops=100 rw=randrw. With iocost enabled, we expect it to throttle +cgA, the submission latency (slat) of cgA should be significantly higher, +cgB can reach 200 IOPS and the completion latency (clat) should below. + + BLK_DEVID="8:0" + MODEL="rbps=173471131 rseqiops=3566 rrandiops=3566 wbps=173333269 wseqiops=3566 wrandiops=3566" + QOS="rpct=90 rlat=3500 wpct=90 wlat=3500 min=80 max=10000" + + echo "$BLK_DEVID ctrl=user model=linear $MODEL" > /sys/fs/cgroup/io.cost.model + echo "$BLK_DEVID enable=1 ctrl=user $QOS" > /sys/fs/cgroup/io.cost.qos + + CG_A="/sys/fs/cgroup/cgA" + CG_B="/sys/fs/cgroup/cgB" + + FILE_A="/path/to/sda/A.fio.testfile" + FILE_B="/path/to/sda/B.fio.testfile" + RESULT_DIR="./iocost_results_$(date +%Y%m%d_%H%M%S)" + + mkdir -p "$CG_A" "$CG_B" "$RESULT_DIR" + + get_result() { + local file=$1 + local label=$2 + + local results=$(jq -r ' + .jobs[0].mixed | + ( .iops | tonumber | round ) as $iops | + ( .bw_bytes / 1024 / 1024 ) as $bps | + ( .slat_ns.mean / 1000000 ) as $slat | + ( .clat_ns.mean / 1000000 ) as $avg | + ( .clat_ns.max / 1000000 ) as $max | + ( .clat_ns.percentile["90.000000"] / 1000000 ) as $p90 | + ( .clat_ns.percentile["99.000000"] / 1000000 ) as $p99 | + ( .clat_ns.percentile["99.900000"] / 1000000 ) as $p999 | + ( .clat_ns.percentile["99.990000"] / 1000000 ) as $p9999 | + "\($iops)|\($bps)|\($slat)|\($avg)|\($max)|\($p90)|\($p99)|\($p999)|\($p9999)" + ' "$file") + + IFS='|' read -r iops bps slat avg max p90 p99 p999 p9999 <<<"$results" + printf "%-8s %-6s %-7.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f\n" \ + "$label" "$iops" "$bps" "$slat" "$avg" "$max" "$p90" "$p99" "$p999" "$p9999" + } + + run_fio() { + local cg_path=$1 + local filename=$2 + local name=$3 + local bs=$4 + local qd=$5 + local out=$6 + shift 6 + local extra=$@ + + ( + pid=$(sh -c 'echo $PPID') + echo $pid >"${cg_path}/cgroup.procs" + fio --name="$name" --filename="$filename" --direct=1 --rw=randrw --rwmixread=50 \ + --ioengine=libaio --bs="$bs" --iodepth="$qd" --size=4G --runtime=10 \ + --time_based --group_reporting --unified_rw_reporting=mixed \ + --output-format=json --output="$out" $extra >/dev/null 2>&1 + ) & + } + + echo "Starting Test ..." + + for bs_b in "4k" "32k" "256k"; do + echo "Running iteration: BS=$bs_b" + out_a="${RESULT_DIR}/cgA_1m.json" + out_b="${RESULT_DIR}/cgB_${bs_b}.json" + + # cgA: Heavy background (BS 1MB, QD 128) + run_fio "$CG_A" "$FILE_A" "cgA" "1m" 128 "$out_a" + # cgB: Latency sensitive (Variable BS, QD 1, Read/Write IOPS limit 100) + run_fio "$CG_B" "$FILE_B" "cgB" "$bs_b" 1 "$out_b" "--rate_iops=100" + + wait + SUMMARY_DATA+="$(get_result "$out_a" "cgA-1m")"$'\n' + SUMMARY_DATA+="$(get_result "$out_b" "cgB-$bs_b")"$'\n\n' + done + + echo -e "\nFinal Results Summary:\n" + + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n" \ + "" "" "" "slat" "clat" "clat" "clat" "clat" "clat" "clat" + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n\n" \ + "CGROUP" "IOPS" "MB/s" "avg(ms)" "avg(ms)" "max(ms)" "P90(ms)" "P99" "P99.9" "P99.99" + echo "$SUMMARY_DATA" + + echo "Results saved in $RESULT_DIR" + +Before: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 166 166.37 3.44 748.95 1298.29 977.27 1233.13 1300.23 1300.23 + cgB-4k 5 0.02 0.02 181.74 761.32 742.39 759.17 759.17 759.17 + + cgA-1m 167 166.51 1.98 748.68 1549.41 809.50 1451.23 1551.89 1551.89 + cgB-32k 6 0.18 0.02 169.98 761.76 742.39 759.17 759.17 759.17 + + cgA-1m 166 165.55 2.89 750.89 1540.37 851.44 1451.23 1535.12 1535.12 + cgB-256k 5 1.30 0.02 191.35 759.51 750.78 759.17 759.17 759.17 + +After: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 162 162.48 6.14 749.69 850.02 826.28 834.67 843.06 851.44 + cgB-4k 199 0.78 0.01 1.95 42.12 2.57 7.50 34.87 42.21 + + cgA-1m 146 146.20 6.83 833.04 908.68 893.39 901.78 910.16 910.16 + cgB-32k 200 6.25 0.01 2.32 31.40 3.06 7.50 16.58 31.33 + + cgA-1m 110 110.46 9.04 1082.67 1197.91 1182.79 1199.57 1199.57 1199.57 + cgB-256k 200 49.98 0.02 3.69 22.20 4.88 9.11 20.05 22.15 + +Signed-off-by: Jialin Wang +Acked-by: Tejun Heo +Link: https://patch.msgid.link/20260331100509.182882-1-wjl.linux@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index a5894ec9696e7..bc3b87be483d4 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1596,7 +1596,8 @@ static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer) + return HRTIMER_NORESTART; + } + +-static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p) ++static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p, ++ u32 *nr_done) + { + u32 nr_met[2] = { }; + u32 nr_missed[2] = { }; +@@ -1633,6 +1634,8 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p + + *rq_wait_pct_p = div64_u64(rq_wait_ns * 100, + ioc->period_us * NSEC_PER_USEC); ++ ++ *nr_done = nr_met[READ] + nr_met[WRITE] + nr_missed[READ] + nr_missed[WRITE]; + } + + /* was iocg idle this period? */ +@@ -2250,12 +2253,12 @@ static void ioc_timer_fn(struct timer_list *timer) + u64 usage_us_sum = 0; + u32 ppm_rthr; + u32 ppm_wthr; +- u32 missed_ppm[2], rq_wait_pct; ++ u32 missed_ppm[2], rq_wait_pct, nr_done; + u64 period_vtime; + int prev_busy_level; + + /* how were the latencies during the period? */ +- ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct); ++ ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct, &nr_done); + + /* take care of active iocgs */ + spin_lock_irq(&ioc->lock); +@@ -2399,9 +2402,17 @@ static void ioc_timer_fn(struct timer_list *timer) + * and should increase vtime rate. + */ + prev_busy_level = ioc->busy_level; +- if (rq_wait_pct > RQ_WAIT_BUSY_PCT || +- missed_ppm[READ] > ppm_rthr || +- missed_ppm[WRITE] > ppm_wthr) { ++ if (!nr_done && nr_lagging) { ++ /* ++ * When there are lagging IOs but no completions, we don't ++ * know if the IO latency will meet the QoS targets. The ++ * disk might be saturated or not. We should not reset ++ * busy_level to 0 (which would prevent vrate from scaling ++ * up or down), but rather to keep it unchanged. ++ */ ++ } else if (rq_wait_pct > RQ_WAIT_BUSY_PCT || ++ missed_ppm[READ] > ppm_rthr || ++ missed_ppm[WRITE] > ppm_wthr) { + /* clearly missing QoS targets, slow down vrate */ + ioc->busy_level = max(ioc->busy_level, 0); + ioc->busy_level++; +-- +2.53.0 + diff --git a/queue-6.12/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch b/queue-6.12/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch new file mode 100644 index 0000000000..79ce2fc66d --- /dev/null +++ b/queue-6.12/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch @@ -0,0 +1,72 @@ +From 705284a824eda8753e659d493a791d02a0254d7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 01:09:29 -0400 +Subject: block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user() + +From: Sungwoo Kim + +[ Upstream commit 8582792cf23b3d94674d4d838f7cde9a28d0fcaf ] + +pin_user_pages_fast() can partially succeed and return the number of +pages that were actually pinned. However, the bio_integrity_map_user() +does not handle this partial pinning. This leads to a general protection +fault since bvec_from_pages() dereferences an unpinned page address, +which is 0. + +To fix this, add a check to verify that all requested memory is pinned. +If partial pinning occurs, unpin the memory and return -EFAULT. + +Kernel Oops: + +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI +KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] +CPU: 0 UID: 0 PID: 1061 Comm: nvme-passthroug Not tainted 7.0.0-11783-g90957f9314e8-dirty #16 PREEMPT(lazy) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 +RIP: 0010:bio_integrity_map_user.cold+0x1b0/0x9d6 + +Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") +Acked-by: Chao Shi +Acked-by: Weidong Zhu +Acked-by: Dave Tian +Signed-off-by: Sungwoo Kim +Tested-by: Shin'ichiro Kawasaki +Link: https://github.com/linux-blktests/blktests/pull/244 +Link: https://patch.msgid.link/20260512050929.541397-2-iam@sung-woo.kim +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 2a02222f4298c..04bab987b0878 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -338,6 +338,24 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + if (unlikely(ret < 0)) + goto free_bvec; + ++ /* ++ * Handle partial pinning. This can happen when pin_user_pages_fast() ++ * returns fewer pages than requested. ++ */ ++ if (user_backed_iter(iter) && unlikely(ret != bytes)) { ++ if (ret > 0) { ++ int npinned = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ int i; ++ ++ for (i = 0; i < npinned; i++) ++ unpin_user_page(pages[i]); ++ } ++ if (pages != stack_pages) ++ kvfree(pages); ++ ret = -EFAULT; ++ goto free_bvec; ++ } ++ + nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, + &is_p2p); + if (pages != stack_pages) +-- +2.53.0 + diff --git a/queue-6.12/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch b/queue-6.12/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch new file mode 100644 index 0000000000..fac49b5262 --- /dev/null +++ b/queue-6.12/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch @@ -0,0 +1,43 @@ +From 6533eba3bd7897a7bdd3a1e06f58ad9d4f0a4543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 22:51:51 +0100 +Subject: block: don't overwrite bip_vcnt in bio_integrity_copy_user() + +From: David Carlier + +[ Upstream commit 637ad3a56a3b889527d1dacea6fea2a8bd648140 ] + +bio_integrity_add_page() already sets bip_vcnt to 1 for the bounce +segment. Overwriting it with nr_vecs breaks bip_vcnt <= bip_max_vcnt +on WRITE (bip_max_vcnt is 1), so the gap-merge checks in block/blk.h +read past the bip_vec[] flex array. On READ the read is in bounds +but lands on a saved user bvec instead of the bounce. + +The line was added for split propagation, but bio_integrity_clone() +doesn't copy bip_vcnt and BIP_CLONE_FLAGS excludes BIP_COPY_USER. + +Fixes: 3991657ae707 ("block: set bip_vcnt correctly") +Signed-off-by: David Carlier +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511215151.346228-1-devnexen@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index ab58f44058e96..9c490fa07a795 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -245,7 +245,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + } + + bip->bip_flags |= BIP_COPY_USER; +- bip->bip_vcnt = nr_vecs; + return 0; + free_bip: + bio_integrity_free(bio); +-- +2.53.0 + diff --git a/queue-6.12/block-drop-direction-param-from-bio_integrity_copy_u.patch b/queue-6.12/block-drop-direction-param-from-bio_integrity_copy_u.patch new file mode 100644 index 0000000000..126461370f --- /dev/null +++ b/queue-6.12/block-drop-direction-param-from-bio_integrity_copy_u.patch @@ -0,0 +1,84 @@ +From 190ecf35dae050463e99e5fb67299793c83646df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Jun 2025 12:31:32 -0600 +Subject: block: drop direction param from bio_integrity_copy_user() + +From: Caleb Sander Mateos + +[ Upstream commit c09a8b00f850d3ca0af998bff1fac4a3f6d11768 ] + +direction is determined from bio, which is already passed in. Compute +op_is_write(bio_op(bio)) directly instead of converting it to an iter +direction and back to a bool. + +Signed-off-by: Caleb Sander Mateos +Reviewed-by: Keith Busch +Reviewed-by: Anuj Gupta +Link: https://lore.kernel.org/r/20250603183133.1178062-1-csander@purestorage.com +Signed-off-by: Jens Axboe +Stable-dep-of: 8582792cf23b ("block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()") +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 17 +++++------------ + 1 file changed, 5 insertions(+), 12 deletions(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 785adefc5f3c3..6801754838bc1 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -196,10 +196,9 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, + EXPORT_SYMBOL(bio_integrity_add_page); + + static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, +- int nr_vecs, unsigned int len, +- unsigned int direction) ++ int nr_vecs, unsigned int len) + { +- bool write = direction == ITER_SOURCE; ++ bool write = op_is_write(bio_op(bio)); + struct bio_integrity_payload *bip; + struct iov_iter iter; + void *buf; +@@ -210,7 +209,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + return -ENOMEM; + + if (write) { +- iov_iter_bvec(&iter, direction, bvec, nr_vecs, len); ++ iov_iter_bvec(&iter, ITER_SOURCE, bvec, nr_vecs, len); + if (!copy_from_iter_full(buf, len, &iter)) { + ret = -EFAULT; + goto free_buf; +@@ -305,7 +304,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; + size_t offset, bytes = iter->count; +- unsigned int direction, nr_bvecs; ++ unsigned int nr_bvecs; + int ret, nr_vecs; + bool copy; + +@@ -314,11 +313,6 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + if (bytes >> SECTOR_SHIFT > queue_max_hw_sectors(q)) + return -E2BIG; + +- if (bio_data_dir(bio) == READ) +- direction = ITER_DEST; +- else +- direction = ITER_SOURCE; +- + nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS + 1); + if (nr_vecs > BIO_MAX_VECS) + return -E2BIG; +@@ -341,8 +335,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + copy = true; + + if (copy) +- ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, +- direction); ++ ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes); + else + ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/block-modify-bio_integrity_map_user-to-accept-iov_it.patch b/queue-6.12/block-modify-bio_integrity_map_user-to-accept-iov_it.patch new file mode 100644 index 0000000000..172a9adb2e --- /dev/null +++ b/queue-6.12/block-modify-bio_integrity_map_user-to-accept-iov_it.patch @@ -0,0 +1,118 @@ +From 28f483d8c097c7f7d9b4d24024901b0a18db4014 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Nov 2024 16:52:33 +0530 +Subject: block: modify bio_integrity_map_user to accept iov_iter as argument + +From: Anuj Gupta + +[ Upstream commit fe8f4ca7107e968b0eb7328155c8811f2a19424a ] + +This patch refactors bio_integrity_map_user to accept iov_iter as +argument. This is a prep patch. + +Signed-off-by: Anuj Gupta +Signed-off-by: Kanchan Joshi +Reviewed-by: Christoph Hellwig +Reviewed-by: Keith Busch +Link: https://lore.kernel.org/r/20241128112240.8867-4-anuj20.g@samsung.com +Signed-off-by: Jens Axboe +Stable-dep-of: 8582792cf23b ("block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()") +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 12 +++++------- + block/blk-integrity.c | 10 +++++++++- + include/linux/bio-integrity.h | 5 ++--- + 3 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 9c490fa07a795..785adefc5f3c3 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -298,16 +298,15 @@ static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + return nr_bvecs; + } + +-int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes) ++int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + { + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + unsigned int align = blk_lim_dma_alignment_and_pad(&q->limits); + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; ++ size_t offset, bytes = iter->count; + unsigned int direction, nr_bvecs; +- struct iov_iter iter; + int ret, nr_vecs; +- size_t offset; + bool copy; + + if (bio_integrity(bio)) +@@ -320,8 +319,7 @@ int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes) + else + direction = ITER_SOURCE; + +- iov_iter_ubuf(&iter, direction, ubuf, bytes); +- nr_vecs = iov_iter_npages(&iter, BIO_MAX_VECS + 1); ++ nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS + 1); + if (nr_vecs > BIO_MAX_VECS) + return -E2BIG; + if (nr_vecs > UIO_FASTIOV) { +@@ -331,8 +329,8 @@ int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes) + pages = NULL; + } + +- copy = !iov_iter_is_aligned(&iter, align, align); +- ret = iov_iter_extract_pages(&iter, &pages, bytes, nr_vecs, 0, &offset); ++ copy = !iov_iter_is_aligned(iter, align, align); ++ ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs, 0, &offset); + if (unlikely(ret < 0)) + goto free_bvec; + +diff --git a/block/blk-integrity.c b/block/blk-integrity.c +index 013469faa5e7c..a1678f0a9f81f 100644 +--- a/block/blk-integrity.c ++++ b/block/blk-integrity.c +@@ -115,8 +115,16 @@ EXPORT_SYMBOL(blk_rq_map_integrity_sg); + int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf, + ssize_t bytes) + { +- int ret = bio_integrity_map_user(rq->bio, ubuf, bytes); ++ int ret; ++ struct iov_iter iter; ++ unsigned int direction; + ++ if (op_is_write(req_op(rq))) ++ direction = ITER_DEST; ++ else ++ direction = ITER_SOURCE; ++ iov_iter_ubuf(&iter, direction, ubuf, bytes); ++ ret = bio_integrity_map_user(rq->bio, &iter); + if (ret) + return ret; + +diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h +index dbf0f74c15291..be91479b2c42d 100644 +--- a/include/linux/bio-integrity.h ++++ b/include/linux/bio-integrity.h +@@ -72,7 +72,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp, + unsigned int nr); + int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len, + unsigned int offset); +-int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len); ++int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter); + void bio_integrity_unmap_user(struct bio *bio); + bool bio_integrity_prep(struct bio *bio); + void bio_integrity_advance(struct bio *bio, unsigned int bytes_done); +@@ -98,8 +98,7 @@ static inline void bioset_integrity_free(struct bio_set *bs) + { + } + +-static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf, +- ssize_t len) ++static int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + { + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.12/block-recompute-nr_integrity_segments-in-blk_insert_.patch b/queue-6.12/block-recompute-nr_integrity_segments-in-blk_insert_.patch new file mode 100644 index 0000000000..a2a85941b2 --- /dev/null +++ b/queue-6.12/block-recompute-nr_integrity_segments-in-blk_insert_.patch @@ -0,0 +1,82 @@ +From 5a1b19eaf1372f3abc737b2db1575f25a19075ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 15:22:30 -0600 +Subject: block: recompute nr_integrity_segments in blk_insert_cloned_request + +From: Casey Chen + +[ Upstream commit 2c6e6a18a37b905cb584eb0dda3ae482162a81ca ] + +blk_insert_cloned_request() already recomputes nr_phys_segments +against the bottom queue, because "the queue settings related to +segment counting may differ from the original queue." The exact same +reasoning applies to integrity segments: a stacked driver's underlying +queue can have tighter virt_boundary_mask, seg_boundary_mask, or +max_segment_size than the top queue, in which case +blk_rq_count_integrity_sg() against the bottom queue produces a +different count than the cached rq->nr_integrity_segments inherited +from the source request by blk_rq_prep_clone(). + +When the cached count is lower than the bottom queue's actual count, +blk_rq_map_integrity_sg() trips + + BUG_ON(segments > rq->nr_integrity_segments); + +on dispatch. The same families of stacked setups that motivated the +existing nr_phys_segments recompute -- dm-multipath fanning out to +nvme-rdma in particular -- can produce this. + +Mirror the nr_phys_segments handling: when the request carries +integrity, recompute nr_integrity_segments against the bottom queue +and reject the request if it exceeds the bottom queue's +max_integrity_segments. blk_rq_count_integrity_sg() and +queue_max_integrity_segments() are both already available via +, which blk-mq.c includes. + +This closes a latent gap in the stacking contract and brings the +integrity-segment accounting in line with the existing +phys-segment accounting. + +Fixes: 76c313f658d2 ("blk-integrity: improved sg segment mapping") +Signed-off-by: Casey Chen +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511212230.27511-1-cachen@purestorage.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-mq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 1891863dcba17..5bfaa8e4b9cf6 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3215,6 +3215,25 @@ blk_status_t blk_insert_cloned_request(struct request *rq) + return BLK_STS_IOERR; + } + ++ /* ++ * Integrity segment counting depends on the same queue limits ++ * (virt_boundary_mask, seg_boundary_mask, max_segment_size) that ++ * vary across stacked queues, so recompute against the bottom ++ * queue just like nr_phys_segments above. ++ */ ++ if (blk_integrity_rq(rq) && rq->bio) { ++ unsigned short max_int_segs = queue_max_integrity_segments(q); ++ ++ rq->nr_integrity_segments = ++ blk_rq_count_integrity_sg(rq->q, rq->bio); ++ if (rq->nr_integrity_segments > max_int_segs) { ++ printk(KERN_ERR "%s: over max integrity segments limit. (%u > %u)\n", ++ __func__, rq->nr_integrity_segments, ++ max_int_segs); ++ return BLK_STS_IOERR; ++ } ++ } ++ + if (q->disk && should_fail_request(q->disk->part0, blk_rq_bytes(rq))) + return BLK_STS_IOERR; + +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-6.12/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..3999f20854 --- /dev/null +++ b/queue-6.12/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From 239ca72395c253125a84aea6ba8d7612e46a7efd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 0a60660fc8ce8..e52beec4a955b 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -507,6 +507,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btmtk-add-mt7902-mcu-support.patch b/queue-6.12/bluetooth-btmtk-add-mt7902-mcu-support.patch new file mode 100644 index 0000000000..7b9fda995a --- /dev/null +++ b/queue-6.12/bluetooth-btmtk-add-mt7902-mcu-support.patch @@ -0,0 +1,47 @@ +From 60c04cdd816e3b056b7747919259fc629988b0ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:19 -0600 +Subject: Bluetooth: btmtk: add MT7902 MCU support + +From: Sean Wang + +[ Upstream commit aab25984e55972e53f3e58821cb85a7101876056 ] + +Add MT7902 device ID and firmware filename to enable MCU firmware +loading. + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 1 + + drivers/bluetooth/btmtk.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index c75189b4a2d76..f71e8f54b2f11 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -1343,6 +1343,7 @@ int btmtk_usb_setup(struct hci_dev *hdev) + case 0x7922: + case 0x7925: + case 0x7961: ++ case 0x7902: + btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id, + fw_version, fw_flavor); + +diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h +index 5df7c32966247..b4506186b2f70 100644 +--- a/drivers/bluetooth/btmtk.h ++++ b/drivers/bluetooth/btmtk.h +@@ -5,6 +5,7 @@ + #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" + #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" + #define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin" ++#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin" + #define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" + #define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" + +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch b/queue-6.12/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch new file mode 100644 index 0000000000..1c9cdb823f --- /dev/null +++ b/queue-6.12/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch @@ -0,0 +1,40 @@ +From 806d737d484c472aca89484448977615c53b4925 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:25:08 +0800 +Subject: Bluetooth: btmtk: improve mt79xx firmware setup retry flow + +From: Chris Lu + +[ Upstream commit 54f1f020e9f4a087779cc4d96a7c86f47d0c6797 ] + +If retries are exhausted, driver should not do futher operation. +During mt79xx firmware download process, if the retry count reaches0, +driver will return an -EIO error and release the firmware resources. + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index 98cb8529d8bcd..c75189b4a2d76 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -205,6 +205,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, + } + } + ++ /* If retry exhausted goto err_release_fw */ ++ if (retry == 0) { ++ err = -EIO; ++ goto err_release_fw; ++ } ++ + fw_ptr += section_offset; + wmt_params.op = BTMTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch b/queue-6.12/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch new file mode 100644 index 0000000000..b65116a962 --- /dev/null +++ b/queue-6.12/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch @@ -0,0 +1,56 @@ +From 5bf424595f0a9d846af8c8d248b0e85d662732ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 20:32:09 +0100 +Subject: Bluetooth: btusb: Add Lite-On 04ca:3807 for MediaTek MT7921 + +From: Dylan Eray + +[ Upstream commit 67377cd38b89ce782ccdb83bda3f65a2def843cd ] + +Add USB device ID (04ca:3807) for a Lite-On Wireless_Device containing +a MediaTek MT7921 (MT7920) Bluetooth chipset found in Acer laptops. + +Without this entry, btusb binds via the generic USB class-based wildcard +match but never sets the BTUSB_MEDIATEK flag. This means btmtk never +triggers firmware loading, and the driver sends a raw HCI Reset that +the uninitialized chip cannot respond to, resulting in: + + Bluetooth: hci0: Opcode 0x0c03 failed: -110 + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below: + +T: Bus=03 Lev=01 Prnt=01 Port=09 Cnt=01 Dev#=5 Spd=480 MxCh=0 +P: Vendor=04ca ProdID=3807 Rev=1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C: #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) + +Reviewed-by: Paul Menzel +Signed-off-by: Dylan Eray +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 5968dfcfd4a15..5cd3c88e24916 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -691,6 +691,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x04ca, 0x3807), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch b/queue-6.12/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch new file mode 100644 index 0000000000..e9849e888a --- /dev/null +++ b/queue-6.12/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch @@ -0,0 +1,79 @@ +From 4a9128e7644750397521ab2216f4dc1b8b9a3596 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:20 -0600 +Subject: Bluetooth: btusb: Add new VID/PID 13d3/3579 for MT7902 + +From: Sean Wang + +[ Upstream commit 51c4173b89fe7399bad1381016096cc154588660 ] + +Add VID 13d3 & PID 3579 for MediaTek MT7902 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=04 Dev#= 7 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=13d3 ProdID=3579 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 5cd3c88e24916..2bf76028922ae 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -655,7 +655,9 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +- ++ /* MediaTek MT7902 Bluetooth devices */ ++ { USB_DEVICE(0x13d3, 0x3579), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + /* MediaTek MT7922 Bluetooth devices */ + { USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch b/queue-6.12/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch new file mode 100644 index 0000000000..abfc756e29 --- /dev/null +++ b/queue-6.12/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch @@ -0,0 +1,46 @@ +From 16590a6488be93953b37bcfe4f5c23bef77bec08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:53:01 +0900 +Subject: Bluetooth: btusb: MediaTek MT7922: Add VID 0489 & PID e11d + +From: Kamiyama Chiaki + +[ Upstream commit 5e17010bfc7e6820a5004f1e06d08db886e3927e ] + +Add VID 0489 & PID e11d for MediaTek MT7922 USB Bluetooth chip. +Found in Dynabook GA/ZY (W6GAZY5RCL). + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e11d Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 + +Reviewed-by: Paul Menzel +Signed-off-by: Kamiyama Chiaki +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 2bf76028922ae..07bfa736284c1 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -683,6 +683,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe11d), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe152), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch b/queue-6.12/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch new file mode 100644 index 0000000000..31f32bb2df --- /dev/null +++ b/queue-6.12/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch @@ -0,0 +1,77 @@ +From 8ccc9e8341ffa3b83565ccae2356efadac0d3667 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:13:56 +0800 +Subject: Bluetooth: btusb: MT7922: Add VID/PID 0489/e174 + +From: Chris Lu + +[ Upstream commit 1f2ac009d3e06380400618e777c858e582872efa ] + +Add VID 0489 & PID e174 for MediaTek MT7922 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e174 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index b8bf4dfea11c2..5968dfcfd4a15 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -687,6 +687,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe174), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch b/queue-6.12/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch new file mode 100644 index 0000000000..d6999e544f --- /dev/null +++ b/queue-6.12/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch @@ -0,0 +1,43 @@ +From 10525b4fbe8f5137b2cc98b16cde64f96dfe98e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:16 +0800 +Subject: Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is + not defined + +From: Shuai Zhang + +[ Upstream commit 7b75867803a8712bdf7683c31d71d3d5e28ce821 ] + +On platforms using an M.2 slot with both UART and USB support, bt_en is +pulled high by hardware. In this case, software-based power control +should be disabled. The current platforms are Lemans-EVK and Monaco-EVK. + +Add QCA_WCN7850 to the existing condition so that power_ctrl_enabled is +cleared when bt_en is not software-controlled (or absent), aligning its +behavior with WCN6750 and WCN6855 + +Signed-off-by: Shuai Zhang +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 586a2ff72a2ae..34dca9fc97a2d 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2403,7 +2403,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + if (!qcadev->bt_en && + (data->soc_type == QCA_WCN6750 || +- data->soc_type == QCA_WCN6855)) ++ data->soc_type == QCA_WCN6855 || ++ data->soc_type == QCA_WCN7850)) + power_ctrl_enabled = false; + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch b/queue-6.12/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch new file mode 100644 index 0000000000..05d4d105ad --- /dev/null +++ b/queue-6.12/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch @@ -0,0 +1,72 @@ +From 635e40341e55fc1a798b332295aea07bd36a5678 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:54:43 +0800 +Subject: Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling + +From: Shuai Zhang + +[ Upstream commit c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f ] + +When a Bluetooth controller encounters a coredump, it triggers the +Subsystem Restart (SSR) mechanism. The controller first reports the +coredump data and, once the upload is complete, sends a hw_error +event. The host relies on this event to proceed with subsequent +recovery actions. + +If the host has not finished processing the coredump data when the +hw_error event is received, it waits until either the processing is +complete or the 8-second timeout expires before handling the event. + +The current implementation clears QCA_MEMDUMP_COLLECTION using +clear_bit(), which does not wake up waiters sleeping in +wait_on_bit_timeout(). As a result, the waiting thread may remain +blocked until the timeout expires even if the coredump collection +has already completed. + +Fix this by clearing QCA_MEMDUMP_COLLECTION with +clear_and_wake_up_bit(), which also wakes up the waiting thread and +allows the hw_error handling to proceed immediately. + +Test case: +- Trigger a controller coredump using: + hcitool cmd 0x3f 0c 26 +- Tested on QCA6390. +- Capture HCI logs using btmon. +- Verify that the delay between receiving the hw_error event and + initiating the power-off sequence is reduced compared to the + timeout-based behavior. + +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Paul Menzel +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 34dca9fc97a2d..acd76af700c5d 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -1090,7 +1090,7 @@ static void qca_controller_memdump(struct work_struct *work) + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; +@@ -1168,7 +1168,7 @@ static void qca_controller_memdump(struct work_struct *work) + kfree(qca->qca_memdump); + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } + + mutex_unlock(&qca->hci_memdump_lock); +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-6.12/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..f45ca09d96 --- /dev/null +++ b/queue-6.12/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From ef0e73753215a7f72c66f3dd01adbbd3811fb914 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index b01107370cbcb..8e02ca3c3c912 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6635,6 +6635,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); +-- +2.53.0 + diff --git a/queue-6.12/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-6.12/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..1fa5532090 --- /dev/null +++ b/queue-6.12/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From be6bde84d77ffb3a3ee87de7c7ff10d0a615c814 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 517710c89fa50..712ad95440ccc 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -2067,12 +2067,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-6.12/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch b/queue-6.12/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch new file mode 100644 index 0000000000..ce8cf0dc84 --- /dev/null +++ b/queue-6.12/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch @@ -0,0 +1,52 @@ +From 2510f44afc32c77f1704525837f7ca15ddfb4386 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:15 +0200 +Subject: bpf, sockmap: Annotate af_unix sock:: Sk_state data-races + +From: Michal Luczaj + +[ Upstream commit a25566084e391348385a72dd507e0cc0c268dd5d ] + +sock_map_sk_state_allowed() and sock_map_redirect_allowed() read af_unix +socket sk_state locklessly. + +Use READ_ONCE(). Note that for sock_map_redirect_allowed() change affects +not only af_unix, but all non-TCP sockets (UDP, af_vsock). + +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-1-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/core/sock_map.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock_map.c b/net/core/sock_map.c +index 82a14f131d00c..95aeea15b45a9 100644 +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -530,7 +530,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return sk->sk_state != TCP_LISTEN; + else +- return sk->sk_state == TCP_ESTABLISHED; ++ return READ_ONCE(sk->sk_state) == TCP_ESTABLISHED; + } + + static bool sock_map_sk_is_suitable(const struct sock *sk) +@@ -543,7 +543,7 @@ static bool sock_map_sk_state_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); + if (sk_is_stream_unix(sk)) +- return (1 << sk->sk_state) & TCPF_ESTABLISHED; ++ return (1 << READ_ONCE(sk->sk_state)) & TCPF_ESTABLISHED; + if (sk_is_vsock(sk) && + (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) + return (1 << sk->sk_state) & TCPF_ESTABLISHED; +-- +2.53.0 + diff --git a/queue-6.12/btrfs-apply-first-key-check-for-readahead-when-possi.patch b/queue-6.12/btrfs-apply-first-key-check-for-readahead-when-possi.patch new file mode 100644 index 0000000000..fbb61f16cb --- /dev/null +++ b/queue-6.12/btrfs-apply-first-key-check-for-readahead-when-possi.patch @@ -0,0 +1,129 @@ +From 4841c34cb1720a6c326f22b35de78cdda39d1909 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 20:31:05 +0930 +Subject: btrfs: apply first key check for readahead when possible + +From: Qu Wenruo + +[ Upstream commit a86a283430e1a44907b142c4f53e1f3ad24e87ae ] + +Currently for tree block readahead we never pass a +btrfs_tree_parent_check with @has_first_key set. + +Without @has_first_key set, btrfs will skip the following extra +checks: + +- Header generation check + This is a minor one. + +- Empty leaf/node checks + This is more serious, for certain trees like the csum tree, they are + allowed to be empty, thus an empty leaf can pass the tree checker. + But if there is a parent node for such an empty leaf, it indicates + corruption. + + Without @has_first_key set, we can no longer detect such a problem. + + In fact there is already a fuzzed image report that a corrupted csum + leaf which has zero nritems but still has a parent node can trigger + a BUG_ON() during csum deletion. + +However there are only two call sites of btrfs_readahead_tree_block(): + +- Inside relocate_tree_blocks() + At this call site we are trying to grab the first key of the tree + block, thus we are not able to pass a @first_key parameter. + +- Inside btrfs_readahead_node_child() + This is the more common call site, where we have the parent node and + want to readahead the child tree blocks. + + In this case we can easily grab the node key and pass it for checks. + +Add a new parameter @first_key to btrfs_readahead_tree_block() and pass +the node key to it inside btrfs_readahead_node_child(). + +This should plug the gap in empty leaf detection during readahead. + +Link: https://lore.kernel.org/linux-btrfs/20260409071255.3358044-1-gality369@gmail.com/ +Reviewed-by: David Sterba +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 14 ++++++++++++-- + fs/btrfs/extent_io.h | 3 ++- + fs/btrfs/relocation.c | 2 +- + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 0d50f3063d346..92630dd04e867 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -4422,7 +4422,8 @@ int try_release_extent_buffer(struct folio *folio) + * to read the block we will not block on anything. + */ + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level) ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key) + { + struct btrfs_tree_parent_check check = { + .has_first_key = 0, +@@ -4432,6 +4433,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb; + int ret; + ++ if (first_key) { ++ memcpy(&check.first_key, first_key, sizeof(struct btrfs_key)); ++ check.has_first_key = true; ++ } ++ + eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); + if (IS_ERR(eb)) + return; +@@ -4459,9 +4465,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + */ + void btrfs_readahead_node_child(struct extent_buffer *node, int slot) + { ++ struct btrfs_key node_key; ++ ++ btrfs_node_key_to_cpu(node, &node_key, slot); + btrfs_readahead_tree_block(node->fs_info, + btrfs_node_blockptr(node, slot), + btrfs_header_owner(node), + btrfs_node_ptr_generation(node, slot), +- btrfs_header_level(node) - 1); ++ btrfs_header_level(node) - 1, ++ &node_key); + } +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 0eedfd7c4b6ec..fe0c81322f878 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -270,7 +270,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb) + } + + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level); ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key); + void btrfs_readahead_node_child(struct extent_buffer *node, int slot); + + static inline int num_extent_pages(const struct extent_buffer *eb) +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 43e8c331168e9..c6eea37f4a196 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2707,7 +2707,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, + if (!block->key_ready) + btrfs_readahead_tree_block(fs_info, block->bytenr, + block->owner, 0, +- block->level); ++ block->level, NULL); + } + + /* Get first keys */ +-- +2.53.0 + diff --git a/queue-6.12/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-6.12/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..82b82f6b70 --- /dev/null +++ b/queue-6.12/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From c0beb2ffd6bd4a707155107495880cea27297286 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index 2b71ed343b63d..99ea7d93b3f98 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -460,10 +460,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + +-- +2.53.0 + diff --git a/queue-6.12/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-6.12/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..4f9c4546bf --- /dev/null +++ b/queue-6.12/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From 3a379707cae28140bb4213ba11213932419a8d9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index a578bd3b32bb0..612e8b08af3fd 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -528,6 +528,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + blocksize, BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-6.12/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch b/queue-6.12/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch new file mode 100644 index 0000000000..d5ee42464b --- /dev/null +++ b/queue-6.12/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch @@ -0,0 +1,61 @@ +From 57e7561b1182a15cd82bb9b4454358db19c722dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 09:06:44 -0700 +Subject: btrfs: fix silent IO error loss in encoded writes and zoned split + +From: Michal Grzedzicki + +[ Upstream commit 3cd181cc46d36aa7bd4af85f14639d86a25beaec ] + +can_finish_ordered_extent() and btrfs_finish_ordered_zoned() set +BTRFS_ORDERED_IOERR via bare set_bit(). Later, +btrfs_mark_ordered_extent_error() in btrfs_finish_one_ordered() uses +test_and_set_bit(), finds it already set, and skips +mapping_set_error(). The error is never recorded on the inode's +address_space, making it invisible to fsync. For encoded writes this +causes btrfs receive to silently produce files with zero-filled holes. + +Fix: replace bare set_bit(BTRFS_ORDERED_IOERR) with +btrfs_mark_ordered_extent_error() which pairs test_and_set_bit() with +mapping_set_error(), guaranteeing the error is recorded exactly once. + +Reviewed-by: Qu Wenruo +Reviewed-by: Johannes Thumshirn +Reviewed-by: Mark Harmstone +Signed-off-by: Michal Grzedzicki +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ordered-data.c | 2 +- + fs/btrfs/zoned.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c +index 6ac254a529073..7bc81f88c185e 100644 +--- a/fs/btrfs/ordered-data.c ++++ b/fs/btrfs/ordered-data.c +@@ -375,7 +375,7 @@ static bool can_finish_ordered_extent(struct btrfs_ordered_extent *ordered, + } + + if (!uptodate) +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + + if (ordered->bytes_left) + return false; +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index d9c26f4be6634..4ba7ec6c23d7e 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -2082,7 +2082,7 @@ void btrfs_finish_ordered_zoned(struct btrfs_ordered_extent *ordered) + continue; + } + if (!btrfs_zoned_split_ordered(ordered, logical, len)) { +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + btrfs_err(fs_info, "failed to split ordered extent"); + goto out; + } +-- +2.53.0 + diff --git a/queue-6.12/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-6.12/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..9b480075ba --- /dev/null +++ b/queue-6.12/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From fcd68c31e00b4306332358330ca9e7d24c5860fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 8e31af036e75e..93239ca22aa90 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -267,7 +267,11 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -410,7 +414,11 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1479,7 +1487,11 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-6.12/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-6.12/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..da05d831b6 --- /dev/null +++ b/queue-6.12/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 6d8bec4b0a24f12abc6026683228516ac06c54fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 3ca24a0845cbe..32859aa00d988 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3250,7 +3250,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-6.12/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch b/queue-6.12/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch new file mode 100644 index 0000000000..a4251a0e4f --- /dev/null +++ b/queue-6.12/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch @@ -0,0 +1,75 @@ +From 22a6fa0b75f89b2b86a113abfecccb1b4daea6c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:58:56 +0100 +Subject: btrfs: tracepoints: fix sleep while in atomic context in + btrfs_sync_file() + +From: Filipe Manana + +[ Upstream commit c73370c677646e86fc4b1780fb07027bdf847375 ] + +The trace event btrfs_sync_file() is called in an atomic context (all trace +events are) and its call to dput(), which is needed due to the call to +dget_parent(), can sleep, triggering a kernel splat. + +This can be reproduced by enabling the trace event and running btrfs/056 +from fstests for example. The splat shown in dmesg is the following: + + [53.919] BUG: sleeping function called from invalid context at fs/dcache.c:970 + [53.947] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 32773, name: xfs_io + [53.988] preempt_count: 2, expected: 0 + [53.967] RCU nest depth: 0, expected: 0 + [53.943] Preemption disabled at: + [53.944] [<0000000000000000>] 0x0 + [54.078] CPU: 0 UID: 0 PID: 32773 Comm: xfs_io Tainted: G W 7.1.0-rc1-btrfs-next-232+ #1 PREEMPT(full) + [54.070] Tainted: [W]=WARN + [54.071] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [54.072] Call Trace: + [54.074] + [54.076] dump_stack_lvl+0x56/0x80 + [54.079] __might_resched.cold+0xd6/0x10f + [54.072] dput.part.0+0x24/0x110 + [54.078] trace_event_raw_event_btrfs_sync_file+0x75/0x140 [btrfs] + [54.089] btrfs_sync_file+0x1ed/0x530 [btrfs] + [54.087] ? __handle_mm_fault+0x8ae/0xed0 + [54.089] btrfs_do_write_iter+0x172/0x210 [btrfs] + [54.091] vfs_write+0x21f/0x450 + [54.094] __x64_sys_pwrite64+0x8d/0xc0 + [54.096] ? do_user_addr_fault+0x20c/0x670 + [54.099] do_syscall_64+0x60/0xf20 + [54.092] ? clear_bhb_loop+0x60/0xb0 + [54.094] entry_SYSCALL_64_after_hwframe+0x76/0x7e + +So stop using dget_parent() and dput() and access the parent dentry +directly as dentry->d_parent. This is also what ext4 is doing in +its equivalent trace event ext4_sync_file_enter(). + +Fixes: a85b46db143f ("btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file()") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + include/trace/events/btrfs.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index b964cba4169c2..6382a570c76c5 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -773,10 +773,8 @@ TRACE_EVENT(btrfs_sync_file, + TP_fast_assign( + struct dentry *dentry = file_dentry(file); + struct inode *inode = file_inode(file); +- struct dentry *parent = dget_parent(dentry); +- struct inode *parent_inode = d_inode(parent); ++ struct inode *parent_inode = d_inode(dentry->d_parent); + +- dput(parent); + TP_fast_assign_fsid(btrfs_sb(inode->i_sb)); + __entry->ino = btrfs_ino(BTRFS_I(inode)); + __entry->parent = btrfs_ino(BTRFS_I(parent_inode)); +-- +2.53.0 + diff --git a/queue-6.12/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-6.12/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..3ab4882a5d --- /dev/null +++ b/queue-6.12/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From ecf61191331589ab8f1996bdb86a00d191640332 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 2dab2ce94cc40..ab46e405ced5d 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3534,7 +3534,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.12/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch b/queue-6.12/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch new file mode 100644 index 0000000000..b226a4de18 --- /dev/null +++ b/queue-6.12/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch @@ -0,0 +1,57 @@ +From f1ab2bfcf536e909e2d27c857881366daf0cbd83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:16:17 +0530 +Subject: bus: mhi: host: pci_generic: Add Qualcomm SDX35 modem + +From: Krishna Chaitanya Chundru + +[ Upstream commit 6a7084102bb9659f699005c420eb59eade6d3b4f ] + +Add support for sdx35 modem. Similar to SDX75, SDX35 can take longer to +transition to ready during power up, so use modem_qcom_v2_mhiv_config +configurations. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Qualcomm Device 011a + +Signed-off-by: Krishna Chaitanya Chundru +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260123-mhi_sdx35-v1-1-79440abf0c92@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index 833d0c940477d..ee1eeb8340962 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -328,6 +328,16 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { + .sideband_wake = false, + }; + ++static const struct mhi_pci_dev_info mhi_qcom_sdx35_info = { ++ .name = "qcom-sdx35m", ++ .config = &modem_qcom_v2_mhiv_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .mru_default = 32768, ++ .sideband_wake = false, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { + .name = "qcom-sdx24", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -779,6 +789,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), ++ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), +-- +2.53.0 + diff --git a/queue-6.12/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch b/queue-6.12/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch new file mode 100644 index 0000000000..2fad2c2515 --- /dev/null +++ b/queue-6.12/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch @@ -0,0 +1,56 @@ +From e81d41953cd893e1c31141fe05e906bb532b44ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:28:37 +0100 +Subject: bus: mhi: host: pci_generic: Add Telit FE912C04 modem support + +From: Daniele Palmas + +[ Upstream commit ac12b852b4ead4a586299c8f68cdcbcaf1bf6cbc ] + +Add SDX35 based modem Telit FE912C04, reusing FN920C04 configuration. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Device 1c5d:2045 + +Signed-off-by: Daniele Palmas +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260323122837.3406521-1-dnlplm@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index ee1eeb8340962..ca7e8602661bc 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -764,6 +764,16 @@ static const struct mhi_pci_dev_info mhi_telit_fe990b40_info = { + .edl_trigger = true, + }; + ++static const struct mhi_pci_dev_info mhi_telit_fe912c04_info = { ++ .name = "telit-fe912c04", ++ .config = &modem_telit_fn920c04_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++ .mru_default = 32768, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = { + .name = "netprisma-lcur57", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -789,6 +799,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ /* Telit FE912C04 (sdx35) */ ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2045), ++ .driver_data = (kernel_ulong_t) &mhi_telit_fe912c04_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-6.12/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..0a2ce6643e --- /dev/null +++ b/queue-6.12/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From 1fbaeeff8e872043038c92e6b0caa73385f3165f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 6aa9dcdabffde..148434547b07c 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -937,6 +937,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-6.12/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-6.12/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..928b04e21b --- /dev/null +++ b/queue-6.12/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From c5755ae3ea04f122b251173a3fb81a614c155e22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index 348eeab0a906b..c495f529f07e1 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -338,13 +338,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-6.12/coda_flag_children-fix-a-uaf.patch b/queue-6.12/coda_flag_children-fix-a-uaf.patch new file mode 100644 index 0000000000..fbc62e78dc --- /dev/null +++ b/queue-6.12/coda_flag_children-fix-a-uaf.patch @@ -0,0 +1,44 @@ +From dbf9d2ee46b4269b13af3d737a9f25f2bdfb4882 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:33:37 -0500 +Subject: coda_flag_children(): fix a UAF + +From: Al Viro + +[ Upstream commit e252ed8988578f01da5a4f5aa4c2269f96f03951 ] + +if de goes negative right under us, there's nothing to prevent inode +getting freed just as we call coda_flag_inode(). We are not holding +->d_lock, so it's not impossible. Not going to be reproducible on +bare hardware unless it's a realtime config, but it could happen on KVM. + +Trivial to fix - just hold rcu_read_lock() over that loop. + +Signed-off-by: Al Viro +Signed-off-by: Sasha Levin +--- + fs/coda/cache.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/coda/cache.c b/fs/coda/cache.c +index 970f0022ec528..2451312963004 100644 +--- a/fs/coda/cache.c ++++ b/fs/coda/cache.c +@@ -93,12 +93,14 @@ static void coda_flag_children(struct dentry *parent, int flag) + struct dentry *de; + + spin_lock(&parent->d_lock); ++ rcu_read_lock(); + hlist_for_each_entry(de, &parent->d_children, d_sib) { + struct inode *inode = d_inode_rcu(de); + /* don't know what to do with negative dentries */ + if (inode) + coda_flag_inode(inode, flag); + } ++ rcu_read_unlock(); + spin_unlock(&parent->d_lock); + } + +-- +2.53.0 + diff --git a/queue-6.12/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-6.12/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..69703f1b35 --- /dev/null +++ b/queue-6.12/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 28f383827613af1d56b78b23221a82d7fcfdbdc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index e9e7dceb606e1..f997a51792699 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -2832,6 +2832,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-6.12/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..10317f770f --- /dev/null +++ b/queue-6.12/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From 2db58866ef4a28471e61dc294c35ec93429aee5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 1328327d1d372..17a4811de2ae2 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1849,3 +1849,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 24e4af14fcca4..2e26a46f535d2 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -144,6 +144,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 3a7881c0a5b13..702d5445695f8 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2960,6 +2960,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2976,6 +2979,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3541,7 +3558,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.12/dm-integrity-fix-mismatched-queue-limits.patch b/queue-6.12/dm-integrity-fix-mismatched-queue-limits.patch new file mode 100644 index 0000000000..ce3c660515 --- /dev/null +++ b/queue-6.12/dm-integrity-fix-mismatched-queue-limits.patch @@ -0,0 +1,48 @@ +From 737307ac3746a2b7c433dbc2225188232d39fb82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:36:06 -0700 +Subject: dm-integrity: fix mismatched queue limits + +From: Keith Busch + +[ Upstream commit 6ebf3b6c6f16fda0568aa4207c6cd398f983c354 ] + +A user can integritysetup a device with a backing device using a 4k +logical block size, but request the dm device use 1k or 2k. This +mismatch creates an inconsistency such that the dm device would report +limits for IO that it can't actually execute. Fix this by using the +backing device's limits if they are larger. + +Signed-off-by: Keith Busch +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-integrity.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index e1dc373ad209d..26b7ddee34622 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -3908,9 +3908,15 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim + struct dm_integrity_c *ic = ti->private; + + if (ic->sectors_per_block > 1) { +- limits->logical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->physical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->io_min = ic->sectors_per_block << SECTOR_SHIFT; ++ limits->logical_block_size = ++ max(limits->logical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->physical_block_size = ++ max(limits->physical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->io_min = ++ max(limits->io_min, ++ ic->sectors_per_block << SECTOR_SHIFT); + limits->dma_alignment = limits->logical_block_size - 1; + limits->discard_granularity = ic->sectors_per_block << SECTOR_SHIFT; + } +-- +2.53.0 + diff --git a/queue-6.12/dm-vdo-indexer-validate-saved-zone-count.patch b/queue-6.12/dm-vdo-indexer-validate-saved-zone-count.patch new file mode 100644 index 0000000000..d8f8c4aa9d --- /dev/null +++ b/queue-6.12/dm-vdo-indexer-validate-saved-zone-count.patch @@ -0,0 +1,36 @@ +From 5ae1e64e603785db7bc6b43d111006b9ecd2a573 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:54 -0500 +Subject: dm vdo indexer: validate saved zone count + +From: Matthew Sakai + +[ Upstream commit 9e809bb1defe9be7fed2e21552c6b03b2694394d ] + +Verify that the loaded zone count is in the valid range +before using it as a loop iterator. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/indexer/index-layout.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/md/dm-vdo/indexer/index-layout.c b/drivers/md/dm-vdo/indexer/index-layout.c +index 053b7845d1f34..af228bb2d5fca 100644 +--- a/drivers/md/dm-vdo/indexer/index-layout.c ++++ b/drivers/md/dm-vdo/indexer/index-layout.c +@@ -1471,6 +1471,9 @@ static int __must_check reconstruct_index_save(struct index_save_layout *isl, + u64 last_block = next_block + isl->index_save.block_count; + + isl->zone_count = table->header.region_count - 3; ++ if (isl->zone_count > MAX_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); + + last_region = &table->regions[table->header.region_count - 1]; + if (last_region->kind == RL_KIND_EMPTY) { +-- +2.53.0 + diff --git a/queue-6.12/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch b/queue-6.12/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch new file mode 100644 index 0000000000..2d41418a91 --- /dev/null +++ b/queue-6.12/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch @@ -0,0 +1,37 @@ +From 72ebc84912dce8bdd0ea88f540c842833c8a4a3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:55 -0500 +Subject: dm vdo slab-depot: validate old zone count on load + +From: Matthew Sakai + +[ Upstream commit b3929b2cc2a6003b8e301e6540c651e60d24dcb4 ] + +Verify the old zone count has a valid value before using +it to compute slab summary entry offsets. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/slab-depot.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c +index 274f9ccd072f0..3b6b402ee2d22 100644 +--- a/drivers/md/dm-vdo/slab-depot.c ++++ b/drivers/md/dm-vdo/slab-depot.c +@@ -4172,6 +4172,10 @@ int vdo_decode_slab_depot(struct slab_depot_state_2_0 state, struct vdo *vdo, + } + slab_size_shift = ilog2(slab_size); + ++ if (state.zone_count > MAX_VDO_PHYSICAL_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); ++ + result = vdo_allocate_extended(struct slab_depot, + vdo->thread_config.physical_zone_count, + struct block_allocator, __func__, &depot); +-- +2.53.0 + diff --git a/queue-6.12/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch b/queue-6.12/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch new file mode 100644 index 0000000000..e13539cfb0 --- /dev/null +++ b/queue-6.12/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch @@ -0,0 +1,40 @@ +From 78d928619032cfee5c8506f0ea93c26bfe3cba39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:48:39 +0100 +Subject: drivers/virt: pkvm: Add Kconfig dependency on DMA_RESTRICTED_POOL + +From: Will Deacon + +[ Upstream commit 61135967fa76d37883d90ccccc5a1cb73e90b94d ] + +pKVM guests practically rely on CONFIG_DMA_RESTRICTED_POOL=y in order +to establish shared memory regions with the host for virtio buffers. + +Make CONFIG_ARM_PKVM_GUEST depend on CONFIG_DMA_RESTRICTED_POOL to avoid +the inevitable segmentation faults experience if you have the former but +not the latter. + +Reported-by: Marc Zyngier +Signed-off-by: Will Deacon +Link: https://patch.msgid.link/20260330144841.26181-39-will@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Sasha Levin +--- + drivers/virt/coco/pkvm-guest/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/virt/coco/pkvm-guest/Kconfig b/drivers/virt/coco/pkvm-guest/Kconfig +index d2f344f1f98f7..928b8e1668ccc 100644 +--- a/drivers/virt/coco/pkvm-guest/Kconfig ++++ b/drivers/virt/coco/pkvm-guest/Kconfig +@@ -1,6 +1,6 @@ + config ARM_PKVM_GUEST + bool "Arm pKVM protected guest driver" +- depends on ARM64 ++ depends on ARM64 && DMA_RESTRICTED_POOL + help + Protected guests running under the pKVM hypervisor on arm64 + are isolated from the host and must issue hypercalls to enable +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-6.12/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..1a800ae7df --- /dev/null +++ b/queue-6.12/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From fb29c73711e0f0cb6e153af83d2f96d2ff7dbc73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index fad0129bf8b12..d052af34bcb8d 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1936,7 +1936,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch b/queue-6.12/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch new file mode 100644 index 0000000000..dd39beabfb --- /dev/null +++ b/queue-6.12/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch @@ -0,0 +1,64 @@ +From 3a4c56c7481314d484846a9a06c1024f2b2e4e16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 17:08:01 -0500 +Subject: drm/amd/display: Exit IPS w/ DC helper for all dc_set_power_state + cases + +From: Ovidiu Bunea + +[ Upstream commit f44c094449669c7d9ac403cc73ce23e255f0828b ] + +[why & how] +On D3 path during dc_set_power_state, we may be in idle_allowed=true, +at which point we will exit idle via dc_wake_and_execute_dmub_cmd_list +which doesn't update dc->idle_optimizations_allowed to false. This +would cause any future attempts to allow idle optimizations via the DC +helper to get skipped because the value is stale and not reflective of +the actual HW state. + +Move dc_exit_ips_for_hw_access() to the top of the function. +Additionally ensure that dc_power_down_on_boot thread holds the DC +lock and only runs if there are 0 streams. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ovidiu Bunea +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 257d77aa7c979..fbfa9bfb6c3a1 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -5231,6 +5231,9 @@ void dc_power_down_on_boot(struct dc *dc) + { + if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW && + dc->hwss.power_down_on_boot) { ++ if (dc->current_state->stream_count > 0) ++ return; ++ + if (dc->caps.ips_support) + dc_exit_ips_for_hw_access(dc); + dc->hwss.power_down_on_boot(dc); +@@ -5242,12 +5245,12 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state) + if (!dc->current_state) + return; + ++ dc_exit_ips_for_hw_access(dc); ++ + switch (power_state) { + case DC_ACPI_CM_POWER_STATE_D0: + dc_state_construct(dc, dc->current_state); + +- dc_exit_ips_for_hw_access(dc); +- + dc_z10_restore(dc); + + dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state); +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch b/queue-6.12/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch new file mode 100644 index 0000000000..c496540a04 --- /dev/null +++ b/queue-6.12/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch @@ -0,0 +1,61 @@ +From 7f5b23f46a170cca0caa4f9388f0ca1b1f4f7208 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:57:19 -0500 +Subject: drm/amd/display: Fix cursor pos at overlay plane edges on DCN4 + +From: Ivan Lipski + +[ Upstream commit d8f6c978fd3d12ae129879dd1c514cec2e8cf2f8 ] + +[Why&How] +On DCN4, when cursor straddles the left/top edge of an overlay plane, the +recout-relative position becomes negative. These negative values wrap +to large positive numbers when cast to uint32_t, causing the cursor on the +the overlay plane to disappear. + +Fix by adding hotspot adjustment and position clamping after the +recout-relative calculation, matching the existing ODM/MPC slice +boundary handling. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index 768b756d427c7..176b4264f659f 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1246,6 +1246,25 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) + x_pos = pos_cpy.x - param.recout.x; + y_pos = pos_cpy.y - param.recout.y; + ++ /** ++ * If the cursor position is negative after recout adjustment, we need ++ * to shift the hotspot to compensate and clamp position to 0. This ++ * handles the case where cursor straddles the left/top edge of an ++ * overlay plane - the cursor is partially visible and needs correct ++ * hotspot adjustment to render the visible portion. ++ */ ++ if (x_pos < 0) { ++ pos_cpy.x_hotspot -= x_pos; ++ if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) ++ adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); ++ x_pos = 0; ++ } ++ ++ if (y_pos < 0) { ++ pos_cpy.y_hotspot -= y_pos; ++ y_pos = 0; ++ } ++ + recout_x_pos = x_pos - pos_cpy.x_hotspot; + recout_y_pos = y_pos - pos_cpy.y_hotspot; + +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-fix-dcn401_optimize_bandwidth.patch b/queue-6.12/drm-amd-display-fix-dcn401_optimize_bandwidth.patch new file mode 100644 index 0000000000..e70966b4b3 --- /dev/null +++ b/queue-6.12/drm-amd-display-fix-dcn401_optimize_bandwidth.patch @@ -0,0 +1,49 @@ +From 4b9b9522ba9a0ba183dd34045660474425358441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:53:44 -0500 +Subject: drm/amd/display: Fix dcn401_optimize_bandwidth + +From: Charlene Liu + +[ Upstream commit 002f32db0d4292f117994c330928d2374887b28e ] + +[Why&How] +We should check for != zstate disallow and programming extend blank from a +different struct. + +Reviewed-by: Leo Chen +Reviewed-by: Dmytro Laktyushkin +Signed-off-by: Charlene Liu +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index 176b4264f659f..41867003c0949 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1516,7 +1516,7 @@ void dcn401_optimize_bandwidth( + dc->clk_mgr, + context, + true); +- if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { ++ if (context->bw_ctx.bw.dcn.clk.zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW) { + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + +@@ -1524,7 +1524,7 @@ void dcn401_optimize_bandwidth( + && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max + && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) + pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, +- pipe_ctx->dlg_regs.min_dst_y_next_start); ++ pipe_ctx->hubp_regs.dlg_regs.min_dst_y_next_start); + } + } + } +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-merge-pipes-for-validate.patch b/queue-6.12/drm-amd-display-merge-pipes-for-validate.patch new file mode 100644 index 0000000000..95a8de329f --- /dev/null +++ b/queue-6.12/drm-amd-display-merge-pipes-for-validate.patch @@ -0,0 +1,43 @@ +From bcfc13fb375754de436e08a286231c46541b5a59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:48:11 -0500 +Subject: drm/amd/display: Merge pipes for validate + +From: Harry Wentland + +[ Upstream commit 606f6b171326152ef08d0ef0ad49f52034edca07 ] + +Validation expects to operate on non-split pipes. This is +seen in dcn20_fast_validate_bw, which merges pipes for +validation. We weren't doing that in the non-fast path +which lead to validation failures when operating with +4-to-1 MPC and a writeback connector. + +Co-developed by Claude Sonnet 4.5 + +Assisted-by: Claude:claude-sonnet-4.5 +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Harry Wentland +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +index 75cc84473a577..6afe022072ba7 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +@@ -1643,6 +1643,8 @@ noinline bool dcn30_internal_validate_bw( + if (!pipes) + return false; + ++ dcn20_merge_pipes_for_validate(dc, context); ++ + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-remove-duplicate-format-modifier.patch b/queue-6.12/drm-amd-display-remove-duplicate-format-modifier.patch new file mode 100644 index 0000000000..69a663e844 --- /dev/null +++ b/queue-6.12/drm-amd-display-remove-duplicate-format-modifier.patch @@ -0,0 +1,60 @@ +From 47c698c304624038daade3d2177a49653b375f1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:08:15 -0500 +Subject: drm/amd/display: remove duplicate format modifier + +From: Erik Kurzinger + +[ Upstream commit 6736c8ff9d63e847a3b694aeaeb78d4e8ad42464 ] + +amdgpu_dm_plane_get_plane_modifiers always adds DRM_FORMAT_MOD_LINEAR to +the list of modifiers. However, with gfx12, +amdgpu_dm_plane_add_gfx12_modifiers also adds that modifier to the list. +So we end up with two copies. Most apps just ignore this but some +(Weston) don't like it. + +As a fix, we change amdgpu_dm_plane_add_gfx12_modifiers to not add +DRM_FORMAT_MOD_LINEAR to the list, matching the behavior of analogous +functions for other chips. + +Signed-off-by: Erik Kurzinger +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 1e993f5d734a6..ce468ddbab9ad 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -699,21 +699,21 @@ static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, + uint8_t max_comp_block[] = {1, 0}; + uint64_t max_comp_block_mod[ARRAY_SIZE(max_comp_block)] = {0}; + uint8_t i = 0, j = 0; +- uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b, DRM_FORMAT_MOD_LINEAR}; ++ /* Note, linear (no DCC) gets added to the modifier list for all chips by the caller. */ ++ uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b}; + + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + max_comp_block_mod[i] = AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, max_comp_block[i]); + + /* With DCC: Best choice should be kept first. Hence, add all 256k modifiers of different + * max compressed blocks first and then move on to the next smaller sized layouts. +- * Do not add the linear modifier here, and hence the condition of size-1 for the loop + */ +- for (j = 0; j < ARRAY_SIZE(gfx12_modifiers) - 1; j++) ++ for (j = 0; j < ARRAY_SIZE(gfx12_modifiers); j++) + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, + ver | dcc | max_comp_block_mod[i] | gfx12_modifiers[j]); + +- /* Without DCC. Add all modifiers including linear at the end */ ++ /* Without DCC. */ + for (i = 0; i < ARRAY_SIZE(gfx12_modifiers); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, gfx12_modifiers[i]); + +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch b/queue-6.12/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch new file mode 100644 index 0000000000..9362c9bc42 --- /dev/null +++ b/queue-6.12/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch @@ -0,0 +1,63 @@ +From 85bcf63343f4b67ced0f40ca47575ca9d4071591 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:45:47 -0400 +Subject: drm/amd/display: Remove invalid DPSTREAMCLK mask usage + +From: Roman Li + +[ Upstream commit 8de2559ec172b04301d6e53c4f30388e40fad08c ] + +[Why] +The invalid register field access causes ASSERT(mask != 0) to fire +in set_reg_field_values() during display enable. + +WARNING: at drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:100 +set_reg_field_values.isra.0+0xcf/0xf0 [amdgpu] +Call Trace: + +generic_reg_update_ex+0x66/0x1d0 [amdgpu] +dccg401_set_dpstreamclk+0xed/0x350 [amdgpu] +dcn401_enable_stream+0x165/0x370 [amdgpu] +link_set_dpms_on+0x6e9/0xe90 [amdgpu] +dce110_apply_single_controller_ctx_to_hw+0x343/0x530 [amdgpu] +dce110_apply_ctx_to_hw+0x1f6/0x2d0 [amdgpu] +dc_commit_state_no_check+0x49a/0xe20 [amdgpu] +dc_commit_streams+0x354/0x570 [amdgpu] +amdgpu_dm_atomic_commit_tail+0x6f8/0x3fc0 [amdgpu] + +DCN4.x hardware does not have DPSTREAMCLK_GATE_DISABLE and +DPSTREAMCLK_ROOT_GATE_DISABLE fields in DCCG_GATE_DISABLE_CNTL3. +These global fields only exist in DCN3.1.x hardware. + +[How] +Remove the call that tries to update non-existent fields in CNTL3. +DCN4.x uses per-instance fields in CNTL5 instead, +which are already correctly programmed in the switch cases above. + +Reviewed-by: Dillon Varone +Signed-off-by: Roman Li +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +index 8cdc7ad104549..88d3770bbd5d1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c ++++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +@@ -525,10 +525,6 @@ static void dccg401_enable_dpstreamclk(struct dccg *dccg, int otg_inst, int dp_h + BREAK_TO_DEBUGGER(); + return; + } +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) +- REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3, +- DPSTREAMCLK_GATE_DISABLE, 1, +- DPSTREAMCLK_ROOT_GATE_DISABLE, 1); + } + + static void dccg401_disable_dpstreamclk(struct dccg *dccg, int dp_hpo_inst) +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch b/queue-6.12/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch new file mode 100644 index 0000000000..13b701a455 --- /dev/null +++ b/queue-6.12/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch @@ -0,0 +1,36 @@ +From 810599941c6f75d04238a8d9278ba4d3f6114b94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 09:33:17 +0800 +Subject: drm/amdgpu: fix DF NULL pointer issue for soc24 + +From: Likun Gao + +[ Upstream commit 50808826a64b4957b7088c789e539dd0a75a1560 ] + +If DF function not initialized, NULL pointer issue +will happen on soc24. + +Signed-off-by: Likun Gao +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/soc24.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c +index 53d96edc2877a..1ffc7f741d81e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc24.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc24.c +@@ -485,7 +485,7 @@ static int soc24_common_hw_init(void *handle) + if (adev->nbio.funcs->remap_hdp_registers) + adev->nbio.funcs->remap_hdp_registers(adev); + +- if (adev->df.funcs->hw_init) ++ if (adev->df.funcs && adev->df.funcs->hw_init) + adev->df.funcs->hw_init(adev); + + /* enable the doorbell aperture */ +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch b/queue-6.12/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch new file mode 100644 index 0000000000..e6cc2e91e3 --- /dev/null +++ b/queue-6.12/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch @@ -0,0 +1,46 @@ +From 3f4afed3be58cfbd4575a773fd09aa8b9c09c68e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 18:53:40 +0800 +Subject: drm/amdgpu: fix shift-out-of-bounds when updating umc active mask + +From: Hawking Zhang + +[ Upstream commit 1394a4926f4bcff0dc6ac6deea5beeb2844297f0 ] + +UMC node_inst_num can exceed 32, causing +(1 << node_inst_num) to shift a 32-bit int +out of bounds + +Signed-off-by: Hawking Zhang +Reviewed-by: Likun Gao +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index f62ac736ed76c..2b4db5fccff55 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -698,7 +698,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + struct harvest_table *harvest_info; + u16 offset; + int i; +- uint32_t umc_harvest_config = 0; ++ u64 umc_harvest_config = 0; + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset); +@@ -754,7 +754,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + } + } + +- adev->umc.active_mask = ((1 << adev->umc.node_inst_num) - 1) & ++ adev->umc.active_mask = ((1ULL << adev->umc.node_inst_num) - 1ULL) & + ~umc_harvest_config; + } + +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch b/queue-6.12/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch new file mode 100644 index 0000000000..27c91d9132 --- /dev/null +++ b/queue-6.12/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch @@ -0,0 +1,95 @@ +From a85ff9d3fa90fe1c3166f71286a58605522a209f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:28:59 +0800 +Subject: drm/amdgpu: guard atom_context in devcoredump VBIOS dump + +From: Jesse Zhang + +[ Upstream commit 557fa5a453c9ccb49a22f30a7ad0545573d434b7 ] + +During GPU reset coredump generation, amdgpu_devcoredump_fw_info() unconditionally +dereferences adev->mode_info.atom_context to print VBIOS fields. On reset/teardown +paths this pointer can be NULL, causing a kernel page fault from the deferred +coredump workqueue. + +Fix by checking ctx before printing VBIOS fields: + +if ctx is valid, print full VBIOS information as before; +This prevents NULL-dereference crashes while preserving coredump output. + +Observed page fault log: +[ 667.933329] RIP: 0010:amdgpu_devcoredump_format+0x780/0xc00 [amdgpu] +[ 667.941517] amdgpu 0002:01:00.0: Dumping IP State +[ 667.949660] Code: 8d 57 74 48 c7 c6 01 65 9f c2 48 8d 7d 98 e8 97 96 7a ff 49 8d 97 b4 00 00 00 48 c7 c6 18 65 9f c2 48 8d 7d 98 e8 80 96 7a ff <41> 8b 97 f4 00 00 00 48 c7 c6 2f 65 9f c2 48 8d 7d 98 e8 69 96 7a +[ 667.949666] RSP: 0018:ffffc9002302bd50 EFLAGS: 00010246 +[ 667.949673] RAX: 0000000000000000 RBX: ffff888110600000 RCX: 0000000000000000 +[ 667.949676] RDX: 000000000000a9b5 RSI: 0000000000000405 RDI: 000000000000a999 +[ 667.949680] RBP: ffffc9002302be00 R08: ffffffffc09c3084 R09: ffffffffc09c3085 +[ 667.949684] R10: 0000000000000000 R11: 0000000000000004 R12: 00000000000048e0 +[ 667.993908] amdgpu 0002:01:00.0: Dumping IP State Completed +[ 667.994229] R13: 0000000000000025 R14: 000000000000000c R15: 0000000000000000 +[ 667.994233] FS: 0000000000000000(0000) GS:ffff88c44c2c9000(0000) knlGS:0000000000000000 +[ 668.000076] amdgpu 0002:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.008025] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 668.008030] CR2: 00000000000000f4 CR3: 000000011195f001 CR4: 0000000000770ef0 +[ 668.008035] PKRU: 55555554 +[ 668.008040] Call Trace: +[ 668.008045] +[ 668.016010] amdgpu 0002:01:00.0: [drm] Check your /sys/class/drm/card16/device/devcoredump/data +[ 668.023967] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 668.023988] ? __pfx___drm_printfn_coredump+0x10/0x10 [drm] +[ 668.031950] amdgpu 0003:01:00.0: Dumping IP State +[ 668.038159] ? __pfx___drm_puts_coredump+0x10/0x10 [drm] +[ 668.083017] amdgpu 0003:01:00.0: Dumping IP State Completed +[ 668.083824] amdgpu_devcoredump_deferred_work+0x26/0xc0 [amdgpu] +[ 668.086163] amdgpu 0003:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.095863] process_scheduled_works+0xa6/0x420 +[ 668.095880] worker_thread+0x12a/0x270 +[ 668.101223] amdgpu 0003:01:00.0: [drm] Check your /sys/class/drm/card24/device/devcoredump/data +[ 668.107441] kthread+0x10d/0x230 +[ 668.107451] ? __pfx_worker_thread+0x10/0x10 +[ 668.107458] ? __pfx_kthread+0x10/0x10 +[ 668.112709] amdgpu 0000:01:00.0: ring vcn_unified_1 timeout, signaled seq=9, emitted seq=10 +[ 668.118630] ret_from_fork+0x17c/0x1f0 +[ 668.118640] ? __pfx_kthread+0x10/0x10 +[ 668.118647] ret_from_fork_asm+0x1a/0x30 + +Reviewed-by: Lijo Lazar +Suggested-by: Lijo Lazar +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +index 18b3b1aaa1d3b..021ef67632e74 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +@@ -187,12 +187,16 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev, + drm_printf(p, "VPE feature version: %u, fw version: 0x%08x\n", + adev->vpe.feature_version, adev->vpe.fw_version); + +- drm_printf(p, "\nVBIOS Information\n"); +- drm_printf(p, "vbios name : %s\n", ctx->name); +- drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); +- drm_printf(p, "vbios version : %d\n", ctx->version); +- drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); +- drm_printf(p, "vbios date : %s\n", ctx->date); ++ if (adev->bios) { ++ drm_printf(p, "\nVBIOS Information\n"); ++ drm_printf(p, "vbios name : %s\n", ctx->name); ++ drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); ++ drm_printf(p, "vbios version : %d\n", ctx->version); ++ drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); ++ drm_printf(p, "vbios date : %s\n", ctx->date); ++ }else { ++ drm_printf(p, "\nVBIOS Information: NA\n"); ++ } + } + + static ssize_t +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-6.12/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..a7bec8c810 --- /dev/null +++ b/queue-6.12/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 9c40dfcbd62255202dc011f8890fba20bd53e483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 844e49d1499ed..1bfa6803bc16d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1740,6 +1740,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-6.12/drm-gem-dma-set-vm_dontdump-for-mmap.patch b/queue-6.12/drm-gem-dma-set-vm_dontdump-for-mmap.patch new file mode 100644 index 0000000000..0723cc8ec6 --- /dev/null +++ b/queue-6.12/drm-gem-dma-set-vm_dontdump-for-mmap.patch @@ -0,0 +1,49 @@ +From 2ab55c6e722eecbe083ddd6a52abb219895126f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 12:00:32 +0800 +Subject: drm/gem-dma: set VM_DONTDUMP for mmap + +From: Chen-Yu Tsai + +[ Upstream commit e3eb0e70815cc02ea15298818e37d8b0a0930ab1 ] + +When the mmap function was converted from a file op to a GEM object +function in commit f5ca8eb6f9bd ("drm/cma-helper: Implement mmap as GEM +CMA object functions") some VM flags were not lifted from drm_gem_mmap(): + + - VM_IO + - VM_DONTEXPAND + - VM_DONTDUMP + +VM_DONTEXPAND was added back in commit 59f39bfa6553 ("drm/cma-helper: +Set VM_DONTEXPAND for mmap"). VM_IO doesn't make sense since these are +memory buffers, while "IO tells people not to look at these pages +(accesses can have side effects)". + +Add back VM_DONTDUMP. This matches the behavior of most other GEM +implementations. + +Reviewed-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260317040034.617585-1-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gem_dma_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c +index 870b90b78bc4e..8128002cdb7b1 100644 +--- a/drivers/gpu/drm/drm_gem_dma_helper.c ++++ b/drivers/gpu/drm/drm_gem_dma_helper.c +@@ -530,7 +530,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct * + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); +- vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); ++ vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP); + + if (dma_obj->map_noncoherent) { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); +-- +2.53.0 + diff --git a/queue-6.12/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-6.12/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..83b9b3ef74 --- /dev/null +++ b/queue-6.12/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From de64df7e4e21a326b80282c5d73b11008b971f39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 88f3dfeb4731d..d4ab74d629163 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -672,6 +672,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -724,6 +739,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -769,30 +786,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch b/queue-6.12/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch new file mode 100644 index 0000000000..d4ce161fab --- /dev/null +++ b/queue-6.12/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch @@ -0,0 +1,60 @@ +From 03a4cea2f2001411ac634a26af3c27efe8147682 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:17:00 +0100 +Subject: drm/msm/dpu: fix vblank IRQ registration before atomic_mode_set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit 961c900628fef77ad07b4bc4c868e47b9a1269c7 ] + +dpu_encoder_toggle_vblank_for_crtc() can call control_vblank_irq() +at any time in response to a userspace vblank request, independently +of the atomic commit sequence. If this happens before the encoder's +first atomic_mode_set(), irq[INTR_IDX_RDPTR] is still zero. + +Passing irq_idx=0 to dpu_core_irq_register_callback() is treated as +invalid, and DPU_IRQ_REG(0) and DPU_IRQ_BIT(0) produce misleading +values of 134217727 and 31 respectively due to unsigned wraparound +in the (irq_idx - 1) macros, resulting in the confusing error: + + [dpu error]invalid IRQ=[134217727, 31] + +Since irq[INTR_IDX_RDPTR] will be properly populated by +atomic_mode_set() and registered by irq_enable() as part of the +normal modeset sequence, silently skip the vblank IRQ registration +when the index has not yet been initialized. This matches the +existing pattern of the master encoder check above it. + +Signed-off-by: Cédric Bellegarde +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/712752/ +Link: https://lore.kernel.org/r/20260318171700.394945-1-cedric.bellegarde@adishatz.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 65dad86edb46e..8fa47559960c6 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -253,6 +253,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + ++ /* IRQ not yet initialized */ ++ if (!phys_enc->irq[INTR_IDX_RDPTR]) { ++ ret = -EINVAL; ++ goto end; ++ } ++ + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-6.12/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..d250cf3769 --- /dev/null +++ b/queue-6.12/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 3bf479e935dc37f968eae471d36c7802b7b218b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index 538d91be88578..38c9b39f9105b 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - const: marvell,armada7040 +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch b/queue-6.12/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch new file mode 100644 index 0000000000..e8ba423612 --- /dev/null +++ b/queue-6.12/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch @@ -0,0 +1,37 @@ +From 218c7eca809b44f5e986f02f613a9f49465be9a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:42 +0100 +Subject: dt-bindings: rtc: microcrystal,rv3028: Allow to specify vdd-supply + +From: Frieder Schrempf + +[ Upstream commit 10663044bee592ba049a2aa37f4431fbdf93b739 ] + +In case the VDD supply voltage regulator of the RTC needs to be +specified explicitly, allow to set vdd-supply. + +Signed-off-by: Frieder Schrempf +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20260309085749.25747-2-frieder@fris.de +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +index cda8ad7c12037..2ea3b40419530 100644 +--- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml ++++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +@@ -32,6 +32,8 @@ properties: + - 9000 + - 15000 + ++ vdd-supply: true ++ + required: + - compatible + - reg +-- +2.53.0 + diff --git a/queue-6.12/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-6.12/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..e7aab42c3e --- /dev/null +++ b/queue-6.12/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From 61a70a20d604eb47bc0a98330d651925480f1bf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 577c563023144..4ba5dba96956b 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -559,6 +559,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-6.12/enic-add-v2-sr-iov-vf-device-id.patch b/queue-6.12/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..4afaef28a4 --- /dev/null +++ b/queue-6.12/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,54 @@ +From 5b5887763a982d9cdf339ba9652f5fe76e19ad49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index a432783756d8c..5e971d0a18b97 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -67,6 +67,7 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + #define RX_COPYBREAK_DEFAULT 256 + +@@ -75,6 +76,7 @@ static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -310,7 +312,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-6.12/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch b/queue-6.12/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch new file mode 100644 index 0000000000..4fb2ba99da --- /dev/null +++ b/queue-6.12/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch @@ -0,0 +1,53 @@ +From 8596c09abcba76b336b089dda1eb8bb6bfe25f3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:02:49 +0800 +Subject: erofs: ensure all folios are managed in + erofs_try_to_free_all_cached_folios() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhan Xusheng + +[ Upstream commit 5de6951fedb29700ace53b283ccb951c8f712d12 ] + +folio_trylock() in erofs_try_to_free_all_cached_folios() may +successfully acquire the folio lock, but the subsequent check +for erofs_folio_is_managed() can skip unlocking when the folio +is not managed by EROFS. + +As Gao Xiang pointed out, this condition should not happen in +practice because compressed_bvecs[] only holds valid cached folios +at this point — any non-managed folio would have already been +detached by z_erofs_cache_release_folio() under folio lock. + +Fix this by adding DBG_BUGON() to catch unexpected folios +and ensure folio_unlock() is always called. + +Suggested-by: Gao Xiang +Signed-off-by: Zhan Xusheng +Reviewed-by: Gao Xiang +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index a81b6e6aee59a..0df85b4415765 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -589,8 +589,7 @@ static int erofs_try_to_free_all_cached_folios(struct erofs_sb_info *sbi, + if (!folio_trylock(folio)) + return -EBUSY; + +- if (!erofs_folio_is_managed(sbi, folio)) +- continue; ++ DBG_BUGON(!erofs_folio_is_managed(sbi, folio)); + pcl->compressed_bvecs[i].page = NULL; + folio_detach_private(folio); + folio_unlock(folio); +-- +2.53.0 + diff --git a/queue-6.12/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-6.12/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..df839bf127 --- /dev/null +++ b/queue-6.12/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From 45dfda021216070edee415015bda3c699cdf8e85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-6.12/exfat-fix-bitwise-operation-having-different-size.patch b/queue-6.12/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..c233c0cf5a --- /dev/null +++ b/queue-6.12/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 85ca21d7f6eec96a206b254a2ee185114a57ce52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 1c428f7f83f5d..57e0de26fa2e8 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -267,7 +267,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-6.12/exfat-fix-incorrect-directory-checksum-after-rename-.patch b/queue-6.12/exfat-fix-incorrect-directory-checksum-after-rename-.patch new file mode 100644 index 0000000000..d200f532f5 --- /dev/null +++ b/queue-6.12/exfat-fix-incorrect-directory-checksum-after-rename-.patch @@ -0,0 +1,44 @@ +From 05329203edd4eb0b8175d562184cb36752be3406 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:33 +0800 +Subject: exfat: fix incorrect directory checksum after rename to shorter name + +From: Chi Zhiling + +[ Upstream commit ff37797badd831797b8a27830fe5046d7e23fdc3 ] + +When renaming a file in-place to a shorter name, exfat_remove_entries +marks excess entries as DELETED, but es->num_entries is not updated +accordingly. As a result, exfat_update_dir_chksum iterates over the +deleted entries and computes an incorrect checksum. + +This does not lead to persistent corruption because mark_inode_dirty() +is called afterward, and __exfat_write_inode later recomputes the +checksum using the correct num_entries value. + +Fix by setting es->num_entries = num_entries in exfat_init_ext_entry. + +Signed-off-by: Chi Zhiling +Reviewed-by: Sungjong Seo +Reviewed-by: Yuezhang Mo +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 57e0de26fa2e8..ac08c48ef2846 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -507,6 +507,7 @@ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries, + unsigned short *uniname = p_uniname->name; + struct exfat_dentry *ep; + ++ es->num_entries = num_entries; + ep = exfat_get_dentry_cached(es, ES_IDX_FILE); + ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); + +-- +2.53.0 + diff --git a/queue-6.12/exfat-fix-s_maxbytes.patch b/queue-6.12/exfat-fix-s_maxbytes.patch new file mode 100644 index 0000000000..69e06372bd --- /dev/null +++ b/queue-6.12/exfat-fix-s_maxbytes.patch @@ -0,0 +1,80 @@ +From a614787cd56aed0ffc1f6db0d0af6e350b47f656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 06:41:37 +0900 +Subject: exfat: fix s_maxbytes + +From: David Timber + +[ Upstream commit 4129a3a2751cba8511cee5d13145223662a8e019 ] + +With fallocate support, xfstest unit generic/213 fails with + + QA output created by 213 + We should get: fallocate: No space left on device + Strangely, xfs_io sometimes says "Success" when something went wrong + -fallocate: No space left on device + +fallocate: File too large + +because sb->s_maxbytes is set to the volume size. + +To be in line with other non-extent-based filesystems, set to max volume +size possible with the cluster size of the volume. + +Signed-off-by: David Timber +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/exfat_raw.h | 1 + + fs/exfat/file.c | 1 + + fs/exfat/super.c | 11 ++++++++--- + 3 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h +index 971a1ccd0e89e..22e6db4254bc0 100644 +--- a/fs/exfat/exfat_raw.h ++++ b/fs/exfat/exfat_raw.h +@@ -25,6 +25,7 @@ + #define EXFAT_FIRST_CLUSTER 2 + #define EXFAT_DATA_CLUSTER_COUNT(sbi) \ + ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) ++#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) + + /* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ + #define ALLOC_POSSIBLE 0x01 +diff --git a/fs/exfat/file.c b/fs/exfat/file.c +index 033852efe5dc3..6542201b6f167 100644 +--- a/fs/exfat/file.c ++++ b/fs/exfat/file.c +@@ -32,6 +32,7 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) + return ret; + + num_clusters = EXFAT_B_TO_CLU(exfat_ondisk_size(inode), sbi); ++ /* integer overflow is already checked in inode_newsize_ok(). */ + new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi); + + if (new_num_clusters == num_clusters) +diff --git a/fs/exfat/super.c b/fs/exfat/super.c +index 75c6d5046e313..70e58d2241d31 100644 +--- a/fs/exfat/super.c ++++ b/fs/exfat/super.c +@@ -551,9 +551,14 @@ static int exfat_read_boot_sector(struct super_block *sb) + if (sbi->vol_flags & MEDIA_FAILURE) + exfat_warn(sb, "Medium has reported failures. Some data may be lost."); + +- /* exFAT file size is limited by a disk volume size */ +- sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << +- sbi->cluster_size_bits; ++ /* ++ * Set to the max possible volume size for this volume's cluster size so ++ * that any integer overflow from bytes to cluster size conversion is ++ * checked in inode_newsize_ok(). Clamped to MAX_LFS_FILESIZE for 32-bit ++ * machines. ++ */ ++ sb->s_maxbytes = min(MAX_LFS_FILESIZE, ++ EXFAT_CLU_TO_B((loff_t)EXFAT_MAX_NUM_CLUSTER, sbi)); + + /* check logical sector size */ + if (exfat_calibrate_blocksize(sb, 1 << p_boot->sect_size_bits)) +-- +2.53.0 + diff --git a/queue-6.12/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-6.12/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..d64124fabb --- /dev/null +++ b/queue-6.12/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From 56fea5c4de8701b2d6bdadf701744e859a4905c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index cc4dcb7a32b57..ef9207bd22638 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -699,7 +699,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-6.12/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch b/queue-6.12/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch new file mode 100644 index 0000000000..054b288a85 --- /dev/null +++ b/queue-6.12/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch @@ -0,0 +1,45 @@ +From b88582dc3061c3e00bc43f70af51d995e7ef7849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 02:20:52 +0000 +Subject: ext2: avoid drop_nlink() during unlink of zero-nlink inode in + ext2_unlink() + +From: Ziyi Guo + +[ Upstream commit 19134a133184fcc49c41cf42797cb2e7fef76065 ] + +ext2_unlink() calls inode_dec_link_count() unconditionally, which +invokes drop_nlink(). If the inode was loaded from a corrupted disk +image with i_links_count == 0, drop_nlink() +triggers WARN_ON(inode->i_nlink == 0) + +Follow the ext4 pattern from __ext4_unlink(): check i_nlink before +decrementing. If already zero, skip the decrement. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260211022052.973114-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/namei.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c +index 8346ab9534c17..f5c8b4761b915 100644 +--- a/fs/ext2/namei.c ++++ b/fs/ext2/namei.c +@@ -292,7 +292,10 @@ static int ext2_unlink(struct inode *dir, struct dentry *dentry) + goto out; + + inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); +- inode_dec_link_count(inode); ++ ++ if (inode->i_nlink) ++ inode_dec_link_count(inode); ++ + err = 0; + out: + return err; +-- +2.53.0 + diff --git a/queue-6.12/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-6.12/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..59c016a02d --- /dev/null +++ b/queue-6.12/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From 159f973f9cc4f792ded8b834c8328086f4da9aeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index 3fcf8191da42a..8b3a2cb5d9024 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -638,7 +638,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-6.12/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch b/queue-6.12/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch new file mode 100644 index 0000000000..a0005f77df --- /dev/null +++ b/queue-6.12/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch @@ -0,0 +1,98 @@ +From 8f01dc36e889fb37217023bd6257f00239661e31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:29:14 +0530 +Subject: ext4: unmap invalidated folios from page tables in + mpage_release_unused_pages() + +From: Deepanshu Kartikey + +[ Upstream commit 9b25f381de6b8942645f43735cb0a4fb0ab3a6d1 ] + +When delayed block allocation fails (e.g., due to filesystem corruption +detected in ext4_map_blocks()), the writeback error handler calls +mpage_release_unused_pages(invalidate=true) which invalidates affected +folios by clearing their uptodate flag via folio_clear_uptodate(). + +However, these folios may still be mapped in process page tables. If a +subsequent operation (such as ftruncate calling ext4_block_truncate_page) +triggers a write fault, the existing page table entry allows access to +the now-invalidated folio. This leads to ext4_page_mkwrite() being called +with a non-uptodate folio, which then gets marked dirty, triggering: + + WARNING: CPU: 0 PID: 5 at mm/page-writeback.c:2960 + __folio_mark_dirty+0x578/0x880 + + Call Trace: + fault_dirty_shared_page+0x16e/0x2d0 + do_wp_page+0x38b/0xd20 + handle_pte_fault+0x1da/0x450 + +The sequence leading to this warning is: + +1. Process writes to mmap'd file, folio becomes uptodate and dirty +2. Writeback begins, but delayed allocation fails due to corruption +3. mpage_release_unused_pages(invalidate=true) is called: + - block_invalidate_folio() clears dirty flag + - folio_clear_uptodate() clears uptodate flag + - But folio remains mapped in page tables +4. Later, ftruncate triggers ext4_block_truncate_page() +5. This causes a write fault on the still-mapped folio +6. ext4_page_mkwrite() is called with folio that is !uptodate +7. block_page_mkwrite() marks buffers dirty +8. fault_dirty_shared_page() tries to mark folio dirty +9. block_dirty_folio() calls __folio_mark_dirty(warn=1) +10. WARNING triggers: WARN_ON_ONCE(warn && !uptodate && !dirty) + +Fix this by unmapping folios from page tables before invalidating them +using unmap_mapping_pages(). This ensures that subsequent accesses +trigger new page faults rather than reusing invalidated folios through +stale page table entries. + +Note that this results in data loss for any writes to the mmap'd region +that couldn't be written back, but this is expected behavior when +writeback fails due to filesystem corruption. The existing error message +already states "This should not happen!! Data will be lost". + +Reported-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Tested-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a +Suggested-by: Matthew Wilcox +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20251205055914.1393799-1-kartikey406@gmail.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index a0b68b9d96266..7b6cef79db5db 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1607,8 +1607,22 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd, + BUG_ON(!folio_test_locked(folio)); + BUG_ON(folio_test_writeback(folio)); + if (invalidate) { +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { + folio_clear_dirty_for_io(folio); ++ /* ++ * Unmap folio from page ++ * tables to prevent ++ * subsequent accesses through ++ * stale PTEs. This ensures ++ * future accesses trigger new ++ * page faults rather than ++ * reusing the invalidated ++ * folio. ++ */ ++ unmap_mapping_pages(folio->mapping, ++ folio->index, ++ folio_nr_pages(folio), false); ++ } + block_invalidate_folio(folio, 0, + folio_size(folio)); + folio_clear_uptodate(folio); +-- +2.53.0 + diff --git a/queue-6.12/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-6.12/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..44fce03876 --- /dev/null +++ b/queue-6.12/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From cf08e71534b23ad4f144669f7c6fd2a3b5f75c95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 6e09b80c0c377..8387472016486 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -910,6 +910,9 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-6.12/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-6.12/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..5222b3297b --- /dev/null +++ b/queue-6.12/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From 8c468a1c4f7098a8d9d8389963b47d35d4f45938 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index 211f23648686c..79688c2cc6d68 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-6.12/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-6.12/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..45e79059a9 --- /dev/null +++ b/queue-6.12/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From 1e2be32dc2d33c5657a9e1d1dd1586e28f60ce05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index ac41f8f37589f..c2f79357c8da0 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-6.12/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-6.12/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..f47c2fe332 --- /dev/null +++ b/queue-6.12/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From b5665ea095ac6a819f37e57b7d4788ae0e570f8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index 8673fced87492..3fa2304fbda7e 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-6.12/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-6.12/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..9a36c76b8c --- /dev/null +++ b/queue-6.12/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From acbd2aec838bf92ab2ec217beee6119e27afc8ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 0fbbb7286008d..6b8cfbee3b9d6 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-6.12/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-6.12/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..d5f5d90f58 --- /dev/null +++ b/queue-6.12/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From fb2c924a76c910d32472c69ff7811e4b31ab39ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index e8920178b50f7..128f574ebb860 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-6.12/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-6.12/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..4a71b649c7 --- /dev/null +++ b/queue-6.12/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From c6e503bc66a1e4acda8120056e82233a700547af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index 6861c09d66d77..7220b056c076d 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1009,7 +1009,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-6.12/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-6.12/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..7502565146 --- /dev/null +++ b/queue-6.12/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From 9f8f068d43caddb41f98629b247d0c5f09067272 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 1af1500ec24b6..b9ee545914760 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1574,7 +1574,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + if (boot2) { +-- +2.53.0 + diff --git a/queue-6.12/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-6.12/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..af60a3c1b0 --- /dev/null +++ b/queue-6.12/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 97572f08e0b0b493dae93b59d78e54e1640bada6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index b8d2827873a33..47ca220bf42f0 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-6.12/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-6.12/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..238a179f76 --- /dev/null +++ b/queue-6.12/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From f105a6c458385438b1e8785307e3c5b14a0dc6c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 23afaadd5f3e3..e59a08c71f121 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -116,6 +116,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-6.12/fuse-validate-outarg-offset-and-size-in-notify-store.patch b/queue-6.12/fuse-validate-outarg-offset-and-size-in-notify-store.patch new file mode 100644 index 0000000000..1d8165a923 --- /dev/null +++ b/queue-6.12/fuse-validate-outarg-offset-and-size-in-notify-store.patch @@ -0,0 +1,81 @@ +From 970677ca11d66e85634026c5a110fd72887822ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:44:46 -0800 +Subject: fuse: validate outarg offset and size in notify store/retrieve + +From: Joanne Koong + +[ Upstream commit 65161470f95bb579a72673bf303ecf0800b9054b ] + +Add validation checking for outarg offset and outarg size values passed +in by the server. MAX_LFS_FILESIZE is the maximum file size supported. +The fuse_notify_store_out and fuse_notify_retrieve_out structs take in +a uint64_t offset. + +Add logic to ensure: +* outarg.offset is less than MAX_LFS_FILESIZE +* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE +* potential uint64_t overflow is fixed when adding outarg.offset and + outarg.size. + +Signed-off-by: Joanne Koong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 1a6efb7cd945b..3edeed8fbd7a8 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1636,7 +1636,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + if (size - sizeof(outarg) != outarg.size) + goto out_finish; + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + nodeid = outarg.nodeid; ++ num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset); + + down_read(&fc->killsb); + +@@ -1649,13 +1653,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + index = outarg.offset >> PAGE_SHIFT; + offset = outarg.offset & ~PAGE_MASK; + file_size = i_size_read(inode); +- end = outarg.offset + outarg.size; ++ end = outarg.offset + num; + if (end > file_size) { + file_size = end; +- fuse_write_update_attr(inode, file_size, outarg.size); ++ fuse_write_update_attr(inode, file_size, num); + } + +- num = outarg.size; + while (num) { + struct page *page; + unsigned int this_num; +@@ -1733,7 +1736,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, + num = min(outarg->size, fc->max_write); + if (outarg->offset > file_size) + num = 0; +- else if (outarg->offset + num > file_size) ++ else if (num > file_size - outarg->offset) + num = file_size - outarg->offset; + + num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -1809,6 +1812,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, + + fuse_copy_finish(cs); + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + down_read(&fc->killsb); + err = -ENOENT; + nodeid = outarg.nodeid; +-- +2.53.0 + diff --git a/queue-6.12/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-6.12/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..0f901e0b8c --- /dev/null +++ b/queue-6.12/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 2aa16b689a7111c9fbc0b87479e0f2fd278957ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 9a4d55f703bb5..f0faac5796bbf 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.12/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-6.12/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..81d431dc56 --- /dev/null +++ b/queue-6.12/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 81c5aa09de58909ce83b5b0d0a4d157a7533e0c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index 49446a030f108..672f0f5b1ee79 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-6.12/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-6.12/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..1910cbf751 --- /dev/null +++ b/queue-6.12/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From ec32efd83d2c7867bbcd92ef8a2e58b65912a29d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 5c79ba1f229c4..6487ff529680e 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -55,7 +55,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.12/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-6.12/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..a2b2c11f82 --- /dev/null +++ b/queue-6.12/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 2655a6463249f65ca9a497c9838be3c98e7e34af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 8f5827554e1e8..ab17e25100d7e 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -52,7 +52,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, +-- +2.53.0 + diff --git a/queue-6.12/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-6.12/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..4e3e1ddfa4 --- /dev/null +++ b/queue-6.12/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 405dc76ac49c3a47dbcb4fabdd64e70dec7d96b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index e55d28a8a66f2..a8ab97bf49770 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -283,7 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-6.12/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-6.12/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..ee074fdfb1 --- /dev/null +++ b/queue-6.12/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From c8a3c0b098e90d523c8eaac97d1df92a78fdc7cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 1154c1d8f66f0..cc748cdcb0968 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -868,11 +868,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -884,7 +889,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-6.12/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..ccf0af5e41 --- /dev/null +++ b/queue-6.12/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From 4e04684364f037ba22944342b72417c0371f7c5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-6.12/hfsplus-fix-generic-642-failure.patch b/queue-6.12/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..bda4fdb534 --- /dev/null +++ b/queue-6.12/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From 104900e8b28f8322638f88a38cacfd5cdd327b5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 1918544a78716..b26cd7504e113 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-6.12/hid-logitech-hidpp-fix-race-condition-when-accessing.patch b/queue-6.12/hid-logitech-hidpp-fix-race-condition-when-accessing.patch new file mode 100644 index 0000000000..b9eaf061cd --- /dev/null +++ b/queue-6.12/hid-logitech-hidpp-fix-race-condition-when-accessing.patch @@ -0,0 +1,112 @@ +From 74b4a91e4b38d822d681c3fda697641ac28db703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:48:11 +0000 +Subject: HID: logitech-hidpp: fix race condition when accessing stale stack + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit e2aaf2d3ad92ac4a8afa6b69ad4c38e7747d3d6e ] + +The driver uses hidpp->send_receive_buf to point to a stack-allocated +buffer in the synchronous command path (__do_hidpp_send_message_sync). +However, this pointer is not cleared when the function returns. + +If an event is processed (e.g. by a different thread) while the +send_mutex is held by a new command, but before that command has +updated send_receive_buf, the handler (hidpp_raw_hidpp_event) will +observe that the mutex is locked and dereference the stale pointer. + +This results in an out-of-bounds access on a different thread's kernel +stack (or a NULL pointer dereference on the very first command). + +Fix this by: +1. Clearing hidpp->send_receive_buf to NULL before releasing the mutex + in the synchronous command path. +2. Moving the assignment of the local 'question' and 'answer' pointers + inside the mutex_is_locked() block in the handler, and adding + a NULL check before dereferencing. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index d60cd4379e866..74bd604be8514 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -306,21 +306,22 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + if (ret) { + dbg_hid("__hidpp_send_report returned err: %d\n", ret); + memset(response, 0, sizeof(struct hidpp_report)); +- return ret; ++ goto out; + } + + if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, + 5*HZ)) { + dbg_hid("%s:timeout waiting for response\n", __func__); + memset(response, 0, sizeof(struct hidpp_report)); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + + if (response->report_id == REPORT_ID_HIDPP_SHORT && + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + + if ((response->report_id == REPORT_ID_HIDPP_LONG || +@@ -328,10 +329,14 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + response->fap.feature_index == HIDPP20_ERROR) { + ret = response->fap.params[1]; + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + +- return 0; ++ ret = 0; ++ ++out: ++ hidpp->send_receive_buf = NULL; ++ return ret; + } + + /* +@@ -3867,8 +3872,7 @@ static int hidpp_input_configured(struct hid_device *hdev, + static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + int size) + { +- struct hidpp_report *question = hidpp->send_receive_buf; +- struct hidpp_report *answer = hidpp->send_receive_buf; ++ struct hidpp_report *question, *answer; + struct hidpp_report *report = (struct hidpp_report *)data; + int ret; + int last_online; +@@ -3878,6 +3882,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + * previously sent command. + */ + if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { ++ question = hidpp->send_receive_buf; ++ answer = hidpp->send_receive_buf; ++ ++ if (!question) ++ return 0; ++ + /* + * Check for a correct hidpp20 answer or the corresponding + * error +-- +2.53.0 + diff --git a/queue-6.12/hid-playstation-validate-num_touch_reports-in-dualsh.patch b/queue-6.12/hid-playstation-validate-num_touch_reports-in-dualsh.patch new file mode 100644 index 0000000000..3b545fa071 --- /dev/null +++ b/queue-6.12/hid-playstation-validate-num_touch_reports-in-dualsh.patch @@ -0,0 +1,64 @@ +From 00bc5d7550eca3d35210a28e71e57a9676ba2311 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:47:37 +0000 +Subject: HID: playstation: validate num_touch_reports in DualShock 4 reports +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit 82a4fc46330910b4c1d9b189561439d468e3ff11 ] + +The DualShock 4 HID driver fails to validate the num_touch_reports field +received from the device in both USB and Bluetooth input reports. +A malicious device could set this field to a value larger than the +allocated size of the touch_reports array (3 for USB, 4 for Bluetooth), +leading to an out-of-bounds read in dualshock4_parse_report(). + +This can result in kernel memory disclosure when processing malicious +HID reports. + +Validate num_touch_reports against the array size for the respective +connection types before processing the touch data. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 915b3ceb8d21b..c40b0a0ed9e45 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -2247,6 +2247,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + size == DS4_INPUT_REPORT_USB_SIZE) { + struct dualshock4_input_report_usb *usb = (struct dualshock4_input_report_usb *)data; + ++ if (usb->num_touch_reports > ARRAY_SIZE(usb->touch_reports)) { ++ hid_err(hdev, "DualShock4 USB input report has invalid num_touch_reports=%d\n", ++ usb->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &usb->common; + num_touch_reports = min_t(u8, usb->num_touch_reports, + ARRAY_SIZE(usb->touch_reports)); +@@ -2262,6 +2268,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + return -EILSEQ; + } + ++ if (bt->num_touch_reports > ARRAY_SIZE(bt->touch_reports)) { ++ hid_err(hdev, "DualShock4 BT input report has invalid num_touch_reports=%d\n", ++ bt->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &bt->common; + num_touch_reports = min_t(u8, bt->num_touch_reports, + ARRAY_SIZE(bt->touch_reports)); +-- +2.53.0 + diff --git a/queue-6.12/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-6.12/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..a2704f1d04 --- /dev/null +++ b/queue-6.12/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From f785a478d556145f6d3712b2ea7845907533e43a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index d9e33dde89899..9d396d2e534d0 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -234,7 +234,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-6.12/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-6.12/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..6a2e0cb037 --- /dev/null +++ b/queue-6.12/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From 9b813d92479bdd186810c55d54e5e0bb389ff42e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 9d396d2e534d0..7993fcabfe3a5 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -134,6 +134,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-6.12/hid-uclogic-fix-regression-of-input-name-assignment.patch b/queue-6.12/hid-uclogic-fix-regression-of-input-name-assignment.patch new file mode 100644 index 0000000000..27d1b6ba1b --- /dev/null +++ b/queue-6.12/hid-uclogic-fix-regression-of-input-name-assignment.patch @@ -0,0 +1,44 @@ +From 6f6150722c2f2c927cadc84ea9049f67f393efa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:33:16 +0200 +Subject: HID: uclogic: Fix regression of input name assignment + +From: Takashi Iwai + +[ Upstream commit 487359284509a6745e14b8c0518768bc277809b0 ] + +The previous fix for adding the devm_kasprintf() return check in the +commit bd07f751208b ("HID: uclogic: Add NULL check in +uclogic_input_configured()") changed the condition of hi->input->name +assignment, and it resulted in missing the proper input device name +when no custom suffix is defined. + +Restore the conditional to the original content to address the +regression. + +Fixes: bd07f751208b ("HID: uclogic: Add NULL check in uclogic_input_configured()") +Signed-off-by: Takashi Iwai +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-uclogic-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index 321c43fb06ae0..f8708a1ec7cc8 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -142,7 +142,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } else { ++ } ++ ++ if (suffix) { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); + if (!hi->input->name) +-- +2.53.0 + diff --git a/queue-6.12/i3c-master-move-bus_init-error-suppression.patch b/queue-6.12/i3c-master-move-bus_init-error-suppression.patch new file mode 100644 index 0000000000..719d2a01cf --- /dev/null +++ b/queue-6.12/i3c-master-move-bus_init-error-suppression.patch @@ -0,0 +1,98 @@ +From 1b3657ba2008b0533e5fe2a8d47e49ed645b893b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:31 +0100 +Subject: i3c: master: Move bus_init error suppression + +From: Jorge Marques + +[ Upstream commit 49775afa983e3e5ce8e7d00ee241791073be214d ] + +Prepare to fix improper Mx positive error propagation in later commits +by handling Mx error codes where the i3c_ccc_cmd command is allocated. +The CCC DISEC to broadcast address is invoked with +i3c_master_enec_disec_locked() and yields error I3C_ERROR_M2 if there +are no devices active on the bus. This is expected at the bus +initialization stage, where it is not known yet that there are no active +devices on the bus. Add bool suppress_m2 argument to +i3c_master_enec_disec_locked() and update the call site at +i3c_master_bus_init() with the exact corner case to not require +propagating positive Mx error codes. Other call site should not suppress +the error code, for example, if a driver requests to peripheral to +disable events and the transfer is not acknowledged, this is an error +and should not proceed. + +Reviewed-by: Frank Li +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-3-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index fe6f956cc3111..eb05a8a4019e6 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -978,7 +978,8 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master) + EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); + + static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, +- u8 addr, bool enable, u8 evts) ++ u8 addr, bool enable, u8 evts, ++ bool suppress_m2) + { + struct i3c_ccc_events *events; + struct i3c_ccc_cmd_dest dest; +@@ -998,6 +999,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + i3c_ccc_cmd_dest_cleanup(&dest); + ++ if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2) ++ ret = 0; ++ + return ret; + } + +@@ -1018,7 +1022,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, false, evts); ++ return i3c_master_enec_disec_locked(master, addr, false, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + +@@ -1039,7 +1043,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, true, evts); ++ return i3c_master_enec_disec_locked(master, addr, true, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + +@@ -1925,11 +1929,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + +- /* Disable all slave events before starting DAA. */ +- ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, +- I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +- I3C_CCC_EVENT_HJ); +- if (ret && ret != I3C_ERROR_M2) ++ /* ++ * Disable all slave events before starting DAA. When no active device ++ * is on the bus, returns Mx error code M2, this error is ignored. ++ */ ++ ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false, ++ I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | ++ I3C_CCC_EVENT_HJ, true); ++ if (ret) + goto err_bus_cleanup; + + /* +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-6.12/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..040b016b25 --- /dev/null +++ b/queue-6.12/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 1c8f0d51c6798ce55b245db691ed76d9d75d56f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index a7c5108328240..d185b1aba7a47 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -537,14 +537,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + int ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-setting-rss-vsi-hash-for-e830.patch b/queue-6.12/ice-fix-setting-rss-vsi-hash-for-e830.patch new file mode 100644 index 0000000000..26958bf5ee --- /dev/null +++ b/queue-6.12/ice-fix-setting-rss-vsi-hash-for-e830.patch @@ -0,0 +1,56 @@ +From aaee55eb80d873f1c2266ad3c94b13d4ab8afb57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:14 -0700 +Subject: ice: fix setting RSS VSI hash for E830 + +From: Marcin Szycik + +[ Upstream commit b3cda96feb60d91fe88d52b974ff110dcfa91239 ] + +ice_set_rss_hfunc() performs a VSI update, in which it sets hashing +function, leaving other VSI options unchanged. However, ::q_opt_flags is +mistakenly set to the value of another field, instead of its original +value, probably due to a typo. What happens next is hardware-dependent: + +On E810, only the first bit is meaningful (see +ICE_AQ_VSI_Q_OPT_PE_FLTR_EN) and can potentially end up in a different +state than before VSI update. + +On E830, some of the remaining bits are not reserved. Setting them +to some unrelated values can cause the firmware to reject the update +because of invalid settings, or worse - succeed. + +Reproducer: + sudo ethtool -X $PF1 equal 8 + +Output in dmesg: + Failed to configure RSS hash for VSI 6, error -5 + +Fixes: 352e9bf23813 ("ice: enable symmetric-xor RSS for Toeplitz hash function") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Signed-off-by: Marcin Szycik +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-5-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 0fe496b1a2269..a10b458685b79 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -8102,7 +8102,7 @@ int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc) + ctx->info.q_opt_rss |= + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hfunc); + ctx->info.q_opt_tc = vsi->info.q_opt_tc; +- ctx->info.q_opt_flags = vsi->info.q_opt_rss; ++ ctx->info.q_opt_flags = vsi->info.q_opt_flags; + + err = ice_update_vsi(hw, vsi->idx, ctx, NULL); + if (err) { +-- +2.53.0 + diff --git a/queue-6.12/iio-abi-fix-current_trigger-description.patch b/queue-6.12/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..f4b7e7786e --- /dev/null +++ b/queue-6.12/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From 860d3d25881e510bfbbf4bfb3a64512fa3e1360a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index 89943c2d54e8a..2bb8dda6d1778 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1387,7 +1387,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-6.12/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch b/queue-6.12/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch new file mode 100644 index 0000000000..d27122d4c0 --- /dev/null +++ b/queue-6.12/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch @@ -0,0 +1,149 @@ +From 783b34f2e51fe0e00f7109cf7196d02ad56daef2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 13:06:45 +0100 +Subject: ima: Define and use a digest_size field in the ima_algo_desc + structure + +From: Roberto Sassu + +[ Upstream commit a74d7197ebe5b1b8028911d47e78c119d9aaf193 ] + +Add the digest_size field to the ima_algo_desc structure to determine the +digest size from the correct source. + +If the hash algorithm is among allocated PCR banks, take the value from the +TPM bank info (equal to the value from the crypto subsystem if the TPM +algorithm is supported by it; otherwise, not exceding the size of the +digest buffer in the tpm_digest structure, used by IMA). + +If the hash algorithm is SHA1, use the predefined value. Lastly, if the +hash algorithm is the default one but not among the PCR banks, take the +digest size from the crypto subsystem (the default hash algorithm is +checked when parsing the ima_hash= command line option). + +Finally, use the new information to correctly show the template digest in +ima_measurements_show() and ima_ascii_measurements_show(). + +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima.h | 1 + + security/integrity/ima/ima_crypto.c | 6 ++++++ + security/integrity/ima/ima_fs.c | 18 ++++++------------ + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h +index 56bf2f55d9387..6edb38a844e7c 100644 +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -53,6 +53,7 @@ extern atomic_t ima_setxattr_allowed_hash_algorithms; + struct ima_algo_desc { + struct crypto_shash *tfm; + enum hash_algo algo; ++ unsigned int digest_size; + }; + + /* set during initialization */ +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 8ae7821a65c26..c2a859710d20f 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -109,6 +109,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) + + int __init ima_init_crypto(void) + { ++ unsigned int digest_size; + enum hash_algo algo; + long rc; + int i; +@@ -147,7 +148,9 @@ int __init ima_init_crypto(void) + + for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { + algo = ima_tpm_chip->allocated_banks[i].crypto_id; ++ digest_size = ima_tpm_chip->allocated_banks[i].digest_size; + ima_algo_array[i].algo = algo; ++ ima_algo_array[i].digest_size = digest_size; + + /* unknown TPM algorithm */ + if (algo == HASH_ALGO__LAST) +@@ -183,12 +186,15 @@ int __init ima_init_crypto(void) + } + + ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; ++ ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE; + } + + if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && + ima_hash_algo_idx != ima_sha1_idx) { ++ digest_size = hash_digest_size[ima_hash_algo]; + ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; + ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; ++ ima_algo_array[ima_hash_algo_idx].digest_size = digest_size; + } + + return 0; +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 25970867f594e..0aa1a50e877c2 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v) + char *template_name; + u32 pcr, namelen, template_data_len; /* temporary fields */ + bool is_ima_template = false; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v) + ima_putc(m, &pcr, sizeof(e->pcr)); + + /* 2nd: template digest */ +- ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_putc(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3rd: template name size */ + namelen = !ima_canonical_fmt ? strlen(template_name) : +@@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + struct ima_queue_entry *qe = v; + struct ima_template_entry *e; + char *template_name; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + seq_printf(m, "%2d ", e->pcr); + + /* 2nd: template hash */ +- ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_print_digest(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3th: template name */ + seq_printf(m, " %s", template_name); +-- +2.53.0 + diff --git a/queue-6.12/io_uring-cancel-validate-opcode-for-ioring_async_can.patch b/queue-6.12/io_uring-cancel-validate-opcode-for-ioring_async_can.patch new file mode 100644 index 0000000000..8bd58a71d0 --- /dev/null +++ b/queue-6.12/io_uring-cancel-validate-opcode-for-ioring_async_can.patch @@ -0,0 +1,53 @@ +From be1b1a52629bd082e9478410e11d7fbdb9f3d9a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:51:13 +0330 +Subject: io_uring/cancel: validate opcode for IORING_ASYNC_CANCEL_OP + +From: Amir Mohammad Jahangirzad + +[ Upstream commit 85a58309c0d5b5f5a4b65658312ceaf2c34c9bbf ] + +io_async_cancel_prep() reads the opcode selector from sqe->len and +stores it in cancel->opcode, which is an 8-bit field. Since sqe->len +is a 32-bit value, values larger than U8_MAX are implicitly truncated. + +This can cause unintended opcode matches when the truncated value +corresponds to a valid io_uring opcode. For example, submitting a value +such as 0x10b will be truncated to 0x0b (IORING_OP_TIMEOUT), allowing a +cancel request to match operations it did not intend to target. +Validate the opcode value before assigning it to the 8-bit field and +reject values outside the valid io_uring opcode range. + +Signed-off-by: Amir Mohammad Jahangirzad +Link: https://patch.msgid.link/20260331232113.615972-1-a.jahangirzad@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index a6e58a20efdd2..d193bd8570ff2 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -154,9 +154,16 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + cancel->fd = READ_ONCE(sqe->fd); + } + if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ u32 op; ++ + if (cancel->flags & IORING_ASYNC_CANCEL_ANY) + return -EINVAL; +- cancel->opcode = READ_ONCE(sqe->len); ++ ++ op = READ_ONCE(sqe->len); ++ if (op >= IORING_OP_LAST) ++ return -EINVAL; ++ ++ cancel->opcode = op; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch b/queue-6.12/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch new file mode 100644 index 0000000000..0bd948d8b5 --- /dev/null +++ b/queue-6.12/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch @@ -0,0 +1,112 @@ +From 58298e33564e8db39ea012900153c09dae751f8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 15:46:16 +0200 +Subject: io_uring: take page references for NOMMU pbuf_ring mmaps + +From: Greg Kroah-Hartman + +[ Upstream commit d0be8884f56b0b800cd8966e37ce23417cd5044e ] + +Under !CONFIG_MMU, io_uring_get_unmapped_area() returns the kernel +virtual address of the io_mapped_region's backing pages directly; +the user's VMA aliases the kernel allocation. io_uring_mmap() then +just returns 0 -- it takes no page references. + +The CONFIG_MMU path uses vm_insert_pages(), which takes a reference on +each inserted page. Those references are released when the VMA is torn +down (zap_pte_range -> put_page). io_free_region() -> release_pages() +drops the io_uring-side references, but the pages survive until munmap +drops the VMA-side references. + +Under NOMMU there are no VMA-side references. io_unregister_pbuf_ring -> +io_put_bl -> io_free_region -> release_pages drops the only references +and the pages return to the buddy allocator while the user's VMA still +has vm_start pointing into them. The user can then write into whatever +the allocator hands out next. + +Mirror the MMU lifetime: take get_page references in io_uring_mmap() and +release them via vm_ops->close. NOMMU's delete_vma() calls vma_close() +which runs ->close on munmap. + +This also incidentally addresses the duplicate-vm_start case: two mmaps +of SQ_RING and CQ_RING resolve to the same ctx->ring_region pointer. +With page refs taken per mmap, the second mmap takes its own refs and +the pages survive until both mmaps are closed. The nommu rb-tree BUG_ON +on duplicate vm_start is a separate mm/nommu.c concern (it should share +the existing region rather than BUG), but the page lifetime is now +correct. + +Cc: Jens Axboe +Reported-by: Anthropic +Assisted-by: gkh_clanker_t1000 +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026042115-body-attention-d15b@gregkh +[axboe: get rid of region lookup, just iterate pages in vma] +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/memmap.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 45 insertions(+), 1 deletion(-) + +diff --git a/io_uring/memmap.c b/io_uring/memmap.c +index 6d151e46f3d69..077ceacf933cc 100644 +--- a/io_uring/memmap.c ++++ b/io_uring/memmap.c +@@ -318,9 +318,53 @@ unsigned long io_uring_get_unmapped_area(struct file *filp, unsigned long addr, + + #else /* !CONFIG_MMU */ + ++/* ++ * Drop the pages that were initially referenced and added in ++ * io_uring_mmap(). We cannot have had a mremap() as that isn't supported, ++ * hence the vma should be identical to the one we initially referenced and ++ * mapped, and partial unmaps and splitting isn't possible on a file backed ++ * mapping. ++ */ ++static void io_uring_nommu_vm_close(struct vm_area_struct *vma) ++{ ++ unsigned long index; ++ ++ for (index = vma->vm_start; index < vma->vm_end; index += PAGE_SIZE) ++ put_page(virt_to_page((void *) index)); ++} ++ ++static const struct vm_operations_struct io_uring_nommu_vm_ops = { ++ .close = io_uring_nommu_vm_close, ++}; ++ + int io_uring_mmap(struct file *file, struct vm_area_struct *vma) + { +- return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -EINVAL; ++ struct io_ring_ctx *ctx = file->private_data; ++ struct io_mapped_region *region; ++ unsigned long i; ++ ++ if (!is_nommu_shared_mapping(vma->vm_flags)) ++ return -EINVAL; ++ ++ guard(mutex)(&ctx->mmap_lock); ++ region = io_mmap_get_region(ctx, vma->vm_pgoff); ++ if (!region || !io_region_is_set(region)) ++ return -EINVAL; ++ ++ if ((vma->vm_end - vma->vm_start) != ++ (unsigned long) region->nr_pages << PAGE_SHIFT) ++ return -EINVAL; ++ ++ /* ++ * Pin the pages so io_free_region()'s release_pages() does not ++ * drop the last reference while this VMA exists. delete_vma() ++ * in mm/nommu.c calls vma_close() which runs ->close above. ++ */ ++ for (i = 0; i < region->nr_pages; i++) ++ get_page(region->pages[i]); ++ ++ vma->vm_ops = &io_uring_nommu_vm_ops; ++ return 0; + } + + unsigned int io_uring_nommu_mmap_capabilities(struct file *file) +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch b/queue-6.12/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch new file mode 100644 index 0000000000..5d14d0045c --- /dev/null +++ b/queue-6.12/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch @@ -0,0 +1,98 @@ +From 744ab58fbd8481b8097e67b2cd56b9dd741cc566 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:42:50 +0200 +Subject: iommu/amd: Invalidate IRT cache for DMA aliases + +From: Magnus Kalland + +[ Upstream commit 5aac28784dca6819e96e5f93e644cdee59e50f6e ] + +DMA aliasing causes interrupt remapping table entries (IRTEs) to be shared +between multiple device IDs. See commit 3c124435e8dd +("iommu/amd: Support multiple PCI DMA aliases in IRQ Remapping") for more +information on this. However, the AMD IOMMU driver currently invalidates +IRTE cache entries on a per-device basis whenever an IRTE is updated, not +for each alias. + +This approach leaves stale IRTE cache entries when an IRTE is cached under +one DMA alias but later updated and invalidated through a different alias. +In such cases, the original device ID is never invalidated, since it is +programmed via aliasing. + +This incoherency bug has been observed when IRTEs are cached for one +Non-Transparent Bridge (NTB) DMA alias, later updated via another. + +Fix this by invalidating the interrupt remapping table cache for all DMA +aliases when updating an IRTE. + +Co-developed-by: Lars B. Kristiansen +Signed-off-by: Lars B. Kristiansen +Co-developed-by: Jonas Markussen +Signed-off-by: Jonas Markussen +Co-developed-by: Tore H. Larsen +Signed-off-by: Tore H. Larsen +Signed-off-by: Magnus Kalland +Link: https://lore.kernel.org/linux-iommu/9204da81-f821-4034-b8ad-501e43383b56@amd.com/ +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 65d61b9c7382c..5195062ad0d53 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -3095,26 +3095,44 @@ const struct iommu_ops amd_iommu_ops = { + static struct irq_chip amd_ir_chip; + static DEFINE_SPINLOCK(iommu_table_lock); + ++static int iommu_flush_dev_irt(struct pci_dev *unused, u16 devid, void *data) ++{ ++ int ret; ++ struct iommu_cmd cmd; ++ struct amd_iommu *iommu = data; ++ ++ build_inv_irt(&cmd, devid); ++ ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ return ret; ++} ++ + static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid) + { + int ret; + u64 data; + unsigned long flags; +- struct iommu_cmd cmd, cmd2; ++ struct iommu_cmd cmd; ++ struct pci_dev *pdev = NULL; ++ struct iommu_dev_data *dev_data = search_dev_data(iommu, devid); + + if (iommu->irtcachedis_enabled) + return; + +- build_inv_irt(&cmd, devid); ++ if (dev_data && dev_data->dev && dev_is_pci(dev_data->dev)) ++ pdev = to_pci_dev(dev_data->dev); + + raw_spin_lock_irqsave(&iommu->lock, flags); + data = get_cmdsem_val(iommu); +- build_completion_wait(&cmd2, iommu, data); ++ build_completion_wait(&cmd, iommu, data); + +- ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ if (pdev) ++ ret = pci_for_each_dma_alias(pdev, iommu_flush_dev_irt, iommu); ++ else ++ ret = iommu_flush_dev_irt(NULL, devid, iommu); + if (ret) + goto out_err; +- ret = __iommu_queue_command_sync(iommu, &cmd2, false); ++ ++ ret = __iommu_queue_command_sync(iommu, &cmd, false); + if (ret) + goto out_err; + raw_spin_unlock_irqrestore(&iommu->lock, flags); +-- +2.53.0 + diff --git a/queue-6.12/iommu-iova-add-null-check-in-iova_magazine_free.patch b/queue-6.12/iommu-iova-add-null-check-in-iova_magazine_free.patch new file mode 100644 index 0000000000..0a68927d34 --- /dev/null +++ b/queue-6.12/iommu-iova-add-null-check-in-iova_magazine_free.patch @@ -0,0 +1,49 @@ +From 74cddddc03398912aafd4ac90ebefe406f43af41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Feb 2026 08:09:19 +0000 +Subject: iommu/iova: Add NULL check in iova_magazine_free() + +From: lynn + +[ Upstream commit fa8fb60d36375ca3166a60589a624f0d0bc9ddb5 ] + +When iova_domain_init_rcaches() fails to allocate an iova_magazine +during the initialization of per-cpu rcaches, it jumps to out_err and +calls free_iova_rcaches() for cleanup. + +In free_iova_rcaches(), the code iterates through all possible CPUs to +free both cpu_rcache->loaded and cpu_rcache->prev. However, if the +original allocation failed mid-way through the CPU loop, the pointers +for the remaining CPUs remain NULL. + +Since kmem_cache_free() does not explicitly handle NULL pointers like +kfree() does, passing these NULL pointers leads to a kernel paging +request fault. + +Add a NULL check in iova_magazine_free() to safely handle partially +initialized rcaches in error paths. + +Signed-off-by: lynn +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/iova.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c +index 16c6adff3eb7b..3ceeaf931e17f 100644 +--- a/drivers/iommu/iova.c ++++ b/drivers/iommu/iova.c +@@ -610,7 +610,8 @@ static struct iova_magazine *iova_magazine_alloc(gfp_t flags) + + static void iova_magazine_free(struct iova_magazine *mag) + { +- kmem_cache_free(iova_magazine_cache, mag); ++ if (mag) ++ kmem_cache_free(iova_magazine_cache, mag); + } + + static void +-- +2.53.0 + diff --git a/queue-6.12/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch b/queue-6.12/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch new file mode 100644 index 0000000000..efe2142675 --- /dev/null +++ b/queue-6.12/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch @@ -0,0 +1,39 @@ +From 90bd7ac4c7a6518661755e83cd5b4eb096bfcd0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:58 +0800 +Subject: ipmi: ssif_bmc: cancel response timer on remove + +From: Jian Zhang + +[ Upstream commit 7fc3e2546cf3fa9a28a2acc92a512c779a8e5038 ] + +The response timer can stay armed across device teardown. If it fires after +remove, the callback dereferences the SSIF context and the i2c client after +teardown has started. + +Cancel the timer in remove so the callback cannot run after the device is +unregistered. + +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-1-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index c5492e17ae573..dd561b0d251c5 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -858,6 +858,7 @@ static void ssif_bmc_remove(struct i2c_client *client) + { + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + ++ timer_delete_sync(&ssif_bmc->response_timer); + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + } +-- +2.53.0 + diff --git a/queue-6.12/ipv4-validate-ipv4_devconf-attributes-properly.patch b/queue-6.12/ipv4-validate-ipv4_devconf-attributes-properly.patch new file mode 100644 index 0000000000..f367560b8e --- /dev/null +++ b/queue-6.12/ipv4-validate-ipv4_devconf-attributes-properly.patch @@ -0,0 +1,106 @@ +From 9d776aed99e98df101cbab525fcc9dce79eabf9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:26:37 +0100 +Subject: ipv4: validate IPV4_DEVCONF attributes properly + +From: Fernando Fernandez Mancera + +[ Upstream commit fa8fca88714c3a4a74f972ed37328e2f0bbef9fa ] + +As the IPV4_DEVCONF netlink attributes are not being validated, it is +possible to use netlink to set read-only values like mc_forwarding. In +addition, valid ranges are not being validated neither but that is less +relevant as they aren't in sysctl. + +To avoid similar situations in the future, define a NLA policy for +IPV4_DEVCONF attributes which are nested in IFLA_INET_CONF. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260312142637.5704-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 55 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 46fa50576f581..de4abcb40d78b 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -1996,12 +1996,50 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { + [IFLA_INET_CONF] = { .type = NLA_NESTED }, + }; + ++static const struct nla_policy inet_devconf_policy[IPV4_DEVCONF_MAX + 1] = { ++ [IPV4_DEVCONF_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MC_FORWARDING] = { .type = NLA_REJECT }, ++ [IPV4_DEVCONF_PROXY_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SECURE_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SEND_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SHARED_MEDIA] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_RP_FILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BOOTP_RELAY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_LOG_MARTIANS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_TAG] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_ARPFILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MEDIUM_ID] = NLA_POLICY_MIN(NLA_S32, -1), ++ [IPV4_DEVCONF_NOXFRM] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_NOPOLICY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_FORCE_IGMP_VERSION] = NLA_POLICY_RANGE(NLA_U32, 0, 3), ++ [IPV4_DEVCONF_ARP_ANNOUNCE] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_IGNORE] = NLA_POLICY_RANGE(NLA_U32, 0, 8), ++ [IPV4_DEVCONF_PROMOTE_SECONDARIES] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_ACCEPT] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_NOTIFY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_LOCAL] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SRC_VMARK] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_PROXY_ARP_PVLAN] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ROUTE_LOCALNET] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BC_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_GRATUITOUS_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_EVICT_NOCARRIER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++}; ++ + static int inet_validate_link_af(const struct net_device *dev, + const struct nlattr *nla, + struct netlink_ext_ack *extack) + { +- struct nlattr *a, *tb[IFLA_INET_MAX+1]; +- int err, rem; ++ struct nlattr *tb[IFLA_INET_MAX + 1], *nested_tb[IPV4_DEVCONF_MAX + 1]; ++ int err; + + if (dev && !__in_dev_get_rtnl(dev)) + return -EAFNOSUPPORT; +@@ -2012,15 +2050,12 @@ static int inet_validate_link_af(const struct net_device *dev, + return err; + + if (tb[IFLA_INET_CONF]) { +- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { +- int cfgid = nla_type(a); ++ err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX, ++ tb[IFLA_INET_CONF], inet_devconf_policy, ++ extack); + +- if (nla_len(a) < 4) +- return -EINVAL; +- +- if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) +- return -EINVAL; +- } ++ if (err < 0) ++ return err; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-6.12/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..faa3a5257c --- /dev/null +++ b/queue-6.12/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From a0bfb26f26f94728fdd49b1b4c87f7f7c97f22fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index f0a8350eb52eb..d01451926b7ad 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -61,6 +61,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -428,11 +430,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-6.12/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch b/queue-6.12/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch new file mode 100644 index 0000000000..b28ac71692 --- /dev/null +++ b/queue-6.12/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch @@ -0,0 +1,150 @@ +From be6cabb03c9f462890d8c80ddae3628a631d9d1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:36:49 +0200 +Subject: ipv6: move IFA_F_PERMANENT percpu allocation in process scope + +From: Paolo Abeni + +[ Upstream commit 8e6405f8218b3f412d36b772318e94d589513eba ] + +Observed at boot time: + + CPU: 43 UID: 0 PID: 3595 Comm: (t-daemon) Not tainted 6.12.0 #1 + Call Trace: + + dump_stack_lvl+0x4e/0x70 + pcpu_alloc_noprof.cold+0x1f/0x4b + fib_nh_common_init+0x4c/0x110 + fib6_nh_init+0x387/0x740 + ip6_route_info_create+0x46d/0x640 + addrconf_f6i_alloc+0x13b/0x180 + addrconf_permanent_addr+0xd0/0x220 + addrconf_notify+0x93/0x540 + notifier_call_chain+0x5a/0xd0 + __dev_notify_flags+0x5c/0xf0 + dev_change_flags+0x54/0x70 + do_setlink+0x36c/0xce0 + rtnl_setlink+0x11f/0x1d0 + rtnetlink_rcv_msg+0x142/0x3f0 + netlink_rcv_skb+0x50/0x100 + netlink_unicast+0x242/0x390 + netlink_sendmsg+0x21b/0x470 + __sys_sendto+0x1dc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x7d/0x160 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + RIP: 0033:0x7f5c3852f127 + Code: 0c 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 80 3d 85 ef 0c 00 00 41 89 ca 74 10 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 71 c3 55 48 83 ec 30 44 89 4c 24 2c 4c 89 44 + RSP: 002b:00007ffe86caf4c8 EFLAGS: 00000202 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 0000556c5cd93210 RCX: 00007f5c3852f127 + RDX: 0000000000000020 RSI: 0000556c5cd938b0 RDI: 0000000000000003 + RBP: 00007ffe86caf5a0 R08: 00007ffe86caf4e0 R09: 0000000000000080 + R10: 0000000000000000 R11: 0000000000000202 R12: 0000556c5cd932d0 + R13: 00000000021d05d1 R14: 00000000021d05d1 R15: 0000000000000001 + +IFA_F_PERMANENT addresses require the allocation of a bunch of percpu +pointers, currently in atomic scope. + +Similar to commit 51454ea42c1a ("ipv6: fix locking issues with loops +over idev->addr_list"), move fixup_permanent_addr() outside the +&idev->lock scope, and do the allocations with GFP_KERNEL. With such +change fixup_permanent_addr() is invoked with the BH enabled, and the +ifp lock acquired there needs the BH variant. + +Note that we don't need to acquire a reference to the permanent +addresses before releasing the mentioned write lock, because +addrconf_permanent_addr() runs under RTNL and ifa removal always happens +under RTNL, too. + +Also the PERMANENT flag is constant in the relevant scope, as it can be +cleared only by inet6_addr_modify() under the RTNL lock. + +Reviewed-by: David Ahern +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/46a7a030727e236af2dc7752994cd4f04f4a91d2.1775658924.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index e104ec8efe1c0..41b0674605a05 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3602,15 +3602,15 @@ static int fixup_permanent_addr(struct net *net, + struct fib6_info *f6i, *prev; + + f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false, +- GFP_ATOMIC, NULL); ++ GFP_KERNEL, NULL); + if (IS_ERR(f6i)) + return PTR_ERR(f6i); + + /* ifp->rt can be accessed outside of rtnl */ +- spin_lock(&ifp->lock); ++ spin_lock_bh(&ifp->lock); + prev = ifp->rt; + ifp->rt = f6i; +- spin_unlock(&ifp->lock); ++ spin_unlock_bh(&ifp->lock); + + fib6_info_release(prev); + } +@@ -3618,7 +3618,7 @@ static int fixup_permanent_addr(struct net *net, + if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, + ifp->rt_priority, idev->dev, 0, 0, +- GFP_ATOMIC); ++ GFP_KERNEL); + } + + if (ifp->state == INET6_IFADDR_STATE_PREDAD) +@@ -3629,29 +3629,36 @@ static int fixup_permanent_addr(struct net *net, + + static void addrconf_permanent_addr(struct net *net, struct net_device *dev) + { +- struct inet6_ifaddr *ifp, *tmp; ++ struct inet6_ifaddr *ifp; ++ LIST_HEAD(tmp_addr_list); + struct inet6_dev *idev; + ++ /* Mutual exclusion with other if_list_aux users. */ ++ ASSERT_RTNL(); ++ + idev = __in6_dev_get(dev); + if (!idev) + return; + + write_lock_bh(&idev->lock); ++ list_for_each_entry(ifp, &idev->addr_list, if_list) { ++ if (ifp->flags & IFA_F_PERMANENT) ++ list_add_tail(&ifp->if_list_aux, &tmp_addr_list); ++ } ++ write_unlock_bh(&idev->lock); + +- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { +- if ((ifp->flags & IFA_F_PERMANENT) && +- fixup_permanent_addr(net, idev, ifp) < 0) { +- write_unlock_bh(&idev->lock); ++ while (!list_empty(&tmp_addr_list)) { ++ ifp = list_first_entry(&tmp_addr_list, ++ struct inet6_ifaddr, if_list_aux); ++ list_del(&ifp->if_list_aux); + ++ if (fixup_permanent_addr(net, idev, ifp) < 0) { + net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n", + idev->dev->name, &ifp->addr); + in6_ifa_hold(ifp); + ipv6_del_addr(ifp); +- write_lock_bh(&idev->lock); + } + } +- +- write_unlock_bh(&idev->lock); + } + + static int addrconf_notify(struct notifier_block *this, unsigned long event, +-- +2.53.0 + diff --git a/queue-6.12/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch b/queue-6.12/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch new file mode 100644 index 0000000000..a9ca3c1cc8 --- /dev/null +++ b/queue-6.12/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch @@ -0,0 +1,68 @@ +From c422ab25bee4d0f47ace2e138b87468a33308bb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:32:29 +0800 +Subject: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 91840be8f710370607f949a627e070896faeddb8 ] + +On PREEMPT_RT, non-HARD irq_work runs in per-CPU kthreads via +run_irq_workd(), so irq_work_sync() uses rcuwait() to wait for BUSY==0. + +After irq_work_single() clears BUSY via atomic_cmpxchg(), it still +dereferences @work for irq_work_is_hard() and rcuwait_wake_up(). + +An irq_work_sync() caller on another CPU that enters after BUSY is cleared +can observe BUSY==0 immediately, return, and free the work before those +accesses complete — causing a use-after-free. + +Fix this by wrapping run_irq_workd() in guard(rcu)() so that the entire +irq_work_single() execution is within an RCU read-side critical +section. Then add synchronize_rcu() in irq_work_sync() after +rcuwait_wait_event() to ensure the caller waits for the RCU grace period +before returning, preventing premature frees. + +Fixes: 810979682ccc ("irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.") +Suggested-by: Sebastian Andrzej Siewior +Suggested-by: Steven Rostedt +Signed-off-by: Jiayuan Chen +Signed-off-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260330073234.303732-1-jiayuan.chen@linux.dev +Signed-off-by: Sasha Levin +--- + kernel/irq_work.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 2f4fb336dda17..188721af8eb31 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -292,6 +292,12 @@ void irq_work_sync(struct irq_work *work) + !arch_irq_work_has_interrupt()) { + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), + TASK_UNINTERRUPTIBLE); ++ /* ++ * Ensure irq_work_single() does not access @work ++ * after removing IRQ_WORK_BUSY. It is always ++ * accessed within a RCU-read section. ++ */ ++ synchronize_rcu(); + return; + } + +@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); + + static void run_irq_workd(unsigned int cpu) + { ++ guard(rcu)(); + irq_work_run_list(this_cpu_ptr(&lazy_list)); + } + +-- +2.53.0 + diff --git a/queue-6.12/irqchip-ath79-cpu-remove-unused-function.patch b/queue-6.12/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..d270766438 --- /dev/null +++ b/queue-6.12/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From 03cc7f1789be050801d710a65c1f866c9498edae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-6.12/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-6.12/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..d3fdc9f7d2 --- /dev/null +++ b/queue-6.12/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From c9e0eeb1f0a0d2260ac29963acff182d0b6a5e1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index cdfa699cd7c8f..5fa6dd3a6ba28 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-6.12/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-6.12/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..d0b7807e2e --- /dev/null +++ b/queue-6.12/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From 4fb93b1beedf7f01c6cb5da003e3b9df9911641f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 93db6eec44655..8187aaceb7530 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4285,3 +4285,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index ecb8e05b8b848..de0738858d4e4 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-6.12/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-6.12/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..ee69709277 --- /dev/null +++ b/queue-6.12/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From 158a432aa54597bb14d1a7508f69932c1cd75582 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 98f9a432c3366..e16c44246bac4 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -378,11 +378,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-6.12/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-6.12/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..622f6d936a --- /dev/null +++ b/queue-6.12/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 77f4a16ca22ff37b2ffbfe0b33ad800072e3c857 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index df575a873ec6d..8ff496e937442 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -188,6 +188,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -297,7 +298,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index 7840a03e5bcb7..a5a5bc0a266d9 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-6.12/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-6.12/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..c2caa6eddb --- /dev/null +++ b/queue-6.12/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From 0eeb848a3a14edfc1e17f2131a161cddb692bc97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index a9cfa6307252d..03284de98e666 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 8b8994e48cd08..09e0ef6aeccef 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 8ec43f53f6865..18569f1eaabdb 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-6.12/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-6.12/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..62094ba9b0 --- /dev/null +++ b/queue-6.12/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From ece4e7ba629b1114eea975810bfb2f5c4d5b94d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 03284de98e666..5b05f44e39bfb 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2179,8 +2179,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2195,12 +2193,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2224,8 +2220,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2277,8 +2272,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2289,6 +2282,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2301,9 +2295,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-6.12/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch b/queue-6.12/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch new file mode 100644 index 0000000000..1f7995f2e6 --- /dev/null +++ b/queue-6.12/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch @@ -0,0 +1,103 @@ +From 065ac3ee5e4cf5450fc1347bf357bf548fa1c291 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist() + +From: Jianpeng Chang + +[ Upstream commit 307abfac04a254c09c5705d816b33354acee97a0 ] + +When kprobe_add_area_blacklist() iterates through a section like +.kprobes.text, the start address may not correspond to a named symbol. +On ARM64 with CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y (introduced by +commit baaf553d3bc3 ("arm64: Implement +HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")), the compiler flag +-fpatchable-function-entry=4,2 inserts 2 NOPs before each function entry +point for ftrace call_ops. These pre-function NOPs sit at the section base +address, before the first named function symbol. The compiler emits a $x +mapping symbol at offset 0x00 to mark the start of code, but +find_kallsyms_symbol() ignores mapping symbols. + +Without CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS (e.g. defconfig), no +pre-function NOPs are inserted, the first function starts at offset +0x00, and the bug does not trigger. + +This only affects modules that have a .kprobes.text section (i.e. those +using the __kprobes annotation). Modules using NOKPROBE_SYMBOL() instead +(like kretprobe_example.ko) blacklist exact function addresses via the +_kprobe_blacklist section and are not affected. + +For kprobe_example.ko on ARM64 with -fpatchable-function-entry=4,2, +the .kprobes.text section layout is: + + offset 0x00: $x + 2 NOPs (mapping symbol + ftrace preamble) + offset 0x08: handler_post (64 bytes) + offset 0x50: handler_pre (68 bytes) + +kprobe_add_area_blacklist() starts iterating from the section base +address (offset 0x00), which only has the $x mapping symbol. +kprobe_add_ksym_blacklist() then calls kallsyms_lookup_size_offset() +for this address, which goes through: + + kallsyms_lookup_size_offset() + -> module_address_lookup() + -> find_kallsyms_symbol() + +find_kallsyms_symbol() scans all module symbols to find the closest +preceding symbol. + +Since no named text symbol exists at offset 0x00, +find_kallsyms_symbol() picks __UNIQUE_ID_vermagic (a .modinfo symbol +whose address is in the temporary image) as the "best" match. The +computed "size" = next_text_symbol - modinfo_symbol spans across +these two unrelated memory regions, creating a blacklist entry with +a bogus range of tens of terabytes. + +Whether this causes a visible failure depends on address randomization, +here is what happens on Raspberry Pi 4/5: + + - On RPi5, the bogus size was ~35 TB. start + size stayed within + 64-bit range, so the blacklist entry covered the entire kernel + text. register_kprobe() in the module's own init function failed + with -EINVAL. + + - On RPi4, the bogus size was ~75 TB. start + size overflowed + 64 bits and wrapped to a small address near zero. The range + check (addr >= start && addr < end) then failed because end + wrapped around, so the bogus entry was accidentally harmless + and kprobes worked by luck. + +The same bug exists on both machines, but randomization determines whether +the integer overflow masks it or not. + +Fix this by adding notrace to the __kprobes macro. Functions in +.kprobes.text are kprobe infrastructure handlers that should never be +traced by ftrace. With notrace, the compiler stops inserting them and the +non-symbol gap at the section start disappears entirely. + +Link: https://lore.kernel.org/all/20260506012706.2785785-1-jianpeng.chang.cn@windriver.com/ + +Fixes: baaf553d3bc3 ("arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS") +Signed-off-by: Jianpeng Chang +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/asm-generic/kprobes.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/asm-generic/kprobes.h b/include/asm-generic/kprobes.h +index 060eab094e5a2..5290a2b2e15a0 100644 +--- a/include/asm-generic/kprobes.h ++++ b/include/asm-generic/kprobes.h +@@ -14,7 +14,7 @@ static unsigned long __used \ + _kbl_addr_##fname = (unsigned long)fname; + # define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) + /* Use this to forbid a kprobes attach on very low level functions */ +-# define __kprobes __section(".kprobes.text") ++# define __kprobes notrace __section(".kprobes.text") + # define nokprobe_inline __always_inline + #else + # define NOKPROBE_SYMBOL(fname) +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-6.12/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..65153fd382 --- /dev/null +++ b/queue-6.12/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 73403b3a7d2548273b98a511d3892aa5e0772c68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index b72983ae9aca9..3e6831e1c3805 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3064,7 +3064,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -3078,7 +3078,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-6.12/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..91a70f6760 --- /dev/null +++ b/queue-6.12/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From 82bfce62521f0eb24506abd065af2a6269b063af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 3e6831e1c3805..a2c53b61ee187 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -7433,7 +7433,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-6.12/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-6.12/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..2d0f1f3236 --- /dev/null +++ b/queue-6.12/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From af6716b4e1dda716ff913c1f8bb7dfb0d9d4c4f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 34d7242d526dc..8a30ad48f3c07 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-6.12/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-6.12/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..4c3e6a16a1 --- /dev/null +++ b/queue-6.12/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 1e8be7d4525741cc113adf2d96f859b7cdc13df1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 8a30ad48f3c07..e22cbee60ab25 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-6.12/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-6.12/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..00ac933096 --- /dev/null +++ b/queue-6.12/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From 24a6d3613b2793b25b53aea4304a7887bc787f80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 330cd46194659..759563ca185cd 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-6.12/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-6.12/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..e40b3a63a9 --- /dev/null +++ b/queue-6.12/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 26b87e283222ea653994c74efd043d1475ea1258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 72e95663b62ff..c257cc415c478 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -18,6 +18,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -70,9 +77,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -96,16 +102,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-6.12/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-6.12/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..9b6424baac --- /dev/null +++ b/queue-6.12/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From 6df07d8330bf7087973d8e86d29d5b5ed3aaf829 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index f71ed0f538258..83e7dbd53b5f3 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3919,6 +3919,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-6.12/media-au0828-fix-green-screen-in-analog.patch b/queue-6.12/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..dbae0752d9 --- /dev/null +++ b/queue-6.12/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From 5763c8c9283e788aa2e5384e6219a6b796196b5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index 2ec49ea479d56..2d17bb351fc76 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1673,6 +1673,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1766,8 +1787,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-6.12/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-6.12/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..2140b01158 --- /dev/null +++ b/queue-6.12/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From 4a3dbea8aba0981d7c8133c1102572abad0d1727 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index 611c9823be857..0077320746e5d 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -803,9 +803,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-6.12/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-6.12/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..7ec795c911 --- /dev/null +++ b/queue-6.12/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 7369ce3c0ae19bdf266cdbbebb1afff89920422f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index a90a9e5705a03..bd83258d3fdd3 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-6.12/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch b/queue-6.12/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch new file mode 100644 index 0000000000..0c32d56468 --- /dev/null +++ b/queue-6.12/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch @@ -0,0 +1,111 @@ +From 392362da938fbd0899bb3e426c01b8e62d1a27c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 16:50:24 +0100 +Subject: media: dw100: Fix kernel oops with PREEMPT_RT enabled + +From: Stefan Klug + +[ Upstream commit 557ec8cc29ade6c72ea768e59389db08cb7742c9 ] + +On kernels with PREEMPT_RT enabled, a "BUG: scheduling while atomic" +kernel oops occurs inside dw100_irq_handler -> vb2_buffer_done. This is +because vb2_buffer_done takes a spinlock which is not allowed within +interrupt context on PREEMPT_RT. + +The first attempt to fix this was to just drop the IRQF_ONESHOT so that +the interrupt is handled threaded on PREEMPT_RT systems. This introduced +a new issue. The dw100 has an internal timeout counter that is gated by +the DW100_BUS_CTRL_AXI_MASTER_ENABLE bit. Depending on the time it takes +for the threaded handler to run and the geometry of the data being +processed it is possible to reach the timeout resulting in +DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT being set and "dw100 +32e30000.dwe: Interrupt error: 0x1" errors in dmesg. + +To properly fix that, split the interrupt into two halves, reset the +DW100_BUS_CTRL_AXI_MASTER_ENABLE bit in the hard interrupt handler and +do the v4l2 buffer handling in the threaded half. The IRQF_ONESHOT can +still be dropped as the interrupt gets disabled in the hard handler and +will only be reenabled on the next dw100_device_run which will not be +called before the current job has finished. + +Signed-off-by: Stefan Klug +Reviewed-by: Xavier Roumegue +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260304-sklug-v6-16-topic-dw100-v3-1-dev-v5-3-1a7e1f721b50@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/nxp/dw100/dw100.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c +index 0024d6175ad9a..9017a312265ab 100644 +--- a/drivers/media/platform/nxp/dw100/dw100.c ++++ b/drivers/media/platform/nxp/dw100/dw100.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,7 @@ struct dw100_device { + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; ++ bool frame_failed; + }; + + struct dw100_q_data { +@@ -1396,7 +1398,8 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + { + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; +- bool with_error = true; ++ ++ dw_dev->frame_failed = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; +@@ -1404,7 +1407,7 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); +- with_error = false; ++ dw_dev->frame_failed = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } +@@ -1417,7 +1420,14 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + +- dw100_job_finish(dw_dev, with_error); ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dw100_irq_thread_fn(int irq, void *dev_id) ++{ ++ struct dw100_device *dw_dev = dev_id; ++ ++ dw100_job_finish(dw_dev, dw_dev->frame_failed); + + return IRQ_HANDLED; + } +@@ -1565,8 +1575,9 @@ static int dw100_probe(struct platform_device *pdev) + + pm_runtime_put_sync(&pdev->dev); + +- ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, +- dev_name(&pdev->dev), dw_dev); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, dw100_irq_handler, ++ dw100_irq_thread_fn, 0, ++ dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_pm; +-- +2.53.0 + diff --git a/queue-6.12/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-6.12/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..6716556caa --- /dev/null +++ b/queue-6.12/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From c8cc7c1a49f24427e1675205c1f71393b5213994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index a51cbcf429e13..37c0c6e860242 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2757,10 +2757,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-6.12/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch b/queue-6.12/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch new file mode 100644 index 0000000000..89e1005525 --- /dev/null +++ b/queue-6.12/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch @@ -0,0 +1,55 @@ +From da794f2a6115f700181c046538fb129297f0d7a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:32 -0500 +Subject: media: em28xx: remove tuner type from Hauppauge DVB DualHD + +From: Bradford Love + +[ Upstream commit a5dcbff7d50a89bf0376e7f2fb1ba3163a6dac0a ] + +This reverts a patch which was perhaps inadvertently added. + +This was changed during the 5.15-rc4 merge. The faulty commit appears +lost in the pull request somehow, I cannot find it to check the +explanation. + +commit c52e7b855b33 ("Merge tag 'v5.15-rc4' into media_tree") + +There was nothing wrong with this device and no reason to moodify the +board profile. The DVB capabilities are added via dvb_module_probe. +Additionally, the device contains *zero* analog inputs, so I'm not +sure why one was added. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 37c0c6e860242..88adc010560a1 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2522,17 +2522,12 @@ const struct em28xx_board em28xx_boards[] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, +- .tuner_type = TUNER_SI2157, ++ .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .has_dual_ts = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, +- .input = { { +- .type = EM28XX_VMUX_COMPOSITE, +- .vmux = TVP5150_COMPOSITE1, +- .amux = EM28XX_AMUX_LINE_IN, +- } }, + }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. +-- +2.53.0 + diff --git a/queue-6.12/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch b/queue-6.12/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch new file mode 100644 index 0000000000..6c0fa72db4 --- /dev/null +++ b/queue-6.12/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch @@ -0,0 +1,47 @@ +From 8c02598750a89df50ffcb37b5d9a31e3712efd21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:18:15 +0800 +Subject: media: i2c: ar0521: Check return value of devm_gpiod_get_optional() + in ar0521_probe() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chen Ni + +[ Upstream commit 46c2891cf12c767de031a248cbb1f96d203bd3f6 ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Acked-by: Krzysztof Hałasa +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ar0521.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c +index 24873149096c1..f2cf574d93d8c 100644 +--- a/drivers/media/i2c/ar0521.c ++++ b/drivers/media/i2c/ar0521.c +@@ -1095,6 +1095,9 @@ static int ar0521_probe(struct i2c_client *client) + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(sensor->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), ++ "failed to get reset gpio\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + +-- +2.53.0 + diff --git a/queue-6.12/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch b/queue-6.12/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch new file mode 100644 index 0000000000..0eb30c38f7 --- /dev/null +++ b/queue-6.12/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch @@ -0,0 +1,85 @@ +From 24a8822422d3dde25314ff4bb7215580b2cf4788 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 02:31:54 +0000 +Subject: media: i2c: imx258: add missing mutex protection for format code + access + +From: Ziyi Guo + +[ Upstream commit c3109ecc3bb76aab9ef65f2e795a97a764a0b4a3 ] + +imx258_open(), imx258_enum_mbus_code(), and imx258_enum_frame_size() +call imx258_get_format_code() without holding imx258->mutex. However, +imx258_get_format_code() has lockdep_assert_held(&imx258->mutex) +indicating that callers must hold this lock. + +All other callers of imx258_get_format_code() properly acquire the mutex: +- imx258_set_pad_format() acquires mutex at imx258.c:918 +- imx258_get_pad_format() acquires mutex at imx258.c:896 + +The mutex is needed to protect access to imx258->vflip->val and +imx258->hflip->val which are used to calculate the bayer format code. + +Add mutex_lock()/mutex_unlock() around the imx258_get_format_code() +calls in the affected functions to fix the missing lock protection. + +Signed-off-by: Ziyi Guo +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/imx258.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index 9e30fce1f2236..2114a15f83c7f 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -706,12 +706,16 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) + v4l2_subdev_state_get_format(fh->state, 0); + struct v4l2_rect *try_crop; + ++ mutex_lock(&imx258->mutex); ++ + /* Initialize try_fmt */ + try_fmt->width = supported_modes[0].width; + try_fmt->height = supported_modes[0].height; + try_fmt->code = imx258_get_format_code(imx258); + try_fmt->field = V4L2_FIELD_NONE; + ++ mutex_unlock(&imx258->mutex); ++ + /* Initialize try_crop */ + try_crop = v4l2_subdev_state_get_crop(fh->state, 0); + try_crop->left = IMX258_PIXEL_ARRAY_LEFT; +@@ -837,7 +841,9 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd, + if (code->index > 0) + return -EINVAL; + ++ mutex_lock(&imx258->mutex); + code->code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); + + return 0; + } +@@ -847,10 +853,16 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_size_enum *fse) + { + struct imx258 *imx258 = to_imx258(sd); ++ u32 code; ++ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + +- if (fse->code != imx258_get_format_code(imx258)) ++ mutex_lock(&imx258->mutex); ++ code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); ++ ++ if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; +-- +2.53.0 + diff --git a/queue-6.12/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-6.12/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..4dfe33020b --- /dev/null +++ b/queue-6.12/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From 26d5b0f16c4d157716cac4c22c4a4c450f523948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index d8735c246e528..d9a2836c465ee 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1185,6 +1185,10 @@ static int mt9p031_probe(struct i2c_client *client) + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/media-ipu-bridge-add-ov5675-sensor-config.patch b/queue-6.12/media-ipu-bridge-add-ov5675-sensor-config.patch new file mode 100644 index 0000000000..2c32d6d983 --- /dev/null +++ b/queue-6.12/media-ipu-bridge-add-ov5675-sensor-config.patch @@ -0,0 +1,42 @@ +From 824f7cc4c2782198628ccdcb15bef9a8e608d31f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 10:45:45 +0100 +Subject: media: ipu-bridge: Add OV5675 sensor config + +From: Leif Skunberg + +[ Upstream commit d6576b85d3fe75238e67d3e311222e7f69730b09 ] + +Add the Omnivision OV5675 (ACPI HID OVTI5675) to the +ipu_supported_sensors[] table with a link frequency of 450 MHz. + +This sensor is found in the Lenovo ThinkPad X1 Fold 16 Gen 1 behind +an Intel Vision Sensing Controller (IVSC). Without this entry the IPU +bridge does not create the software-node fwnode graph for the sensor, +preventing the camera from being enumerated. + +Signed-off-by: Leif Skunberg +Reviewed-by: Hans de Goede +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/pci/intel/ipu-bridge.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index 4e921c7516293..3c64df4961218 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -83,6 +83,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), + /* Omnivision OV2680 */ + IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), ++ /* Omnivision OV5675 */ ++ IPU_SENSOR_CONFIG("OVTI5675", 1, 450000000), + /* Omnivision OV8856 */ + IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), + }; +-- +2.53.0 + diff --git a/queue-6.12/media-pulse8-cec-handle-partial-deinit.patch b/queue-6.12/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..035c16a054 --- /dev/null +++ b/queue-6.12/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From ee45e1eb6857541d7f0b20f066a21f0f5e884f16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 171366fe35443..90b8a968fed77 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-6.12/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-6.12/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..5ece7c4f88 --- /dev/null +++ b/queue-6.12/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From be84ac78ccf123ba2932dc06ea24d7ca32451cc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +index 9c2d4c91bfadb..90a172a58923c 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +@@ -172,7 +172,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/media-renesas-vsp1-initialize-format-on-all-pads.patch b/queue-6.12/media-renesas-vsp1-initialize-format-on-all-pads.patch new file mode 100644 index 0000000000..b0bdf1322a --- /dev/null +++ b/queue-6.12/media-renesas-vsp1-initialize-format-on-all-pads.patch @@ -0,0 +1,38 @@ +From 876279c19e42d3a9a7f8c3f69e14bd5e70d788b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:07 +0200 +Subject: media: renesas: vsp1: Initialize format on all pads + +From: Laurent Pinchart + +[ Upstream commit 133ac42af0a1b389e8b7b3dc7c1cc8c30ff162b6 ] + +The state initialization function vsp1_entity_init_state() incorrectly +leaves the last entity pad out when initializing formats due to an off +by one error. Fix it. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-14-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_entity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +index 8b8945bd8f108..a4d6d6eaa7cb9 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +@@ -361,7 +361,7 @@ static int vsp1_entity_init_state(struct v4l2_subdev *subdev, + unsigned int pad; + + /* Initialize all pad formats with default values. */ +- for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { ++ for (pad = 0; pad < subdev->entity.num_pads; ++pad) { + struct v4l2_subdev_format format = { + .pad = pad, + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY +-- +2.53.0 + diff --git a/queue-6.12/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-6.12/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..a9c35f6327 --- /dev/null +++ b/queue-6.12/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From 142bef02f12c4d59e2e15909ec1a9984b590893b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + .../media/platform/renesas/vsp1/vsp1_rwpf.c | 28 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 9d38203e73d00..e8eb9411bce3e 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -171,6 +171,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *format; +@@ -199,18 +201,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-6.12/media-saa7164-fix-rev2-firmware-filename.patch b/queue-6.12/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..bd97f82358 --- /dev/null +++ b/queue-6.12/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 0757bbe37bacef8a0d66f9ea31b64c9eaae75f91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index cc9f384f7f1e9..341cef62452f1 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-6.12/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-6.12/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..7dedf7b6e8 --- /dev/null +++ b/queue-6.12/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From 902d7be79e5edfb8e5b742fb4b5fab363686a679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index a085cefeebdd1..a0fa457e7c5b3 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-6.12/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-6.12/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..b195a3e2a9 --- /dev/null +++ b/queue-6.12/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From 4f436341eec2b06da1cd9366bc8d8460560d867e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index d6b6b8bc7d4e0..a085cefeebdd1 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -572,8 +572,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-6.12/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-6.12/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..5d32ae1bbc --- /dev/null +++ b/queue-6.12/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From e97df694ccc4952da5b16f4bede70b8c1a7dda1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index ff3331af94068..3f87f31cf2672 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -447,9 +447,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-6.12/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch b/queue-6.12/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch new file mode 100644 index 0000000000..5251f7436d --- /dev/null +++ b/queue-6.12/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch @@ -0,0 +1,62 @@ +From 3d5f33a2e76f53e0a4d9ea67b71694d2d5a4c2b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 16:35:00 -0800 +Subject: memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5 + +From: Florian Fainelli + +[ Upstream commit a969a0835152984a0f556434eafdee0b84213670 ] + +The same limitations that apply to LPDDR4 also apply to LPDDR5. Expand +the check and rename accordingly. + +Signed-off-by: Florian Fainelli +Link: https://patch.msgid.link/20260122003501.1191059-1-florian.fainelli@broadcom.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/brcmstb_memc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c +index 4f17a93aa0284..a8d295b14b975 100644 +--- a/drivers/memory/brcmstb_memc.c ++++ b/drivers/memory/brcmstb_memc.c +@@ -14,6 +14,7 @@ + + #define REG_MEMC_CNTRLR_CONFIG 0x00 + #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 ++#define CNTRLR_CONFIG_LPDDR5_SHIFT 6 + #define CNTRLR_CONFIG_MASK 0xf + #define REG_MEMC_SRPD_CFG_21 0x20 + #define REG_MEMC_SRPD_CFG_20 0x34 +@@ -34,14 +35,15 @@ struct brcmstb_memc { + u32 srpd_offset; + }; + +-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc) ++static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc) + { + void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG; + u32 reg; + + reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK; + +- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT; ++ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT || ++ reg == CNTRLR_CONFIG_LPDDR5_SHIFT; + } + + static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc, +@@ -95,7 +97,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr, + * dynamic tuning process will also get affected by the inactivity + * timeout, thus making it non functional. + */ +- if (brcmstb_memc_uses_lpddr4(memc)) ++ if (brcmstb_memc_uses_lpddr45(memc)) + return -EOPNOTSUPP; + + ret = kstrtouint(buf, 10, &val); +-- +2.53.0 + diff --git a/queue-6.12/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch b/queue-6.12/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch new file mode 100644 index 0000000000..3b18ee5ed3 --- /dev/null +++ b/queue-6.12/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch @@ -0,0 +1,52 @@ +From 1f1a6a45f641a1c87669843e843a8fd4c6394b93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 12:03:37 +0200 +Subject: mfd: intel-lpss: Add Intel Nova Lake-H PCI IDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Saranya Gopal + +[ Upstream commit d6e0ef44688249009dfa24f1cd619d41637de060 ] + +Add Intel Nova Lake-H LPSS PCI IDs. + +Signed-off-by: Saranya Gopal +Co-developed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260313100337.3471-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/intel-lpss-pci.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c +index a7feb82c28e3f..6035fbfd42721 100644 +--- a/drivers/mfd/intel-lpss-pci.c ++++ b/drivers/mfd/intel-lpss-pci.c +@@ -633,6 +633,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0xa879), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87a), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87b), (kernel_ulong_t)&ehl_i2c_info }, ++ /* NVL-H */ ++ { PCI_VDEVICE(INTEL, 0xd325), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd326), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd327), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd330), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd347), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd350), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd351), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd352), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd378), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd379), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37a), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37b), (kernel_ulong_t)&ehl_i2c_info }, + /* PTL-H */ + { PCI_VDEVICE(INTEL, 0xe325), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe326), (kernel_ulong_t)&bxt_uart_info }, +-- +2.53.0 + diff --git a/queue-6.12/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch b/queue-6.12/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch new file mode 100644 index 0000000000..c2c7ab7b1f --- /dev/null +++ b/queue-6.12/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch @@ -0,0 +1,64 @@ +From 18f1f33fadfc4748be8e30585563ff5c1f4e7ad8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:35:52 +0800 +Subject: mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus + width + +From: Luke Wang + +[ Upstream commit e98f926e5a2d8023a74ec2ba7a973b5d76610f4e ] + +UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers +that lack relevant capability registers rely on paring properties provided +by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() +has been introduced to validate such configuration violations, let's also +add checks for UHS/DDR/HS200 modes. + +This fixes an issue where, if the HS200/HS400 property is set while only +a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually +performing the mode switch. Consequently, mmc_select_timing() proceeds +without falling back to mmc_select_hs(), leaving the eMMC device operating +in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). + +Signed-off-by: Luke Wang +[Shawn: reword the commit msg and rework the code] +Signed-off-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/host.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 48bda70145ee6..75146854a1169 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -621,12 +621,24 @@ static int mmc_validate_host_caps(struct mmc_host *host) + return -EINVAL; + } + ++ /* UHS/DDR/HS200 modes require at least 4-bit bus */ ++ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) && ++ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) { ++ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n"); ++ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR); ++ caps2 &= ~MMC_CAP2_HS200; ++ } ++ ++ /* HS400 and HS400ES modes require 8-bit bus */ + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); +- host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; ++ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400); + } + ++ host->caps = caps; ++ host->caps2 = caps2; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/module-override-eexist-module-return.patch b/queue-6.12/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..223558aa8a --- /dev/null +++ b/queue-6.12/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From cb53982ac2e54d1a1874693c497cb81ae767173b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index ad58c44fb74fd..6c4a0d111ecd1 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -2551,6 +2551,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-6.12/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-6.12/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..5e4ec897c6 --- /dev/null +++ b/queue-6.12/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From a5d11703acf61f0c0718d224931209a3bf4e0bb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 8a9a85af17a72..1c920e962319d 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7289,7 +7289,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-6.12/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..101c967812 --- /dev/null +++ b/queue-6.12/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From 001ce4be941f0307900b6c6ea41b22bb0441902f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 8fee13bd056ad..2ce8191ad5007 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1444,6 +1445,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1457,7 +1459,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1497,6 +1498,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1507,6 +1509,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1541,6 +1544,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1549,6 +1553,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1558,6 +1563,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1887,6 +1893,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-6.12/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..10c1638811 --- /dev/null +++ b/queue-6.12/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From e0d26fba14326a072773f84587fc9f318a3cc51a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 47072fbabcaee..8fee13bd056ad 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1493,6 +1493,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-6.12/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..17cf04eeee --- /dev/null +++ b/queue-6.12/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From 13eab5d5aa7e32cb961addca2e48194d24977ffb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 92833eefc04b4..47072fbabcaee 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -121,6 +121,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1442,10 +1444,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1499,6 +1501,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1549,6 +1552,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1877,6 +1881,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-6.12/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..09304cefd7 --- /dev/null +++ b/queue-6.12/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From 35c61e65ae386ac7f73f26b990df8978509e9ffc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index 0a21a10a791c5..6b01c44a5f728 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1271,7 +1271,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1298,7 +1297,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch b/queue-6.12/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch new file mode 100644 index 0000000000..321ed0b753 --- /dev/null +++ b/queue-6.12/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch @@ -0,0 +1,101 @@ +From 33eb97ba6fa2d3be7dfa95af41b53fb44ecc472f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:45:18 +0000 +Subject: net: ethernet: mtk_eth_soc: avoid writing to ESW registers on MT7628 + +From: Joris Vaisvila + +[ Upstream commit 9a04d3b2f0708a9e5e1f731bafb69b040bb934a0 ] + +The MT7628 has a fixed-link PHY and does not expose MAC control +registers. Writes to these registers only corrupt the ESW VLAN +configuration. + +This patch explicitly registers no-op phylink_mac_ops for MT7628, as +after removing the invalid register accesses, the existing +phylink_mac_ops effectively become no-ops. + +This code was introduced by commit 296c9120752b +("net: ethernet: mediatek: Add MT7628/88 SoC support") + +Signed-off-by: Joris Vaisvila +Reviewed-by: Daniel Golle +Reviewed-by: Stefan Roese +Link: https://patch.msgid.link/20260226154547.68553-1-joey@tinyisr.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 ++++++++++++++++++--- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 7406b706fb753..a1bca5ee8acb0 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -541,9 +541,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + int val, ge_mode, err = 0; + u32 i; + +- /* MT76x8 has no hardware settings between for the MAC */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +- mac->interface != state->interface) { ++ if (mac->interface != state->interface) { + /* Setup soc pin functions */ + switch (state->interface) { + case PHY_INTERFACE_MODE_TRGMII: +@@ -819,6 +817,30 @@ static const struct phylink_mac_ops mtk_phylink_ops = { + .mac_link_up = mtk_mac_link_up, + }; + ++static void rt5350_mac_config(struct phylink_config *config, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++} ++ ++static void rt5350_mac_link_down(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++} ++ ++static void rt5350_mac_link_up(struct phylink_config *config, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++} ++ ++/* MT76x8 (rt5350-eth) does not expose any MAC control registers */ ++static const struct phylink_mac_ops rt5350_phylink_ops = { ++ .mac_config = rt5350_mac_config, ++ .mac_link_down = rt5350_mac_link_down, ++ .mac_link_up = rt5350_mac_link_up, ++}; ++ + static void mtk_mdio_config(struct mtk_eth *eth) + { + u32 val; +@@ -4601,6 +4623,7 @@ static const struct net_device_ops mtk_netdev_ops = { + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + { ++ const struct phylink_mac_ops *mac_ops = &mtk_phylink_ops; + const __be32 *_id = of_get_property(np, "reg", NULL); + phy_interface_t phy_mode; + struct phylink *phylink; +@@ -4732,9 +4755,12 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ mac_ops = &rt5350_phylink_ops; ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), +- phy_mode, &mtk_phylink_ops); ++ phy_mode, mac_ops); + if (IS_ERR(phylink)) { + err = PTR_ERR(phylink); + goto free_netdev; +-- +2.53.0 + diff --git a/queue-6.12/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-6.12/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..fb4c980ae6 --- /dev/null +++ b/queue-6.12/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From fb48487965a81d6b56407f943ded54f1c4e6df81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 641ad4054df45..cdcb3a9f08f04 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2350,6 +2350,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* PHY disconnect */ + if (ndev->phydev) { +-- +2.53.0 + diff --git a/queue-6.12/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-6.12/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..3c99009bc9 --- /dev/null +++ b/queue-6.12/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From e6182e2ffd06dabf6847d814d342eb88e14ce502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index bac1bb69d63a1..1542c0f1113e0 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -207,6 +207,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-6.12/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-6.12/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..e980276b16 --- /dev/null +++ b/queue-6.12/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From df5945541a349a44ee1d7abfd2fb6210c284bf56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index a9184a78650b0..46073afb1874a 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1908,6 +1908,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-6.12/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-6.12/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..07da676097 --- /dev/null +++ b/queue-6.12/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From 5be924dfad7fa4ef0e669aa2e848985f255ccaa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 58f3f0d979540..029e180ea5e3a 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2502,6 +2502,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-6.12/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch b/queue-6.12/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch new file mode 100644 index 0000000000..98662c7a44 --- /dev/null +++ b/queue-6.12/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch @@ -0,0 +1,82 @@ +From dc73dbbbceead4d9273db66d9fabcaadb63a5f6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 12:02:28 +0530 +Subject: net: lan743x: fix SGMII detection on PCI1xxxx B0+ during warm reset + +From: Thangaraj Samynathan + +[ Upstream commit e783e40fb689381caca31e03d28c39e10c82e722 ] + +A warm reset on boards using an EEPROM-only strap configuration (where +no MAC address is set in the image) can cause the driver to incorrectly +revert to RGMII mode. This occurs because the ENET_CONFIG_LOAD_STARTED +bit may not persist or behave as expected. + +Update pci11x1x_strap_get_status() to use revision-specific validation: + +- For PCI11x1x A0: Continue using the legacy check (config load started + or reset protection) to validate the SGMII strap. +- For PCI11x1x B0 and later: Use the newly available + STRAP_READ_USE_SGMII_EN_ bit in the upper strap register to validate + the lower SGMII_EN bit. + +This ensures the SGMII interface is correctly identified even after a +warm reboot. + +Signed-off-by: Thangaraj Samynathan +Link: https://patch.msgid.link/20260318063228.17110-1-thangaraj.s@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 15 +++++++++++---- + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index b897d071fc452..c2160357fd229 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -28,6 +28,12 @@ + + #define RFE_RD_FIFO_TH_3_DWORDS 0x3 + ++static bool pci11x1x_is_a0(struct lan743x_adapter *adapter) ++{ ++ u32 dev_rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_; ++ return dev_rev == ID_REV_CHIP_REV_PCI11X1X_A0_; ++} ++ + static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + { + u32 chip_rev; +@@ -47,10 +53,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); + lan743x_hs_syslock_release(adapter); + hw_cfg = lan743x_csr_read(adapter, HW_CFG); +- +- if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || +- hw_cfg & HW_CFG_RST_PROTECT_) { +- strap = lan743x_csr_read(adapter, STRAP_READ); ++ strap = lan743x_csr_read(adapter, STRAP_READ); ++ if ((pci11x1x_is_a0(adapter) && ++ (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || ++ hw_cfg & HW_CFG_RST_PROTECT_)) || ++ (strap & STRAP_READ_USE_SGMII_EN_)) { + if (strap & STRAP_READ_SGMII_EN_) + adapter->is_sgmii_en = true; + else +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 2f0cab0c85e1d..e17b708cd5058 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -27,6 +27,7 @@ + #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) + #define ID_REV_CHIP_REV_A0_ (0x00000000) + #define ID_REV_CHIP_REV_B0_ (0x00000010) ++#define ID_REV_CHIP_REV_PCI11X1X_A0_ (0x000000A0) + #define ID_REV_CHIP_REV_PCI11X1X_B0_ (0x000000B0) + + #define FPGA_REV (0x04) +-- +2.53.0 + diff --git a/queue-6.12/net-lan966x-avoid-unregistering-netdev-on-register-f.patch b/queue-6.12/net-lan966x-avoid-unregistering-netdev-on-register-f.patch new file mode 100644 index 0000000000..b3aaefe47a --- /dev/null +++ b/queue-6.12/net-lan966x-avoid-unregistering-netdev-on-register-f.patch @@ -0,0 +1,65 @@ +From 78162e95a864059ebe64470c69eda646d3007440 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 21:43:11 +0900 +Subject: net: lan966x: avoid unregistering netdev on register failure + +From: Myeonghun Pak + +[ Upstream commit c4f3d6eb1fcf6cd9ce4644f604d5aad1ce594dfc ] + +lan966x_probe_port() stores the newly allocated net_device in the +port before calling register_netdev(). If register_netdev() fails, +the probe error path calls lan966x_cleanup_ports(), which sees +port->dev and calls unregister_netdev() for a device that was never +registered. + +Destroy the phylink instance created for this port and clear port->dev +before returning the registration error. The common cleanup path now skips +ports without port->dev before reaching the registered netdev cleanup, so +it only handles ports that reached the registered-netdev lifetime. + +This also avoids treating an uninitialized FDMA netdev and the failed port +as a NULL == NULL match in the common cleanup path. + +Fixes: d28d6d2e37d1 ("net: lan966x: add port module support") +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260506124331.31945-1-mhun512@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index b5dc65a4d6403..9acba25a30586 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -749,11 +749,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) + + for (p = 0; p < lan966x->num_phys_ports; p++) { + port = lan966x->ports[p]; +- if (!port) ++ if (!port || !port->dev) + continue; + +- if (port->dev) +- unregister_netdev(port->dev); ++ unregister_netdev(port->dev); + + lan966x_xdp_port_deinit(port); + if (lan966x->fdma && lan966x->fdma_ndev == port->dev) +@@ -874,6 +873,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, + err = register_netdev(dev); + if (err) { + dev_err(lan966x->dev, "register_netdev failed\n"); ++ phylink_destroy(phylink); ++ port->phylink = NULL; ++ port->dev = NULL; + return err; + } + +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch b/queue-6.12/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch new file mode 100644 index 0000000000..44afdf05e9 --- /dev/null +++ b/queue-6.12/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch @@ -0,0 +1,41 @@ +From 7a416177328c67dcd4fdf676e6e349db7e3f45a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:09:23 +0300 +Subject: net/mlx5e: XSK, Increase size for chunk_size param + +From: Dragos Tatulea + +[ Upstream commit 1047e14b44edecbbab02a86514a083b8db9fde4d ] + +When 64K pages are used, chunk_size can take the 64K value +which doesn't fit in u16. This results in overflows that +are detected in mlx5e_mpwrq_log_wqe_sz(). + +Increase the type to u32 to fix this. + +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260403090927.139042-2-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/params.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +index bd5877acc5b1e..dc1df0c79e2ea 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +@@ -8,7 +8,7 @@ + + struct mlx5e_xsk_param { + u16 headroom; +- u16 chunk_size; ++ u32 chunk_size; + bool unaligned; + }; + +-- +2.53.0 + diff --git a/queue-6.12/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-6.12/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..6b02330700 --- /dev/null +++ b/queue-6.12/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From 50771a8517b3c4aeead1212a79b78f88a3fd5b8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index d72b2d5f96db8..ae3e1d035b256 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5589,6 +5589,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5724,6 +5726,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-6.12/net-phy-dp83tc811-add-reading-of-abilities.patch b/queue-6.12/net-phy-dp83tc811-add-reading-of-abilities.patch new file mode 100644 index 0000000000..9f768a9a09 --- /dev/null +++ b/queue-6.12/net-phy-dp83tc811-add-reading-of-abilities.patch @@ -0,0 +1,40 @@ +From 8c4eb1f73f9aa6298b70662b0295f850ed7f982e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 09:19:47 +0200 +Subject: net: phy: DP83TC811: add reading of abilities + +From: Sven Schuchmann + +[ Upstream commit c78bdba7b9666020c0832150a4fc4c0aebc7c6ac ] + +At this time the driver is not listing any speeds +it supports. This should be ETHTOOL_LINK_MODE_100baseT1_Full_BIT +for DP83TC811. Add the missing call for phylib to read the abilities. + +Fixes: b753a9faaf9a ("net: phy: DP83TC811: Introduce support for the DP83TC811 phy") +Suggested-by: Andrew Lunn +Signed-off-by: Sven Schuchmann +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260512071949.6218-1-schuchmann@schleissheimer.de +[pabeni@redhat.com: dropped revision history] +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83tc811.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c +index 7ea32fb77190c..5425a95352f9f 100644 +--- a/drivers/net/phy/dp83tc811.c ++++ b/drivers/net/phy/dp83tc811.c +@@ -393,6 +393,7 @@ static struct phy_driver dp83811_driver[] = { + .config_init = dp83811_config_init, + .config_aneg = dp83811_config_aneg, + .soft_reset = dp83811_phy_reset, ++ .get_features = genphy_c45_pma_read_ext_abilities, + .get_wol = dp83811_get_wol, + .set_wol = dp83811_set_wol, + .config_intr = dp83811_config_intr, +-- +2.53.0 + diff --git a/queue-6.12/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-6.12/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..a056943bb5 --- /dev/null +++ b/queue-6.12/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From 7ded80f882ef2658569db1260ae99f08320738cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c645853..4cbf5f934cde1 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -361,7 +361,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -462,7 +462,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-6.12/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-6.12/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..ce6a5f6e3e --- /dev/null +++ b/queue-6.12/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 941037eae45e4f585c8a382f45bd8047bdb82854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 7caae93937ee9..0b272eaa88739 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -270,6 +270,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch b/queue-6.12/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch new file mode 100644 index 0000000000..4038d893ab --- /dev/null +++ b/queue-6.12/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch @@ -0,0 +1,58 @@ +From 7589696fd7a2cf33b4b7bcbcdb988b67484a5a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 20:39:16 +0800 +Subject: net: sched: cls_u32: Avoid memcpy() false-positive warning in + u32_init_knode() + +From: Jiayuan Chen + +[ Upstream commit 34bd3c6b0bd383a76d987c8c45c4f309b681b255 ] + +Syzbot reported a warning in u32_init_knode() [1]. + +Similar to commit 7cba18332e36 ("net: sched: cls_u32: Avoid memcpy() +false-positive warning") which addressed the same issue in u32_change(), +use unsafe_memcpy() in u32_init_knode() to work around the compiler's +inability to see into composite flexible array structs. + +This silences the false-positive reported by syzbot: + + memcpy: detected field-spanning write (size 32) of single field + "&new->sel" at net/sched/cls_u32.c:855 (size 16) + +Since the memory is correctly allocated with kzalloc_flex() using +s->nkeys, this is purely a false positive and does not need a Fixes tag. + +[1] https://syzkaller.appspot.com/bug?extid=d5ace703ed883df56e42 + +Reported-by: syzbot+d5ace703ed883df56e42@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69a811b9.a70a0220.b118c.0019.GAE@google.com/T/ +Reviewed-by: Simon Horman +Acked-by: Gustavo A. R. Silva +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260309123917.402183-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_u32.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 58e849c0acf41..c2d032b9aab72 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -852,7 +852,10 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, + /* Similarly success statistics must be moved as pointers */ + new->pcpu_success = n->pcpu_success; + #endif +- memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); ++ unsafe_memcpy(&new->sel, s, struct_size(s, keys, s->nkeys), ++ /* A composite flex-array structure destination, ++ * which was correctly sized with kzalloc_flex(), ++ * above. */); + + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { + kfree(new); +-- +2.53.0 + diff --git a/queue-6.12/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch b/queue-6.12/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch new file mode 100644 index 0000000000..3af709081a --- /dev/null +++ b/queue-6.12/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch @@ -0,0 +1,57 @@ +From fb9f44f6b813e45536c1a2bc6287e3e61d60b93b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:11:11 +0200 +Subject: net: sfp: add quirk for ZOERAX SFP-2.5G-T + +From: Jan Hoffmann + +[ Upstream commit 911e2c050963ccf239faec6ae9dee0f5e8f1cc5c ] + +This is a 2.5G copper module which appears to be based on a Motorcomm +YT8821 PHY. There doesn't seem to be a usable way to to access the PHY +(I2C address 0x56 provides only read-only C22 access, and Rollball is +also not working). + +The module does not report the correct extended compliance code for +2.5GBase-T, and instead claims to support SONET OC-48 and Fibre Channel: + + Identifier : 0x03 (SFP) + Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID) + Connector : 0x07 (LC) + Transceiver codes : 0x00 0x01 0x00 0x00 0x40 0x40 0x04 0x00 0x00 + Transceiver type : FC: Multimode, 50um (M5) + Encoding : 0x05 (SONET Scrambled) + BR Nominal : 2500MBd + +Despite this, the kernel still enables the correct 2500Base-X interface +mode. However, for the module to actually work, it is also necessary to +disable inband auto-negotiation. + +Enable the existing "sfp_quirk_oem_2_5g" for this module, which handles +that and also sets the bit for 2500Base-T link mode. + +Signed-off-by: Jan Hoffmann +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260329191304.720160-1-jan@3e8.eu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/sfp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index 90ffba8f79520..0b9a9b3dee324 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -581,6 +581,8 @@ static const struct sfp_quirk sfp_quirks[] = { + SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball), ++ ++ SFP_QUIRK_S("ZOERAX", "SFP-2.5G-T", sfp_quirk_oem_2_5g), + }; + + static size_t sfp_strlen(const char *str, size_t maxlen) +-- +2.53.0 + diff --git a/queue-6.12/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch b/queue-6.12/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch new file mode 100644 index 0000000000..a7736938ff --- /dev/null +++ b/queue-6.12/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch @@ -0,0 +1,65 @@ +From a8e20ea0f4fc4f72c11c0f720af7ebbc3fd7b780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 15:26:40 -0700 +Subject: net/smc: avoid NULL deref of conn->lnk in smc_msg_event tracepoint + +From: Xiang Mei + +[ Upstream commit 7bf563badd37cb796df5477d2b78bb64148a1268 ] + +The smc_msg_event tracepoint class, shared by smc_tx_sendmsg and +smc_rx_recvmsg, unconditionally dereferences smc->conn.lnk: + + __string(name, smc->conn.lnk->ibname) + +conn->lnk is only set for SMC-R; for SMC-D it is NULL. Other code on +these paths already handles this (e.g. !conn->lnk in +SMC_STAT_RMB_TX_SIZE_SMALL()). With the tracepoint enabled, the first +sendmsg()/recvmsg() on an SMC-D socket crashes: + + Oops: general protection fault, probably for non-canonical address + KASAN: null-ptr-deref in range [...] + RIP: 0010:strlen+0x1e/0xa0 + Call Trace: + trace_event_raw_event_smc_msg_event (net/smc/smc_tracepoint.h:44) + smc_rx_recvmsg (net/smc/smc_rx.c:515) + smc_recvmsg (net/smc/af_smc.c:2859) + __sys_recvfrom (net/socket.c:2315) + __x64_sys_recvfrom (net/socket.c:2326) + do_syscall_64 + +The faulting address 0x3e0 is offsetof(struct smc_link, ibname), +confirming the NULL ->lnk deref. Enabling the tracepoint requires +root, but the trigger itself is unprivileged: socket(AF_SMC, ...) has +no capability check, and SMC-D negotiation needs no admin step on +s390 or on x86 with the loopback ISM device loaded. + +Log an empty device name for SMC-D instead of dereferencing NULL. + +Fixes: aff3083f10bf ("net/smc: Introduce tracepoints for tx and rx msg") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Dust Li +Reviewed-by: Sidraya Jayagond +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/smc_tracepoint.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/smc/smc_tracepoint.h b/net/smc/smc_tracepoint.h +index a9a6e3c1113aa..53da84f57fd6f 100644 +--- a/net/smc/smc_tracepoint.h ++++ b/net/smc/smc_tracepoint.h +@@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(smc_msg_event, + __field(const void *, smc) + __field(u64, net_cookie) + __field(size_t, len) +- __string(name, smc->conn.lnk->ibname) ++ __string(name, smc->conn.lnk ? smc->conn.lnk->ibname : "") + ), + + TP_fast_assign( +-- +2.53.0 + diff --git a/queue-6.12/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch b/queue-6.12/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch new file mode 100644 index 0000000000..7aaee0af34 --- /dev/null +++ b/queue-6.12/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch @@ -0,0 +1,63 @@ +From 7d9127b6521f1ccb4a3f347a098b04db64245554 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 23:21:38 -0700 +Subject: net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot + +From: Xiang Mei + +[ Upstream commit 277740023def559a4a2ddc3e8e784ee37a0f16a9 ] + +On the SMC-D client, slot 0 of ini->ism_dev[]/ini->ism_chid[] is +reserved for an SMC-Dv1 device. smc_find_ism_v2_device_clnt() +populates V2 entries starting at index 1, so when no V1 device is +selected slot 0 is left in its kzalloc()'ed state with ism_dev[0] == +NULL and ism_chid[0] == 0. + +smc_v2_determine_accepted_chid() then matches the peer's CHID against +the array starting from index 0 using the CHID alone. A malicious +peer replying to a SMC-Dv2-only proposal with d1.chid == 0 matches +the empty slot, ini->ism_selected becomes 0, and the subsequent +ism_dev[0]->lgr_lock dereference in smc_conn_create() faults at +offsetof(struct smcd_dev, lgr_lock) == 0x68: + + BUG: KASAN: null-ptr-deref in _raw_spin_lock_bh+0x79/0xe0 + Write of size 4 at addr 0000000000000068 by task exploit/144 + Call Trace: + _raw_spin_lock_bh + smc_conn_create (net/smc/smc_core.c:1997) + __smc_connect (net/smc/af_smc.c:1447) + smc_connect (net/smc/af_smc.c:1720) + __sys_connect + __x64_sys_connect + do_syscall_64 + +Require ism_dev[i] to be non-NULL before accepting a CHID match. + +Fixes: a7c9c5f4af7f ("net/smc: CLC accept / confirm V2") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260511062138.2839584-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 23bb360ebd07b..c96abb1386be4 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1398,7 +1398,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc, + int i; + + for (i = 0; i < ini->ism_offered_cnt + 1; i++) { +- if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) { ++ if (ini->ism_dev[i] && ++ ini->ism_chid[i] == ntohs(aclc->d1.chid)) { + ini->ism_selected = i; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-6.12/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..cd98446c0e --- /dev/null +++ b/queue-6.12/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 1ffa96c624fae491032649eb83d74a969554f6d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 4550f15d052dc..834cb01f8e0e8 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -800,11 +800,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-6.12/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-6.12/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..abd61fd72a --- /dev/null +++ b/queue-6.12/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From 646915984a932be81c792ad309a0b60b71275375 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 834cb01f8e0e8..7511cce76fbbf 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -789,21 +789,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-6.12/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..4911f8cea6 --- /dev/null +++ b/queue-6.12/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From 9155a0d329abb2188b4141e57b9ef1525e0dab16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 6240bb2b5b5b7..d480a91f081d3 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2583,19 +2583,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-6.12/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..3ac576e882 --- /dev/null +++ b/queue-6.12/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From 62cb2614f0abc6e8290bd0f599dd525218818914 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index e6f9e343b41f1..f05c79f215ea0 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 02b6501c15a5e..0fc03b07e62ae 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -93,18 +93,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 9985a82555c41..8a10375d89099 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -93,16 +93,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-6.12/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..bf0c62361a --- /dev/null +++ b/queue-6.12/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From 818a6370eb26e2d82641fc5312135466b171259c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 7413602195525..e6f9e343b41f1 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index dacd81b12e626..02b6501c15a5e 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 0f2a8c6118d42..9985a82555c41 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index a461c59ad2859..6240bb2b5b5b7 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2556,11 +2560,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-exclude-legacy-tables-on-preempt_rt.patch b/queue-6.12/netfilter-exclude-legacy-tables-on-preempt_rt.patch new file mode 100644 index 0000000000..8ceae17be2 --- /dev/null +++ b/queue-6.12/netfilter-exclude-legacy-tables-on-preempt_rt.patch @@ -0,0 +1,335 @@ +From e94e6e274a3848321a8c5cddba4ce06a06505a42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Jun 2025 17:44:23 +0200 +Subject: netfilter: Exclude LEGACY TABLES on PREEMPT_RT. + +From: Pablo Neira Ayuso + +[ Upstream commit 9fce66583f06c212e95e4b76dd61d8432ffa56b6 ] + +The seqcount xt_recseq is used to synchronize the replacement of +xt_table::private in xt_replace_table() against all readers such as +ipt_do_table() + +To ensure that there is only one writer, the writing side disables +bottom halves. The sequence counter can be acquired recursively. Only the +first invocation modifies the sequence counter (signaling that a writer +is in progress) while the following (recursive) writer does not modify +the counter. +The lack of a proper locking mechanism for the sequence counter can lead +to live lock on PREEMPT_RT if the high prior reader preempts the +writer. Additionally if the per-CPU lock on PREEMPT_RT is removed from +local_bh_disable() then there is no synchronisation for the per-CPU +sequence counter. + +The affected code is "just" the legacy netfilter code which is replaced +by "netfilter tables". That code can be disabled without sacrificing +functionality because everything is provided by the newer +implementation. This will only requires the usage of the "-nft" tools +instead of the "-legacy" ones. +The long term plan is to remove the legacy code so lets accelerate the +progress. + +Relax dependencies on iptables legacy, replace select with depends on, +this should cause no harm to existing kernel configs and users can still +toggle IP{6}_NF_IPTABLES_LEGACY in any case. +Make EBTABLES_LEGACY, IPTABLES_LEGACY and ARPTABLES depend on +NETFILTER_XTABLES_LEGACY. Hide xt_recseq and its users, +xt_register_table() and xt_percpu_counter_alloc() behind +NETFILTER_XTABLES_LEGACY. Let NETFILTER_XTABLES_LEGACY depend on +!PREEMPT_RT. + +This will break selftest expecing the legacy options enabled and will be +addressed in a following patch. + +Co-developed-by: Florian Westphal +Co-developed-by: Sebastian Andrzej Siewior +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 10 +++++----- + net/ipv4/netfilter/Kconfig | 24 ++++++++++++------------ + net/ipv6/netfilter/Kconfig | 19 +++++++++---------- + net/netfilter/Kconfig | 10 ++++++++++ + net/netfilter/x_tables.c | 16 +++++++++++----- + 5 files changed, 47 insertions(+), 32 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index f16bbbbb94817..60f28e4fb5c0a 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -42,8 +42,8 @@ config NF_CONNTRACK_BRIDGE + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY + tristate "Legacy EBTABLES support" +- depends on BRIDGE && NETFILTER_XTABLES +- default n ++ depends on BRIDGE && NETFILTER_XTABLES_LEGACY ++ default n + help + Legacy ebtables packet/frame classifier. + This is not needed if you are using ebtables over nftables +@@ -65,7 +65,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -76,7 +76,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -86,7 +86,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index ef8009281da5c..2c438b140e88f 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -13,8 +13,8 @@ config NF_DEFRAG_IPV4 + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY + tristate "Legacy IP tables support" +- default n +- select NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + iptables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -182,8 +182,8 @@ config IP_NF_MATCH_TTL + # `filter', generic and specific targets + config IP_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -220,10 +220,10 @@ config IP_NF_TARGET_SYNPROXY + config IP_NF_NAT + tristate "iptables NAT support" + depends on NF_CONNTRACK ++ depends on IP_NF_IPTABLES_LEGACY + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -263,8 +263,8 @@ endif # IP_NF_NAT + # mangle + specific targets + config IP_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -299,7 +299,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -313,7 +313,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -325,8 +325,8 @@ endif # IP_NF_IPTABLES + # ARP tables + config IP_NF_ARPTABLES + tristate "Legacy ARPTABLES support" +- depends on NETFILTER_XTABLES +- default n ++ depends on NETFILTER_XTABLES_LEGACY ++ default n + help + arptables is a legacy packet classifier. + This is not needed if you are using arptables over nftables +@@ -342,7 +342,7 @@ config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES + select NETFILTER_FAMILY_ARP +- depends on NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index e087a8e97ba78..276860f65baae 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -9,9 +9,8 @@ menu "IPv6: Netfilter Configuration" + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY + tristate "Legacy IP6 tables support" +- depends on INET && IPV6 +- select NETFILTER_XTABLES +- default n ++ depends on INET && IPV6 && NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + ip6tables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -196,8 +195,8 @@ config IP6_NF_TARGET_HL + + config IP6_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + tristate + help + Packet filtering defines a table `filter', which has a series of +@@ -233,8 +232,8 @@ config IP6_NF_TARGET_SYNPROXY + + config IP6_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -244,7 +243,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -258,7 +257,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -269,8 +268,8 @@ config IP6_NF_NAT + tristate "ip6tables NAT support" + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED ++ depends on IP6_NF_IPTABLES_LEGACY + select NF_NAT +- select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index df2dc21304efb..0d1d997abe191 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -762,6 +762,16 @@ config NETFILTER_XTABLES_COMPAT + + If unsure, say N. + ++config NETFILTER_XTABLES_LEGACY ++ bool "Netfilter legacy tables support" ++ depends on !PREEMPT_RT ++ help ++ Say Y here if you still require support for legacy tables. This is ++ required by the legacy tools (iptables-legacy) and is not needed if ++ you use iptables over nftables (iptables-nft). ++ Legacy support is not limited to IP, it also includes EBTABLES and ++ ARPTABLES. ++ + comment "Xtables combined modules" + + config NETFILTER_XT_MARK +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index efe7b7d71e7f7..1ca4fa9d249b8 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1340,12 +1340,13 @@ void xt_compat_unlock(u_int8_t af) + EXPORT_SYMBOL_GPL(xt_compat_unlock); + #endif + +-DEFINE_PER_CPU(seqcount_t, xt_recseq); +-EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); +- + struct static_key xt_tee_enabled __read_mostly; + EXPORT_SYMBOL_GPL(xt_tee_enabled); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY ++DEFINE_PER_CPU(seqcount_t, xt_recseq); ++EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); ++ + static int xt_jumpstack_alloc(struct xt_table_info *i) + { + unsigned int size; +@@ -1537,6 +1538,7 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++#endif + + #ifdef CONFIG_PROC_FS + static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) +@@ -1920,6 +1922,7 @@ void xt_proto_fini(struct net *net, u_int8_t af) + } + EXPORT_SYMBOL_GPL(xt_proto_fini); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY + /** + * xt_percpu_counter_alloc - allocate x_tables rule counter + * +@@ -1974,6 +1977,7 @@ void xt_percpu_counter_free(struct xt_counters *counters) + free_percpu((void __percpu *)pcnt); + } + EXPORT_SYMBOL_GPL(xt_percpu_counter_free); ++#endif + + static int __net_init xt_net_init(struct net *net) + { +@@ -2006,8 +2010,10 @@ static int __init xt_init(void) + unsigned int i; + int rv; + +- for_each_possible_cpu(i) { +- seqcount_init(&per_cpu(xt_recseq, i)); ++ if (IS_ENABLED(CONFIG_NETFILTER_XTABLES_LEGACY)) { ++ for_each_possible_cpu(i) { ++ seqcount_init(&per_cpu(xt_recseq, i)); ++ } + } + + xt = kcalloc(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-6.12/netfilter-make-legacy-configs-user-selectable.patch b/queue-6.12/netfilter-make-legacy-configs-user-selectable.patch new file mode 100644 index 0000000000..e13a4b742f --- /dev/null +++ b/queue-6.12/netfilter-make-legacy-configs-user-selectable.patch @@ -0,0 +1,104 @@ +From 838f34e9c06f832ae8c4dfafba38e1a5e7de9f13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 02:58:54 -0700 +Subject: netfilter: Make legacy configs user selectable + +From: Breno Leitao + +[ Upstream commit 6c959fd5e17387201dba3619b2e6af213939a0a7 ] + +This option makes legacy Netfilter Kconfig user selectable, giving users +the option to configure iptables without enabling any other config. + +Make the following KConfig entries user selectable: + * BRIDGE_NF_EBTABLES_LEGACY + * IP_NF_ARPTABLES + * IP_NF_IPTABLES_LEGACY + * IP6_NF_IPTABLES_LEGACY + +Signed-off-by: Breno Leitao +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 8 +++++++- + net/ipv4/netfilter/Kconfig | 16 ++++++++++++++-- + net/ipv6/netfilter/Kconfig | 9 ++++++++- + 3 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 104c0125e32e8..f16bbbbb94817 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -41,7 +41,13 @@ config NF_CONNTRACK_BRIDGE + + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY +- tristate ++ tristate "Legacy EBTABLES support" ++ depends on BRIDGE && NETFILTER_XTABLES ++ default n ++ help ++ Legacy ebtables packet/frame classifier. ++ This is not needed if you are using ebtables over nftables ++ (iptables-nft). + + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 1b991b889506a..ef8009281da5c 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -12,7 +12,13 @@ config NF_DEFRAG_IPV4 + + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP tables support" ++ default n ++ select NETFILTER_XTABLES ++ help ++ iptables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" +@@ -318,7 +324,13 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate ++ tristate "Legacy ARPTABLES support" ++ depends on NETFILTER_XTABLES ++ default n ++ help ++ arptables is a legacy packet classifier. ++ This is not needed if you are using arptables over nftables ++ (iptables-nft). + + config NFT_COMPAT_ARP + tristate +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index f3c8e2d918e13..e087a8e97ba78 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -8,7 +8,14 @@ menu "IPv6: Netfilter Configuration" + + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP6 tables support" ++ depends on INET && IPV6 ++ select NETFILTER_XTABLES ++ default n ++ help ++ ip6tables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" +-- +2.53.0 + diff --git a/queue-6.12/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-6.12/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..758446d829 --- /dev/null +++ b/queue-6.12/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From 8e610da5bdfc70feb6de865df67127a5aa332f0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e8..c593113557333 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -78,7 +78,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -787,6 +790,9 @@ static void dump_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-6.12/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..edbedee0ce --- /dev/null +++ b/queue-6.12/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From 35d429d552203e85420589948797d814458ac642 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 5897f3dbaf7c3..df2022fe440b0 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -310,6 +310,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 132b0e4a6d4df..13593391d6058 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 8b8885a73c764..c6d5b927830dd 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 97ead883e4a13..d19fce8589809 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1581,15 +1581,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 3d101613f27fa..49b7989c24e08 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1789,14 +1789,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1887,7 +1879,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 595bfb492b1c1..0dea754a91209 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -61,7 +61,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index db90db7057cc4..4d3b124923080 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -96,7 +96,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index a5db7c67d61be..d6c5824943f8e 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -129,6 +129,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index b46a790917306..6f7afec7954bd 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -53,7 +53,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 2b89adc1e5751..81175c20ccbe8 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -50,7 +50,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 7d5602950ae72..6b431b3f90ddb 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1795,14 +1795,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1894,7 +1886,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 9dcd4501fe800..cf561919bde84 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -60,7 +60,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index ce2cbce9e3ed3..1a758f2bc5379 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -89,7 +89,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index e119d4f090cc8..4ce45f3d11109 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -131,6 +131,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 8af0f8bd036dc..923455921c1dd 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -52,7 +52,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 66018b169b010..c44834d93fc79 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -49,7 +49,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 1ca4fa9d249b8..2d93f189a79b9 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1538,6 +1538,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-6.12/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-6.12/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..893e685248 --- /dev/null +++ b/queue-6.12/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From 9bd0748ef9f3529d2423fa530ea885d707fdb1b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index df2022fe440b0..706f08839050a 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -309,8 +309,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index d19fce8589809..f3dadbc416a3a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1583,7 +1582,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 49b7989c24e08..84b1f49ddbc5c 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1704,12 +1704,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1718,6 +1716,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1791,7 +1790,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index d6c5824943f8e..4dae3da4586b8 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -119,8 +119,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 6b431b3f90ddb..1eac22dbb957c 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1713,12 +1713,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1727,6 +1725,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1797,7 +1796,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 4ce45f3d11109..8088ebaf9b352 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -121,8 +121,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 2d93f189a79b9..76fd0999db4a8 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1522,23 +1525,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1548,6 +1534,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1557,6 +1551,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1567,6 +1562,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2013,8 +2052,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2023,8 +2064,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-6.12/netfilter-x_tables-close-dangling-table-module-init-.patch b/queue-6.12/netfilter-x_tables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..c57a377faa --- /dev/null +++ b/queue-6.12/netfilter-x_tables-close-dangling-table-module-init-.patch @@ -0,0 +1,406 @@ +From f259b5ab7d28dcc0004eb26e2ea857eb5b85b7d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:20 +0200 +Subject: netfilter: x_tables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 16bc4b6686b2c112c10e67d6b493adc3607256d3 ] + +Similar to the previous ebtables patch: +template add exposes the table to userspace, we must do this last to +rnsure the pernet ops are set up (contain the destructors). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_mangle.c | 25 +++++++++++++------------ + net/ipv4/netfilter/iptable_raw.c | 22 +++++++++++----------- + net/ipv4/netfilter/iptable_security.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_filter.c | 22 +++++++++++----------- + net/ipv6/netfilter/ip6table_mangle.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_raw.c | 20 ++++++++++---------- + net/ipv6/netfilter/ip6table_security.c | 23 ++++++++++++----------- + 9 files changed, 105 insertions(+), 99 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 382345567a600..370b635e3523b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = { + + static int __init arptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- arptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); +- if (IS_ERR(arpfilter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(arpfilter_ops)) + return PTR_ERR(arpfilter_ops); +- } + + ret = register_pernet_subsys(&arptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ arptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(arpfilter_ops); +- return ret; ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(arpfilter_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 0dea754a91209..672d7da1071d3 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = { + + static int __init iptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- iptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&iptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ iptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_filter_net_ops); ++ goto err_free; + } + + return 0; ++err_free: ++ kfree(filter_ops); ++ return ret; + } + + static void __exit iptable_filter_fini(void) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 4d3b124923080..13d25d9a4610e 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -111,25 +111,26 @@ static struct pernet_operations iptable_mangle_net_ops = { + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); +- ret = PTR_ERR(mangle_ops); +- return ret; +- } ++ if (IS_ERR(mangle_ops)) ++ return PTR_ERR(mangle_ops); + + ret = register_pernet_subsys(&iptable_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ iptable_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 6f7afec7954bd..2745c22f4034d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, +- iptable_raw_table_init); +- if (ret < 0) +- return ret; +- + rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&iptable_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ++ iptable_raw_table_init); + if (ret < 0) { +- xt_unregister_template(table); +- kfree(rawtable_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 81175c20ccbe8..491894511c544 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = { + + static int __init iptable_security_init(void) + { +- int ret = xt_register_template(&security_table, +- iptable_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&iptable_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ iptable_security_table_init); + if (ret < 0) { +- xt_unregister_template(&security_table); +- kfree(sectbl_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index cf561919bde84..b074fc4776764 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = { + + static int __init ip6table_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- ip6table_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&ip6table_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ip6table_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(filter_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 1a758f2bc5379..e6ee036a9b2c5 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -104,25 +104,26 @@ static struct pernet_operations ip6table_mangle_net_ops = { + + static int __init ip6table_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- ip6table_mangle_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); ++ if (IS_ERR(mangle_ops)) + return PTR_ERR(mangle_ops); +- } + + ret = register_pernet_subsys(&ip6table_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ ip6table_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 923455921c1dd..3b161ee875bcc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, ip6table_raw_table_init); +- if (ret < 0) +- return ret; +- + /* Register hooks */ + rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&ip6table_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ip6table_raw_table_init); + if (ret < 0) { +- kfree(rawtable_ops); +- xt_unregister_template(table); +- return ret; ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index c44834d93fc79..4bd5d97b8ab65 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = { + + static int __init ip6table_security_init(void) + { +- int ret = xt_register_template(&security_table, +- ip6table_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&ip6table_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ ip6table_security_table_init); + if (ret < 0) { +- kfree(sectbl_ops); +- xt_unregister_template(&security_table); +- return ret; ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-x_tables-unregister-the-templates-first.patch b/queue-6.12/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..a68187a7b6 --- /dev/null +++ b/queue-6.12/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From 79ffb9e6444394954f562928782608f5c22de4e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 78cd5ee24448f..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -82,8 +82,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 3ab908b747951..595bfb492b1c1 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -101,8 +101,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 385d945d8ebea..db90db7057cc4 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -135,8 +135,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 0e7f53964d0af..b46a790917306 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -100,9 +100,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index d885443cb2679..2b89adc1e5751 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -89,9 +89,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index e8992693e14a0..9dcd4501fe800 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -100,8 +100,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 8dd4cd0c47bd4..ce2cbce9e3ed3 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -128,8 +128,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index fc9f6754028f2..8af0f8bd036dc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -98,8 +98,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 4df14a9bae782..66018b169b010 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -88,8 +88,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-6.12/netfs-defer-the-emission-of-trace_netfs_folio.patch b/queue-6.12/netfs-defer-the-emission-of-trace_netfs_folio.patch new file mode 100644 index 0000000000..4c5c51a05b --- /dev/null +++ b/queue-6.12/netfs-defer-the-emission-of-trace_netfs_folio.patch @@ -0,0 +1,116 @@ +From 9c7342c5958e47587ed8057d7c870d37b105ebcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:49 +0100 +Subject: netfs: Defer the emission of trace_netfs_folio() + +From: David Howells + +[ Upstream commit daeb443b92817021c1234e8eded219e164b7c35d ] + +Change netfs_perform_write() to keep the netfs_folio trace value in a +variable and emit it later to make it easier to choose the value displayed. +This is a prerequisite for a subsequent patch. + +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-13-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Stable-dep-of: 7b4dcf1b9455 ("netfs: Fix streaming write being overwritten") +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index be77a137cc871..48c66d26e7b7e 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -143,6 +143,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + do { ++ enum netfs_folio_trace trace; + struct netfs_folio *finfo; + struct netfs_group *group; + unsigned long long fpos; +@@ -216,7 +217,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_folio_is_uptodate); ++ trace = netfs_folio_is_uptodate; + goto copied; + } + +@@ -232,7 +233,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + zero_user_segment(&folio->page, offset + copied, flen); + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_modify_and_clear); ++ trace = netfs_modify_and_clear; + goto copied; + } + +@@ -250,7 +251,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_whole_folio_modify); ++ trace = netfs_whole_folio_modify; + goto copied; + } + +@@ -277,7 +278,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_just_prefetch); ++ trace = netfs_just_prefetch; + goto copied; + } + +@@ -291,7 +292,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (offset == 0 && copied == flen) { + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_streaming_filled_page); ++ trace = netfs_streaming_filled_page; + goto copied; + } + +@@ -306,7 +307,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len = copied; + folio_attach_private(folio, (void *)((unsigned long)finfo | + NETFS_FOLIO_INFO)); +- trace_netfs_folio(folio, netfs_streaming_write); ++ trace = netfs_streaming_write; + goto copied; + } + +@@ -326,9 +327,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + folio_detach_private(folio); + folio_mark_uptodate(folio); + kfree(finfo); +- trace_netfs_folio(folio, netfs_streaming_cont_filled_page); ++ trace = netfs_streaming_cont_filled_page; + } else { +- trace_netfs_folio(folio, netfs_streaming_write_cont); ++ trace = netfs_streaming_write_cont; + } + goto copied; + } +@@ -344,6 +345,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + continue; + + copied: ++ trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); + + /* Update the inode size if we moved the EOF marker */ +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-a-few-minor-bugs-in-netfs_page_mkwrite.patch b/queue-6.12/netfs-fix-a-few-minor-bugs-in-netfs_page_mkwrite.patch new file mode 100644 index 0000000000..e67c63db70 --- /dev/null +++ b/queue-6.12/netfs-fix-a-few-minor-bugs-in-netfs_page_mkwrite.patch @@ -0,0 +1,90 @@ +From d186d791946bb8ad82ee0ca7a6703e36be7cdad5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 5 Oct 2024 19:23:04 +0100 +Subject: netfs: Fix a few minor bugs in netfs_page_mkwrite() + +From: Matthew Wilcox (Oracle) + +[ Upstream commit c6a90fe7f080d71271b723490454cfda1f81e4b0 ] + +We can't return with VM_FAULT_SIGBUS | VM_FAULT_LOCKED; the core +code will not unlock the folio in this instance. Introduce a new +"unlock" error exit to handle this case. Use it to handle +the "folio is truncated" check, and change the "writeback interrupted +by a fatal signal" to do a NOPAGE exit instead of letting the core +code install the folio currently under writeback before killing the +process. + +Signed-off-by: Matthew Wilcox (Oracle) +Link: https://lore.kernel.org/r/20241005182307.3190401-3-willy@infradead.org +Signed-off-by: Christian Brauner +Stable-dep-of: ccde2ac757c7 ("netfs: Fix folio->private handling in netfs_perform_write()") +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 08da4c2512f52..a02bd071cee77 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -513,7 +513,9 @@ EXPORT_SYMBOL(netfs_file_write_iter); + + /* + * Notification that a previously read-only page is about to become writable. +- * Note that the caller indicates a single page of a multipage folio. ++ * The caller indicates the precise page that needs to be written to, but ++ * we only track group on a per-folio basis, so we block more often than ++ * we might otherwise. + */ + vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_group) + { +@@ -523,7 +525,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + struct address_space *mapping = file->f_mapping; + struct inode *inode = file_inode(file); + struct netfs_inode *ictx = netfs_inode(inode); +- vm_fault_t ret = VM_FAULT_RETRY; ++ vm_fault_t ret = VM_FAULT_NOPAGE; + int err; + + _enter("%lx", folio->index); +@@ -532,21 +534,15 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + + if (folio_lock_killable(folio) < 0) + goto out; +- if (folio->mapping != mapping) { +- folio_unlock(folio); +- ret = VM_FAULT_NOPAGE; +- goto out; +- } +- +- if (folio_wait_writeback_killable(folio)) { +- ret = VM_FAULT_LOCKED; +- goto out; +- } ++ if (folio->mapping != mapping) ++ goto unlock; ++ if (folio_wait_writeback_killable(folio) < 0) ++ goto unlock; + + /* Can we see a streaming write here? */ + if (WARN_ON(!folio_test_uptodate(folio))) { +- ret = VM_FAULT_SIGBUS | VM_FAULT_LOCKED; +- goto out; ++ ret = VM_FAULT_SIGBUS; ++ goto unlock; + } + + group = netfs_folio_group(folio); +@@ -581,5 +577,8 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + out: + sb_end_pagefault(inode->i_sb); + return ret; ++unlock: ++ folio_unlock(folio); ++ goto out; + } + EXPORT_SYMBOL(netfs_page_mkwrite); +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch b/queue-6.12/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch new file mode 100644 index 0000000000..5116e02da5 --- /dev/null +++ b/queue-6.12/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch @@ -0,0 +1,80 @@ +From c3ecd6c468a5b80c3ccbb8567cd74f491f5209c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:54 +0100 +Subject: netfs: Fix early put of sink folio in netfs_read_gaps() + +From: David Howells + +[ Upstream commit 3e5dd91b87a8b1450217b56a336bee315f40da7d ] + +Fix netfs_read_gaps() to release the sink page it uses after waiting for +the request to complete. The way the sink page is used is that an +ITER_BVEC-class iterator is created that has the gaps from the target folio +at either end, but has the sink page tiled over the middle so that a single +read op can fill in both gaps. + +The bug was found by KASAN detecting a UAF on the generic/075 xfstest in +the cifsd kernel thread that handles reception of data from the TCP socket: + + BUG: KASAN: use-after-free in _copy_to_iter+0x48a/0xa20 + Write of size 885 at addr ffff888107f92000 by task cifsd/1285 + CPU: 2 UID: 0 PID: 1285 Comm: cifsd Not tainted 7.0.0 #6 PREEMPT(lazy) + Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x17f/0x4f1 + kasan_report+0x100/0x1e0 + kasan_check_range+0x10f/0x1e0 + __asan_memcpy+0x3c/0x60 + _copy_to_iter+0x48a/0xa20 + __skb_datagram_iter+0x2c9/0x430 + skb_copy_datagram_iter+0x6e/0x160 + tcp_recvmsg_locked+0xce0/0x1130 + tcp_recvmsg+0xeb/0x300 + inet_recvmsg+0xcf/0x3a0 + sock_recvmsg+0xea/0x100 + cifs_readv_from_socket+0x3a6/0x4d0 [cifs] + cifs_read_iter_from_socket+0xdd/0x130 [cifs] + cifs_readv_receive+0xaad/0xb10 [cifs] + cifs_demultiplex_thread+0x1148/0x1740 [cifs] + kthread+0x1cf/0x210 + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Reported-by: Steve French +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-18-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 2dd2260352dbf..1c906035fef02 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -525,14 +525,14 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + + netfs_read_to_pagecache(rreq); + +- if (sink) +- folio_put(sink); +- + ret = netfs_wait_for_read(rreq); + if (ret == 0) { + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } ++ ++ if (sink) ++ folio_put(sink); + folio_unlock(folio); + netfs_put_request(rreq, false, netfs_rreq_trace_put_return); + return ret < 0 ? ret : 0; +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch b/queue-6.12/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch new file mode 100644 index 0000000000..9bac900efd --- /dev/null +++ b/queue-6.12/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch @@ -0,0 +1,307 @@ +From 8e5c280c6f2d4cdcf22d47d93f81248c00474fc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:58 +0100 +Subject: netfs: Fix folio->private handling in netfs_perform_write() + +From: David Howells + +[ Upstream commit ccde2ac757c713535b224233a296de40efe5212d ] + +Under some circumstances, netfs_perform_write() doesn't correctly +manipulate folio->private between NULL, NETFS_FOLIO_COPY_TO_CACHE, pointing +to a group and pointing to a netfs_folio struct, leading to potential +multiple attachments of private data with associated folio ref leaks and +also leaks of netfs_folio structs or netfs_group refs. + +Fix this by consolidating the place at which a folio is marked uptodate in +one place and having that look at what's attached to folio->private and +decide how to clean it up and then set the new group. Also, the content +shouldn't be flushed if group is NULL, even if a group is specified in the +netfs_group parameter, as that would be the case for a new folio. A +filesystem should always specify netfs_group or never specify netfs_group. + +The Sashiko auto-review tool noted that it was theoretically possible that +the fpos >= ctx->zero_point section might leak if it modified a streaming +write folio. This is unlikely, but with a network filesystem, third party +changes can happen. It also pointed out that __netfs_set_group() would +leak if called multiple times on the same folio from the "whole folio +modify section". + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-22-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 134 +++++++++++++++++++++-------------- + include/trace/events/netfs.h | 1 + + 2 files changed, 82 insertions(+), 53 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 8ba74556bccab..f4e9d88a0a7bf 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -13,24 +13,6 @@ + #include + #include "internal.h" + +-static void __netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- if (netfs_group) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +-} +- +-static void netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- void *priv = folio_get_private(folio); +- +- if (unlikely(priv != netfs_group)) { +- if (netfs_group && (!priv || priv == NETFS_FOLIO_COPY_TO_CACHE)) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +- else if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) +- folio_detach_private(folio); +- } +-} +- + /* + * Grab a folio for writing and lock it. Attempt to allocate as large a folio + * as possible to hold as much of the remaining length as possible in one go. +@@ -151,6 +133,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + size_t offset; /* Offset into pagecache folio */ + size_t part; /* Bytes to write to folio */ + size_t copied; /* Bytes copied from user */ ++ void *priv; + + offset = pos & (max_chunk - 1); + part = min(max_chunk - offset, iov_iter_count(iter)); +@@ -196,6 +179,25 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto error_folio_unlock; + } + ++ finfo = netfs_folio_info(folio); ++ group = netfs_folio_group(folio); ++ ++ /* If the requested group differs from the group set on the ++ * page, then we need to flush out the folio if it has a group ++ * set (ie. is non-NULL). Note that COPY_TO_CACHE is a special ++ * case, being a netfs annotation rather than an actual group. ++ * ++ * The filesystem isn't permitted to mix writes with groups and ++ * writes without groups as the NULL group is used to indicate ++ * that no group is set. ++ */ ++ if (unlikely(group != netfs_group) && ++ group != NETFS_FOLIO_COPY_TO_CACHE && ++ group) { ++ WARN_ON_ONCE(!netfs_group); ++ goto flush_content; ++ } ++ + /* Decide how we should modify a folio. We might be attempting + * to do write-streaming, as we don't want to a local RMW cycle + * if we can avoid it. If we're doing local caching or content +@@ -203,22 +205,14 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + * file is open readably, then we let ->read_folio() fill in + * the gaps. + */ +- finfo = netfs_folio_info(folio); +- group = netfs_folio_group(folio); +- +- if (unlikely(group != netfs_group) && +- group != NETFS_FOLIO_COPY_TO_CACHE) +- goto flush_content; +- + if (folio_test_uptodate(folio)) { + if (mapping_writably_mapped(mapping)) + flush_dcache_folio(folio); + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_folio_is_uptodate; +- goto copied; ++ goto copied_uptodate; + } + + /* If the page is above the zero-point then we assume that the +@@ -231,24 +225,22 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + folio_zero_segment(folio, offset + copied, flen); +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_modify_and_clear; +- goto copied; ++ if (finfo) ++ trace = netfs_modify_and_clear_rm_finfo; ++ else ++ trace = netfs_modify_and_clear; ++ goto mark_uptodate; + } + + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (likely(copied == part)) { +- if (finfo) { ++ if (finfo) + trace = netfs_whole_folio_modify_filled; +- goto folio_now_filled; +- } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; +- goto copied; ++ else ++ trace = netfs_whole_folio_modify; ++ goto mark_uptodate; + } + if (copied == 0) + goto copy_failed; +@@ -266,7 +258,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += finfo->dirty_offset; + if (finfo->dirty_len == flen) { + trace = netfs_whole_folio_modify_filled_efault; +- goto folio_now_filled; ++ goto mark_uptodate; + } + if (copied > finfo->dirty_len) + finfo->dirty_len = copied; +@@ -294,11 +286,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_just_prefetch; +- goto copied; ++ goto copied_uptodate; + } + ++ /* Do a streaming write on a folio that has nothing in it yet. */ + if (!finfo) { + ret = -EIO; + if (WARN_ON(folio_get_private(folio))) +@@ -307,10 +299,8 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + if (offset == 0 && copied == flen) { +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); + trace = netfs_streaming_filled_page; +- goto copied; ++ goto mark_uptodate; + } + + finfo = kzalloc(sizeof(*finfo), GFP_KERNEL); +@@ -339,7 +329,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { + trace = netfs_streaming_cont_filled_page; +- goto folio_now_filled; ++ goto mark_uptodate; + } + trace = netfs_streaming_write_cont; + goto copied; +@@ -355,13 +345,36 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + +- folio_now_filled: +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); ++ /* Mark a folio as being up to data when we've filled it ++ * completely. If the folio has a group attached, then it must ++ * be the same group, otherwise we should have flushed it out ++ * above. We have to get rid of the netfs_folio struct if ++ * there was one. ++ */ ++ mark_uptodate: + folio_mark_uptodate(folio); +- kfree(finfo); ++ ++ copied_uptodate: ++ priv = folio_get_private(folio); ++ if (likely(priv == netfs_group)) { ++ /* Already set correctly; no change required. */ ++ } else if (priv == NETFS_FOLIO_COPY_TO_CACHE) { ++ if (!netfs_group) ++ folio_detach_private(folio); ++ else ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ } else if (!priv) { ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ } else { ++ WARN_ON_ONCE(!finfo); ++ if (netfs_group) ++ /* finfo->netfs_group has a ref */ ++ folio_change_private(folio, netfs_group); ++ else ++ folio_detach_private(folio); ++ kfree(finfo); ++ } ++ + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +@@ -526,6 +539,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + struct inode *inode = file_inode(file); + struct netfs_inode *ictx = netfs_inode(inode); + vm_fault_t ret = VM_FAULT_NOPAGE; ++ void *priv; + int err; + + _enter("%lx", folio->index); +@@ -546,7 +560,9 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + } + + group = netfs_folio_group(folio); +- if (group != netfs_group && group != NETFS_FOLIO_COPY_TO_CACHE) { ++ if (group && ++ group != netfs_group && ++ group != NETFS_FOLIO_COPY_TO_CACHE) { + folio_unlock(folio); + err = filemap_fdatawrite_range(mapping, + folio_pos(folio), +@@ -568,7 +584,19 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + trace_netfs_folio(folio, netfs_folio_trace_mkwrite_plus); + else + trace_netfs_folio(folio, netfs_folio_trace_mkwrite); +- netfs_set_group(folio, netfs_group); ++ ++ priv = folio_get_private(folio); ++ if (priv != netfs_group) { ++ if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_detach_private(folio); ++ else if (netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ else if (netfs_group && !priv) ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ else ++ WARN_ON_ONCE(1); ++ } ++ + file_update_time(file); + set_bit(NETFS_ICTX_MODIFIED_ATTR, &ictx->flags); + if (ictx->ops->post_modify) +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index 6395827e83954..1d9b068bb1758 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -149,6 +149,7 @@ + EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ + EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ ++ EM(netfs_modify_and_clear_rm_finfo, "mod-n-clear+") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ + EM(netfs_flush_content, "flush") \ +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch b/queue-6.12/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch new file mode 100644 index 0000000000..532919fdea --- /dev/null +++ b/queue-6.12/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch @@ -0,0 +1,128 @@ +From 17380d69bf63b57d28cee1481583ebb7e5e47e12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:48 +0100 +Subject: netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes + gone + +From: David Howells + +[ Upstream commit 156ac2ec2ee77c44c4eb7439d6d165247ba12247 ] + +If a streaming write is made, this will leave the relevant modified folio +in a not-uptodate, but dirty state with a netfs_folio struct hung off of +folio->private indicating the dirty range. Subsequently truncating the +file such that the dirty data in the folio is removed, but the first part +of the folio theoretically remains will cause the netfs_folio struct to be +discarded... but will leave the dirty flag set. + +If the folio is then read via mmap(), netfs_read_folio() will see that the +page is dirty and jump to netfs_read_gaps() to fill in the missing bits. +netfs_read_gaps(), however, expects there to be a netfs_folio struct +present and can oops because truncate removed it. + +Fix this by calling folio_cancel_dirty() in netfs_invalidate_folio() in the +event that all the dirty data in the folio is erased (as nfs does). + +Also add some tracepoints to log modifications to a dirty page. + +This can be reproduced with something like: + + dd if=/dev/zero of=/xfstest.test/foo bs=1M count=1 + umount /xfstest.test + mount /xfstest.test + xfs_io -c "w 0xbbbf 0xf96c" \ + -c "truncate 0xbbbf" \ + -c "mmap -r 0xb000 0x11000" \ + -c "mr 0xb000 0x11000" \ + /xfstest.test/foo + +with fscaching disabled (otherwise streaming writes are suppressed) and a +change to netfs_perform_write() to disallow streaming writes if the fd is +open O_RDWR: + + if (//(file->f_mode & FMODE_READ) || <--- comment this out + netfs_is_cache_enabled(ctx)) { + +It should be reproducible even without this change, but if prevents the +above trivial xfs_io command from reproducing it. + +Note that the initial dd is important: the file must start out sufficiently +large that the zero-point logic doesn't just clear the gaps because it +knows there's nothing in the file to read yet. Unmounting and mounting is +needed to clear the pagecache (there are other ways to do that that may +also work). + +This was initially reproduced with the generic/522 xfstest on some patches +that remove the FMODE_READ restriction. + +Fixes: 9ebff83e6481 ("netfs: Prep to use folio->private for write grouping and streaming write") +Reported-by: Marc Dionne +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-12-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 6 +++++- + include/trace/events/netfs.h | 4 ++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 78fe5796b2b2f..488a4b1914300 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -268,6 +268,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; + finfo->dirty_offset = offset; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } + +@@ -276,12 +277,14 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + */ + if (iend >= fend) { + finfo->dirty_len = offset - fstart; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_tail); + return; + } + + /* A partial write was split. The caller has already zeroed + * it, so just absorb the hole. + */ ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_middle); + } + return; + +@@ -289,8 +292,9 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + netfs_put_group(netfs_folio_group(folio)); + folio_detach_private(folio); + folio_clear_uptodate(folio); ++ folio_cancel_dirty(folio); + kfree(finfo); +- return; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_all); + } + EXPORT_SYMBOL(netfs_invalidate_folio); + +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index 69975c9c68239..f3e386c69cc8b 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -161,6 +161,10 @@ + EM(netfs_folio_trace_copy_to_cache, "mark-copy") \ + EM(netfs_folio_trace_end_copy, "end-copy") \ + EM(netfs_folio_trace_filled_gaps, "filled-gaps") \ ++ EM(netfs_folio_trace_invalidate_all, "inval-all") \ ++ EM(netfs_folio_trace_invalidate_front, "inval-front") \ ++ EM(netfs_folio_trace_invalidate_middle, "inval-mid") \ ++ EM(netfs_folio_trace_invalidate_tail, "inval-tail") \ + EM(netfs_folio_trace_kill, "kill") \ + EM(netfs_folio_trace_kill_cc, "kill-cc") \ + EM(netfs_folio_trace_kill_g, "kill-g") \ +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch b/queue-6.12/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch new file mode 100644 index 0000000000..e7b8081b2d --- /dev/null +++ b/queue-6.12/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch @@ -0,0 +1,80 @@ +From a437285747aabe877c009dc17c5d78b57a622b9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:47 +0100 +Subject: netfs: Fix overrun check in netfs_extract_user_iter() + +From: David Howells + +[ Upstream commit 0ef37eef83fad3542ee06db2940433ae1a92b39d ] + +Fix netfs_extract_user_iter() so that if iov_iter_extract_pages() overfills +pages[], then those pages don't get included in the iterator constructed at +the end of the function. If there was an overfill, memory corruption has +already happened. + +Fixes: 85dd2c8ff368 ("netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-11-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/iterator.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c +index 429e4396e1b00..b375567e0520e 100644 +--- a/fs/netfs/iterator.c ++++ b/fs/netfs/iterator.c +@@ -72,21 +72,24 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + break; + } + +- if (ret > count) { +- pr_err("get_pages rc=%zd more than %zu\n", ret, count); ++ if (WARN(ret > count, ++ "%s: extract_pages overrun %zd > %zu bytes\n", ++ __func__, ret, count)) { ++ ret = -EIO; + break; + } + +- count -= ret; +- ret += offset; +- cur_npages = DIV_ROUND_UP(ret, PAGE_SIZE); +- +- if (npages + cur_npages > max_pages) { +- pr_err("Out of bvec array capacity (%u vs %u)\n", +- npages + cur_npages, max_pages); ++ cur_npages = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ if (WARN(cur_npages > max_pages - npages, ++ "%s: extract_pages overrun %u > %u pages\n", ++ __func__, npages + cur_npages, max_pages)) { ++ ret = -EIO; + break; + } + ++ count -= ret; ++ ret += offset; ++ + for (i = 0; i < cur_npages; i++) { + len = ret > PAGE_SIZE ? PAGE_SIZE : ret; + bvec_set_page(bv + npages + i, *pages++, len - offset, offset); +@@ -97,6 +100,11 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + npages += cur_npages; + } + ++ /* Note: Don't try to clean up after EIO. Either we got no pages, so ++ * nothing to clean up, or we got a buffer overrun, memory corruption ++ * and can't trust the stuff in the buffer (a WARN was emitted). ++ */ ++ + if (ret < 0 && (ret == -ENOMEM || npages == 0)) { + for (i = 0; i < npages; i++) + unpin_user_page(bv[i].bv_page); +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-partial-invalidation-of-streaming-write-fo.patch b/queue-6.12/netfs-fix-partial-invalidation-of-streaming-write-fo.patch new file mode 100644 index 0000000000..5d14cbd980 --- /dev/null +++ b/queue-6.12/netfs-fix-partial-invalidation-of-streaming-write-fo.patch @@ -0,0 +1,49 @@ +From d43c8c5197b3ed46faf9f9c816854c8aaa12cf57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:57 +0100 +Subject: netfs: Fix partial invalidation of streaming-write folio + +From: David Howells + +[ Upstream commit 6d91acc7fb85d33ea58fca9b964a32a453937f4b ] + +In netfs_invalidate_folio(), if the region of a partial invalidation +overlaps the front (but not all) of a dirty write cached in a streaming +write page (dirty, but not uptodate, with the dirty region tracked by a +netfs_folio struct), the function modifies the dirty region - but +incorrectly as it moves the region forward by setting the start to the +start, not the end, of the invalidation region. + +Fix this by setting finfo->dirty_offset to the end of the invalidation +region (iend). + +Fixes: cce6bfa6ca0e ("netfs: Fix trimming of streaming-write folios in netfs_inval_folio()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-21-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 488a4b1914300..9672904232ad5 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -267,7 +267,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + goto erase_completely; + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; +- finfo->dirty_offset = offset; ++ finfo->dirty_offset = iend; + trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-potential-deadlock-in-write-through-mode.patch b/queue-6.12/netfs-fix-potential-deadlock-in-write-through-mode.patch new file mode 100644 index 0000000000..31a503210c --- /dev/null +++ b/queue-6.12/netfs-fix-potential-deadlock-in-write-through-mode.patch @@ -0,0 +1,119 @@ +From de2003f22a74af53c528ddef49b5a955f9c4a2b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:51 +0100 +Subject: netfs: Fix potential deadlock in write-through mode + +From: David Howells + +[ Upstream commit b6a4ae1634b3ad2aaa05222e53d36da532852faf ] + +Fix netfs_advance_writethrough() to always unlock the supplied folio and to +mark it dirty if it isn't yet written to the end. Unfortunately, it can't +be marked for writeback until the folio is done with as that may cause a +deadlock against mmapped reads and writes. + +Even though it has been marked dirty, premature writeback can't occur as +the caller is holding both inode->i_rwsem (which will prevent concurrent +truncation, fallocation, DIO and other writes) and ictx->wb_lock (which +will cause flushing to wait and writeback to skip or wait). + +Note that this may be easier to deal with once the queuing of folios is +split from the generation of subrequests. + +Fixes: 288ace2f57c9 ("netfs: New writeback implementation") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-15-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/write_issue.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index b7830a15ae40f..2789ac4c80272 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -402,12 +402,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq, + if (streamw) + netfs_issue_write(wreq, cache); + +- /* Flip the page to the writeback state and unlock. If we're called +- * from write-through, then the page has already been put into the wb +- * state. +- */ +- if (wreq->origin == NETFS_WRITEBACK) +- folio_start_writeback(folio); ++ folio_start_writeback(folio); + folio_unlock(folio); + + if (fgroup == NETFS_FOLIO_COPY_TO_CACHE) { +@@ -632,29 +627,41 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c + struct folio *folio, size_t copied, bool to_page_end, + struct folio **writethrough_cache) + { ++ int ret; ++ + _enter("R=%x ic=%zu ws=%u cp=%zu tp=%u", + wreq->debug_id, wreq->iter.count, wreq->wsize, copied, to_page_end); + +- if (!*writethrough_cache) { +- if (folio_test_dirty(folio)) +- /* Sigh. mmap. */ +- folio_clear_dirty_for_io(folio); ++ /* The folio is locked. */ + ++ if (*writethrough_cache != folio) { ++ if (*writethrough_cache) { ++ /* Did the folio get moved? */ ++ folio_put(*writethrough_cache); ++ *writethrough_cache = NULL; ++ } + /* We can make multiple writes to the folio... */ +- folio_start_writeback(folio); + if (wreq->len == 0) + trace_netfs_folio(folio, netfs_folio_trace_wthru); + else + trace_netfs_folio(folio, netfs_folio_trace_wthru_plus); + *writethrough_cache = folio; ++ folio_get(folio); + } + + wreq->len += copied; +- if (!to_page_end) ++ ++ if (!to_page_end) { ++ folio_mark_dirty(folio); ++ folio_unlock(folio); + return 0; ++ } + ++ ret = netfs_write_folio(wreq, wbc, folio); ++ folio_put(*writethrough_cache); + *writethrough_cache = NULL; +- return netfs_write_folio(wreq, wbc, folio); ++ wreq->submitted = wreq->len; ++ return ret; + } + + /* +@@ -668,8 +675,12 @@ int netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_contr + + _enter("R=%x", wreq->debug_id); + +- if (writethrough_cache) ++ if (writethrough_cache) { ++ folio_lock(writethrough_cache); + netfs_write_folio(wreq, wbc, writethrough_cache); ++ folio_put(writethrough_cache); ++ wreq->submitted = wreq->len; ++ } + + netfs_end_issue_write(wreq); + +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-streaming-write-being-overwritten.patch b/queue-6.12/netfs-fix-streaming-write-being-overwritten.patch new file mode 100644 index 0000000000..eecc5701ef --- /dev/null +++ b/queue-6.12/netfs-fix-streaming-write-being-overwritten.patch @@ -0,0 +1,176 @@ +From 6a57a66d6e44a88d75df28da97deea9d2140b1d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:50 +0100 +Subject: netfs: Fix streaming write being overwritten + +From: David Howells + +[ Upstream commit 7b4dcf1b9455a6e52ac7478b4057dbe10359576d ] + +In order to avoid reading whilst writing, netfslib will allow "streaming +writes" in which dirty data is stored directly into folios without reading +them first. Such folios are marked dirty but may not be marked uptodate. +If a folio is entirely written by a streaming write, uptodate will be set, +otherwise it will have a netfs_folio struct attached to ->private recording +the dirty region. + +In the event that a partially written streaming write page is to be +overwritten entirely by a single write(), netfs_perform_write() will try to +copy over it, but doesn't discard the netfs_folio if it succeeds; further, +it doesn't correctly handle a partial copy that overwrites some of the +dirty data. + +Fix this by the following: + + (1) If the folio is successfully overwritten, free the netfs_folio struct + before marking the page uptodate. + + (2) If the copy to the folio partially fails, but short of the dirty data, + just ignore the copy. + + (3) If the copy partially fails and overwrites some of the dirty data, + accept the copy, update the netfs_folio struct to record the new data. + If the folio is now filled, free the netfs_folio and set uptodate, + otherwise return a partial write. + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0 0x927c0 + write 0x63fb8 0x53c8 0 + copy_range 0xb704 0x19b9 0x24429 0x79380 + write 0x2402b 0x144a2 0x90660 * + write 0x204d5 0x140a0 0x927c0 * + copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 * + read 0x00000 0x20000 0x9157c + read 0x20000 0x20000 0x9157c + read 0x40000 0x20000 0x9157c + read 0x60000 0x20000 0x9157c + read 0x7e1a0 0xcfb9 0x9157c + +on cifs with the default cache option. + +It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in +netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-14-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 47 ++++++++++++++++++++++++++---------- + include/trace/events/netfs.h | 3 +++ + 2 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 48c66d26e7b7e..19a58aea670cb 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -240,18 +240,38 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); +- if (unlikely(copied == 0)) ++ if (likely(copied == part)) { ++ if (finfo) { ++ trace = netfs_whole_folio_modify_filled; ++ goto folio_now_filled; ++ } ++ __netfs_set_group(folio, netfs_group); ++ folio_mark_uptodate(folio); ++ trace = netfs_whole_folio_modify; ++ goto copied; ++ } ++ if (copied == 0) + goto copy_failed; +- if (unlikely(copied < part)) { ++ if (!finfo || copied <= finfo->dirty_offset) { + maybe_trouble = true; + iov_iter_revert(iter, copied); + copied = 0; + folio_unlock(folio); + goto retry; + } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; ++ ++ /* We overwrote some existing dirty data, so we have to ++ * accept the partial write. ++ */ ++ finfo->dirty_len += finfo->dirty_offset; ++ if (finfo->dirty_len == flen) { ++ trace = netfs_whole_folio_modify_filled_efault; ++ goto folio_now_filled; ++ } ++ if (copied > finfo->dirty_len) ++ finfo->dirty_len = copied; ++ finfo->dirty_offset = 0; ++ trace = netfs_whole_folio_modify_efault; + goto copied; + } + +@@ -321,16 +341,10 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto copy_failed; + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); +- folio_mark_uptodate(folio); +- kfree(finfo); + trace = netfs_streaming_cont_filled_page; +- } else { +- trace = netfs_streaming_write_cont; ++ goto folio_now_filled; + } ++ trace = netfs_streaming_write_cont; + goto copied; + } + +@@ -344,6 +358,13 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + ++ folio_now_filled: ++ if (finfo->netfs_group) ++ folio_change_private(folio, finfo->netfs_group); ++ else ++ folio_detach_private(folio); ++ folio_mark_uptodate(folio); ++ kfree(finfo); + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index f3e386c69cc8b..6395827e83954 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -145,6 +145,9 @@ + EM(netfs_folio_is_uptodate, "mod-uptodate") \ + EM(netfs_just_prefetch, "mod-prefetch") \ + EM(netfs_whole_folio_modify, "mod-whole-f") \ ++ EM(netfs_whole_folio_modify_efault, "mod-whole-f!") \ ++ EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ ++ EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch b/queue-6.12/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch new file mode 100644 index 0000000000..feceb48862 --- /dev/null +++ b/queue-6.12/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch @@ -0,0 +1,169 @@ +From f099242c77743952a4ce2eb600c7055e1c62d0ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:44 +0100 +Subject: netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call + +From: Viacheslav Dubeyko + +[ Upstream commit dc7832d05deb4d632e8035e3299e31a3528fa0d0 ] + +The multiple runs of generic/013 test-case is capable +to reproduce a kernel BUG at mm/filemap.c:1504 with +probability of 30%. + +while true; do + sudo ./check generic/013 +done + +[ 9849.452376] page: refcount:3 mapcount:0 mapping:00000000e58ff252 index:0x10781 pfn:0x1c322 +[ 9849.452412] memcg:ffff8881a1915800 +[ 9849.452417] aops:ceph_aops ino:1000058db9e dentry name(?):"f9XXXXXX" +[ 9849.452432] flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff) +[ 9849.452441] raw: 0017ffffc0000000 0000000000000000 dead000000000122 ffff88816110d248 +[ 9849.452445] raw: 0000000000010781 0000000000000000 00000003ffffffff ffff8881a1915800 +[ 9849.452447] page dumped because: VM_BUG_ON_FOLIO(!folio_test_locked(folio)) +[ 9849.452474] ------------[ cut here ]------------ +[ 9849.452476] kernel BUG at mm/filemap.c:1504! +[ 9849.478635] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +[ 9849.481772] CPU: 2 UID: 0 PID: 84223 Comm: fsstress Not tainted 7.0.0-rc1+ #18 PREEMPT(full) +[ 9849.482881] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/1 +0/2025 +[ 9849.484539] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.485076] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc +cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.493818] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.495740] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.498678] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.500559] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.501097] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.502108] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.502516] FS: 00007e36cbe94740(0000) GS:ffff88824a899000(0000) knlGS:0000000000000000 +[ 9849.502996] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.503810] CR2: 000000c0002b0000 CR3: 000000011bbf6004 CR4: 0000000000772ef0 +[ 9849.504459] PKRU: 55555554 +[ 9849.504626] Call Trace: +[ 9849.505242] +[ 9849.505379] netfs_write_begin+0x7c8/0x10a0 +[ 9849.505877] ? __kasan_check_read+0x11/0x20 +[ 9849.506384] ? __pfx_netfs_write_begin+0x10/0x10 +[ 9849.507178] ceph_write_begin+0x8c/0x1c0 +[ 9849.507934] generic_perform_write+0x391/0x8f0 +[ 9849.508503] ? __pfx_generic_perform_write+0x10/0x10 +[ 9849.509062] ? file_update_time_flags+0x19a/0x4b0 +[ 9849.509581] ? ceph_get_caps+0x63/0xf0 +[ 9849.510259] ? ceph_get_caps+0x63/0xf0 +[ 9849.510530] ceph_write_iter+0xe79/0x1ae0 +[ 9849.511282] ? __pfx_ceph_write_iter+0x10/0x10 +[ 9849.511839] ? lock_acquire+0x1ad/0x310 +[ 9849.512334] ? ksys_write+0xf9/0x230 +[ 9849.512582] ? lock_is_held_type+0xaa/0x140 +[ 9849.513128] vfs_write+0x512/0x1110 +[ 9849.513634] ? __fget_files+0x33/0x350 +[ 9849.513893] ? __pfx_vfs_write+0x10/0x10 +[ 9849.514143] ? mutex_lock_nested+0x1b/0x30 +[ 9849.514394] ksys_write+0xf9/0x230 +[ 9849.514621] ? __pfx_ksys_write+0x10/0x10 +[ 9849.514887] ? do_syscall_64+0x25e/0x1520 +[ 9849.515122] ? __kasan_check_read+0x11/0x20 +[ 9849.515366] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.515655] __x64_sys_write+0x72/0xd0 +[ 9849.515885] ? trace_hardirqs_on+0x24/0x1c0 +[ 9849.516130] x64_sys_call+0x22f/0x2390 +[ 9849.516341] do_syscall_64+0x12b/0x1520 +[ 9849.516545] ? do_syscall_64+0x27c/0x1520 +[ 9849.516783] ? do_syscall_64+0x27c/0x1520 +[ 9849.517003] ? lock_release+0x318/0x480 +[ 9849.517220] ? __x64_sys_io_getevents+0x143/0x2d0 +[ 9849.517479] ? percpu_ref_put_many.constprop.0+0x8f/0x210 +[ 9849.517779] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.518073] ? do_syscall_64+0x25e/0x1520 +[ 9849.518291] ? __kasan_check_read+0x11/0x20 +[ 9849.518519] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.518799] ? do_syscall_64+0x27c/0x1520 +[ 9849.519024] ? local_clock_noinstr+0xf/0x120 +[ 9849.519262] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.519544] ? do_syscall_64+0x25e/0x1520 +[ 9849.519781] ? __kasan_check_read+0x11/0x20 +[ 9849.520008] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520273] ? do_syscall_64+0x27c/0x1520 +[ 9849.520491] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520767] ? irqentry_exit+0x10c/0x6c0 +[ 9849.520984] ? trace_hardirqs_off+0x86/0x1b0 +[ 9849.521224] ? exc_page_fault+0xab/0x130 +[ 9849.521472] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.521766] RIP: 0033:0x7e36cbd14907 +[ 9849.521989] Code: 10 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 9849.523057] RSP: 002b:00007ffff2d2a968 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 9849.523484] RAX: ffffffffffffffda RBX: 000000000000e549 RCX: 00007e36cbd14907 +[ 9849.523885] RDX: 000000000000e549 RSI: 00005bd797ec6370 RDI: 0000000000000004 +[ 9849.524277] RBP: 0000000000000004 R08: 0000000000000047 R09: 00005bd797ec6370 +[ 9849.524652] R10: 0000000000000078 R11: 0000000000000246 R12: 0000000000000049 +[ 9849.525062] R13: 0000000010781a37 R14: 00005bd797ec6370 R15: 0000000000000000 +[ 9849.525447] +[ 9849.525574] Modules linked in: intel_rapl_msr intel_rapl_common intel_uncore_frequency_common intel_pmc_core pmt_telemetry pmt_discovery pmt_class intel_pmc_ssram_telemetry intel_vsec kvm_intel joydev kvm irqbypass ghash_clmulni_intel aesni_intel input_leds rapl mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 bochs qemu_fw_cfg i2c_smbus pata_acpi sch_fq_codel rbd msr parport_pc ppdev lp parport efi_pstore +[ 9849.529150] ---[ end trace 0000000000000000 ]--- +[ 9849.529502] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.530813] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.534986] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.536198] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.537718] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.539321] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.540862] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.542438] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.543996] FS: 00007e36cbe94740(0000) GS:ffff88824b899000(0000) knlGS:0000000000000000 +[ 9849.545854] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.547092] CR2: 00007e36cb3ff000 CR3: 000000011bbf6006 CR4: 0000000000772ef0 +[ 9849.548679] PKRU: 55555554 + +The race sequence: +1. Read completes -> netfs_read_collection() runs +2. netfs_wake_rreq_flag(rreq, NETFS_RREQ_IN_PROGRESS, ...) +3. netfs_wait_for_read() returns -EFAULT to netfs_write_begin() +4. The netfs_unlock_abandoned_read_pages() unlocks the folio +5. netfs_write_begin() calls folio_unlock(folio) -> VM_BUG_ON_FOLIO() + +The key reason of the issue that netfs_unlock_abandoned_read_pages() +doesn't check the flag NETFS_RREQ_NO_UNLOCK_FOLIO and executes +folio_unlock() unconditionally. This patch implements in +netfs_unlock_abandoned_read_pages() logic similar to +netfs_unlock_read_folio(). + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-8-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +cc: Ceph Development +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/read_retry.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index 48fb0303f7eee..42abf574e6788 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -249,8 +249,15 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq) + struct folio *folio = folioq_folio(p, slot); + + if (folio && !folioq_is_marked2(p, slot)) { +- trace_netfs_folio(folio, netfs_folio_trace_abandon); +- folio_unlock(folio); ++ if (folio->index == rreq->no_unlock_folio && ++ test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, ++ &rreq->flags)) { ++ _debug("no unlock"); ++ } else { ++ trace_netfs_folio(folio, ++ netfs_folio_trace_abandon); ++ folio_unlock(folio); ++ } + } + } + } +-- +2.53.0 + diff --git a/queue-6.12/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch b/queue-6.12/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch new file mode 100644 index 0000000000..252f74c754 --- /dev/null +++ b/queue-6.12/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch @@ -0,0 +1,80 @@ +From 81c91a547a7fa263a6774e10fa6c70b95d810089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:53 +0100 +Subject: netfs: Fix write streaming disablement if fd open O_RDWR + +From: David Howells + +[ Upstream commit 70a7b9193bbbfceaab5974de66834c64ccc875dd ] + +In netfs_perform_write(), "write streaming" (the caching of dirty data in +dirty but !uptodate folios) is performed to avoid the need to read data +that is just going to get immediately overwritten. However, this is/will +be disabled in three circumstances: if the fd is open O_RDWR, if fscache is +in use (as we need to round out the blocks for DIO) or if content +encryption is enabled (again for rounding out purposes). + +The idea behind disabling it if the fd is open O_RDWR is that we'd need to +flush the write-streaming page before we could read the data, particularly +through mmap. But netfs now fills in the gaps if ->read_folio() is called +on the page, so that is unnecessary. Further, this doesn't actually work +if a separate fd is open for reading. + +Fix this by removing the check for O_RDWR, thereby allowing streaming +writes even when we might read. + +This caused a number of problems with the generic/522 xfstest, but those +are now fixed. + +Fixes: c38f4e96e605 ("netfs: Provide func to copy data to pagecache for buffered write") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-17-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 19a58aea670cb..08da4c2512f52 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -197,11 +197,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + /* Decide how we should modify a folio. We might be attempting +- * to do write-streaming, in which case we don't want to a +- * local RMW cycle if we can avoid it. If we're doing local +- * caching or content crypto, we award that priority over +- * avoiding RMW. If the file is open readably, then we also +- * assume that we may want to read what we wrote. ++ * to do write-streaming, as we don't want to a local RMW cycle ++ * if we can avoid it. If we're doing local caching or content ++ * crypto, we award that priority over avoiding RMW. If the ++ * file is open readably, then we let ->read_folio() fill in ++ * the gaps. + */ + finfo = netfs_folio_info(folio); + group = netfs_folio_group(folio); +@@ -277,12 +277,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + + /* We don't want to do a streaming write on a file that loses + * caching service temporarily because the backing store got +- * culled and we don't really want to get a streaming write on +- * a file that's open for reading as ->read_folio() then has to +- * be able to flush it. ++ * culled. + */ +- if ((file->f_mode & FMODE_READ) || +- netfs_is_cache_enabled(ctx)) { ++ if (netfs_is_cache_enabled(ctx)) { + if (finfo) { + netfs_stat(&netfs_n_wh_wstream_conflict); + goto flush_content; +-- +2.53.0 + diff --git a/queue-6.12/netfs-remove-unnecessary-references-to-pages.patch b/queue-6.12/netfs-remove-unnecessary-references-to-pages.patch new file mode 100644 index 0000000000..1d4be078f4 --- /dev/null +++ b/queue-6.12/netfs-remove-unnecessary-references-to-pages.patch @@ -0,0 +1,109 @@ +From c4392b5fcf91dda424311aeb0d62d953d5f2d838 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 5 Oct 2024 19:23:05 +0100 +Subject: netfs: Remove unnecessary references to pages + +From: Matthew Wilcox (Oracle) + +[ Upstream commit e995e8b600260cff3cfaf2607a62be8bdc4aa9c7 ] + +These places should all use folios instead of pages. + +Signed-off-by: Matthew Wilcox (Oracle) +Link: https://lore.kernel.org/r/20241005182307.3190401-4-willy@infradead.org +Signed-off-by: Christian Brauner +Stable-dep-of: ccde2ac757c7 ("netfs: Fix folio->private handling in netfs_perform_write()") +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 8 ++++---- + fs/netfs/buffered_write.c | 14 +++++++------- + 2 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 1c906035fef02..3b418fed46027 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -631,7 +631,7 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len, + if (unlikely(always_fill)) { + if (pos - offset + len <= i_size) + return false; /* Page entirely before EOF */ +- zero_user_segment(&folio->page, 0, plen); ++ folio_zero_segment(folio, 0, plen); + folio_mark_uptodate(folio); + return true; + } +@@ -650,7 +650,7 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len, + + return false; + zero_out: +- zero_user_segments(&folio->page, 0, offset, offset + len, plen); ++ folio_zero_segments(folio, 0, offset, offset + len, plen); + return true; + } + +@@ -717,7 +717,7 @@ int netfs_write_begin(struct netfs_inode *ctx, + if (folio_test_uptodate(folio)) + goto have_folio; + +- /* If the page is beyond the EOF, we want to clear it - unless it's ++ /* If the folio is beyond the EOF, we want to clear it - unless it's + * within the cache granule containing the EOF, in which case we need + * to preload the granule. + */ +@@ -777,7 +777,7 @@ int netfs_write_begin(struct netfs_inode *ctx, + EXPORT_SYMBOL(netfs_write_begin); + + /* +- * Preload the data into a page we're proposing to write into. ++ * Preload the data into a folio we're proposing to write into. + */ + int netfs_prefetch_for_write(struct file *file, struct folio *folio, + size_t offset, size_t len) +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index a02bd071cee77..8ba74556bccab 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -85,13 +85,13 @@ static void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode, + * netfs_perform_write - Copy data into the pagecache. + * @iocb: The operation parameters + * @iter: The source buffer +- * @netfs_group: Grouping for dirty pages (eg. ceph snaps). ++ * @netfs_group: Grouping for dirty folios (eg. ceph snaps). + * +- * Copy data into pagecache pages attached to the inode specified by @iocb. ++ * Copy data into pagecache folios attached to the inode specified by @iocb. + * The caller must hold appropriate inode locks. + * +- * Dirty pages are tagged with a netfs_folio struct if they're not up to date +- * to indicate the range modified. Dirty pages may also be tagged with a ++ * Dirty folios are tagged with a netfs_folio struct if they're not up to date ++ * to indicate the range modified. Dirty folios may also be tagged with a + * netfs-specific grouping such that data from an old group gets flushed before + * a new one is started. + */ +@@ -226,11 +226,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + * we try to read it. + */ + if (fpos >= ctx->zero_point) { +- zero_user_segment(&folio->page, 0, offset); ++ folio_zero_segment(folio, 0, offset); + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- zero_user_segment(&folio->page, offset + copied, flen); ++ folio_zero_segment(folio, offset + copied, flen); + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); + trace = netfs_modify_and_clear; +@@ -429,7 +429,7 @@ EXPORT_SYMBOL(netfs_perform_write); + * netfs_buffered_write_iter_locked - write data to a file + * @iocb: IO state structure (file, offset, etc.) + * @from: iov_iter with data to write +- * @netfs_group: Grouping for dirty pages (eg. ceph snaps). ++ * @netfs_group: Grouping for dirty folios (eg. ceph snaps). + * + * This function does all the work needed for actually writing data to a + * file. It does all basic checks, removes SUID from the file, updates +-- +2.53.0 + diff --git a/queue-6.12/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch b/queue-6.12/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch new file mode 100644 index 0000000000..b1cbff0f0e --- /dev/null +++ b/queue-6.12/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch @@ -0,0 +1,116 @@ +From e1927394696d2cbf2b3cfbc01c643de05dd25515 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:19:27 -0500 +Subject: NFS: Use nlmclnt_shutdown_rpc_clnt() to safely shut down NLM + +From: Chuck Lever + +[ Upstream commit 840621fd2ff23ada8b9262d90477e75232566e6b ] + +A race condition exists in shutdown_store() when writing to the sysfs +"shutdown" file concurrently with nlm_shutdown_hosts_net(). Without +synchronization, the following sequence can occur: + + 1. shutdown_store() reads server->nlm_host (non-NULL) + 2. nlm_shutdown_hosts_net() acquires nlm_host_mutex, calls + rpc_shutdown_client(), sets h_rpcclnt to NULL, and potentially + frees the host via nlm_gc_hosts() + 3. shutdown_store() dereferences the now-stale or freed host + +Introduce nlmclnt_shutdown_rpc_clnt(), which acquires nlm_host_mutex +before accessing h_rpcclnt. This synchronizes with +nlm_shutdown_hosts_net() and ensures the rpc_clnt pointer remains +valid during the shutdown operation. + +This change also improves API layering: NFS client code no longer +needs to include the internal lockd header to access nlm_host fields. +The new helper resides in bind.h alongside other public lockd +interfaces. + +Reported-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 29 +++++++++++++++++++++++++++++ + fs/nfs/sysfs.c | 4 ++-- + include/linux/lockd/bind.h | 1 + + 3 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 5e6877c37f730..87c88a8f99026 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -306,6 +306,35 @@ void nlmclnt_release_host(struct nlm_host *host) + } + } + ++/* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ ++static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) ++{ ++ return true; ++} ++ ++/** ++ * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations ++ * @host: nlm_host to shut down ++ * ++ * Cancels outstanding RPC tasks and marks the client as shut down. ++ * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent ++ * races between shutdown and host destruction. Safe to call if h_rpcclnt ++ * is NULL or already shut down. ++ */ ++void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) ++{ ++ struct rpc_clnt *clnt; ++ ++ mutex_lock(&nlm_host_mutex); ++ clnt = host->h_rpcclnt; ++ if (clnt) { ++ clnt->cl_shutdown = 1; ++ rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); ++ } ++ mutex_unlock(&nlm_host_mutex); ++} ++EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); ++ + /** + * nlmsvc_lookup_host - Find an NLM host handle matching a remote client + * @rqstp: incoming NLM request +diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c +index 53d4cdf28ee00..5a772aa490d6e 100644 +--- a/fs/nfs/sysfs.c ++++ b/fs/nfs/sysfs.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + + #include "internal.h" + #include "nfs4_fs.h" +@@ -285,7 +285,7 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr, + shutdown_client(server->client_acl); + + if (server->nlm_host) +- shutdown_client(server->nlm_host->h_rpcclnt); ++ nlmclnt_shutdown_rpc_clnt(server->nlm_host); + out: + shutdown_nfs_client(server->nfs_client); + return count; +diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h +index c53c81242e727..40c124f932252 100644 +--- a/include/linux/lockd/bind.h ++++ b/include/linux/lockd/bind.h +@@ -58,6 +58,7 @@ struct nlmclnt_initdata { + extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); + extern void nlmclnt_done(struct nlm_host *host); + extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); ++extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); + + /* + * NLM client operations provide a means to modify RPC processing of NLM +-- +2.53.0 + diff --git a/queue-6.12/nfsd-fix-infinite-loop-in-layout-state-revocation.patch b/queue-6.12/nfsd-fix-infinite-loop-in-layout-state-revocation.patch new file mode 100644 index 0000000000..14a9c5cf57 --- /dev/null +++ b/queue-6.12/nfsd-fix-infinite-loop-in-layout-state-revocation.patch @@ -0,0 +1,46 @@ +From 255cef1719c832fd3d2d0e90703eb0347e2e4b20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 14:52:59 -0400 +Subject: NFSD: Fix infinite loop in layout state revocation + +From: Chuck Lever + +[ Upstream commit 4f8ef58c10bfe5f86a643c7c8331b37e69e3dae1 ] + +find_one_sb_stid() skips stids whose sc_status is non-zero, but the +SC_TYPE_LAYOUT case in nfsd4_revoke_states() never sets sc_status +before calling nfsd4_close_layout(). The retry loop therefore finds +the same layout stid on every iteration, hanging the revoker +indefinitely. + +Fixes: 1e33e1414bec ("nfsd: allow layout state to be admin-revoked.") +Reported-by: Dai Ngo +Reviewed-by: Jeff Layton +Tested-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 1a15e458b178a..2d91747297820 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1832,6 +1832,13 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) + break; + case SC_TYPE_LAYOUT: + ls = layoutstateid(stid); ++ spin_lock(&clp->cl_lock); ++ if (stid->sc_status == 0) { ++ stid->sc_status |= ++ SC_STATUS_ADMIN_REVOKED; ++ atomic_inc(&clp->cl_admin_revoked); ++ } ++ spin_unlock(&clp->cl_lock); + nfsd4_close_layout(ls); + break; + } +-- +2.53.0 + diff --git a/queue-6.12/nouveau-pci-quiesce-gpu-on-shutdown.patch b/queue-6.12/nouveau-pci-quiesce-gpu-on-shutdown.patch new file mode 100644 index 0000000000..35c3f8c75c --- /dev/null +++ b/queue-6.12/nouveau-pci-quiesce-gpu-on-shutdown.patch @@ -0,0 +1,204 @@ +From 3641c32af9711fb7c2d903bd9284b512e1242bc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 19:36:44 +0800 +Subject: nouveau: pci: quiesce GPU on shutdown + +From: Li Chen + +[ Upstream commit 310326bb7df4bba094a3fc60364c641c547fd923 ] + +Kexec reboot does not reset PCI devices. +Invoking the full DRM/TTM teardown from ->shutdown can trigger WARNs when +userspace still holds DRM file descriptors. + +Quiesce the GPU through the suspend path and then power down the PCI +function so the next kernel can re-initialize the device from a consistent +state. + +WARNING: drivers/gpu/drm/drm_mode_config.c:578 at drm_mode_config_cleanup+0x2e7/0x300, CPU#2: kexec/1300 +Call Trace: + + ? srso_return_thunk+0x5/0x5f + ? enable_work+0x3a/0x100 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +nouveau 0000:26:00.0: [drm] drm_WARN_ON(!list_empty(&fb->filp_head)) +WARNING: drivers/gpu/drm/drm_framebuffer.c:833 at drm_framebuffer_free+0x73/0xa0, CPU#2: kexec/1300 +Call Trace: + + drm_mode_config_cleanup+0x248/0x300 + ? __pfx___drm_printfn_dbg+0x10/0x10 + ? drm_mode_config_cleanup+0x1dc/0x300 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +WARNING: include/drm/ttm/ttm_resource.h:406 at nouveau_ttm_fini+0x257/0x270 [nouveau], CPU#2: kexec/1300 +Call Trace: + + nouveau_drm_device_fini+0x93/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Signed-off-by: Li Chen +Reviewed-by: Dave Airlie +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/20260121113646.111561-1-me@linux.beauty +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index 2216db0aa9d54..f7370b6b73180 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -1058,6 +1058,37 @@ nouveau_pmops_resume(struct device *dev) + return ret; + } + ++static void ++nouveau_drm_shutdown(struct pci_dev *pdev) ++{ ++ struct nouveau_drm *drm = pci_get_drvdata(pdev); ++ int ret; ++ ++ if (!drm) ++ return; ++ ++ if (drm->dev->switch_power_state == DRM_SWITCH_POWER_OFF || ++ drm->dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) ++ return; ++ ++ ret = nouveau_do_suspend(drm, false); ++ if (ret) ++ NV_ERROR(drm, "shutdown suspend failed with: %d\n", ret); ++ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ /* ++ * This is just to give the pci power transition time to settle ++ * before an immediate kexec jump. it’s mirroring the existing ++ * nouveau_pmops_suspend() behavior, which already does ++ * udelay(200) right after pci_set_power_state(..., pci_d3hot). In ++ * ->shutdown() we’re allowed to sleep, so I used usleep_range() ++ * instead of a busy-wait udelay(). ++ */ ++ usleep_range(200, 400); ++} ++ + static int + nouveau_pmops_freeze(struct device *dev) + { +@@ -1385,6 +1416,7 @@ nouveau_drm_pci_driver = { + .id_table = nouveau_drm_pci_table, + .probe = nouveau_drm_probe, + .remove = nouveau_drm_remove, ++ .shutdown = nouveau_drm_shutdown, + .driver.pm = &nouveau_pm_ops, + }; + +-- +2.53.0 + diff --git a/queue-6.12/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch b/queue-6.12/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch new file mode 100644 index 0000000000..cf59273bd2 --- /dev/null +++ b/queue-6.12/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch @@ -0,0 +1,43 @@ +From 46aa5a5997d008eb3fd50c3077cae26d096c04a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 19:23:01 +0800 +Subject: nsfs: fix wrong error code returned for pidns ioctls + +From: Zhihao Cheng + +[ Upstream commit 725ecd80688bf3c57ca9205431f2c06174ff0756 ] + +When executing NS_GET_PID_FROM_PIDNS (or similar pidns ioctls), if the +target task cannot be found in the corresponding pid_ns, the error code +should be ESRCH instead of ENOTTY. + +This bug was introduced when the extensible ioctl handling was added. +Without proper return, ret would be overwritten by the default case in +the extensible ioctl switch statement. + +Fixes: a1d220d9dafa8 ("nsfs: iterate through mount namespaces") +Signed-off-by: Zhihao Cheng +Link: https://patch.msgid.link/20260507112301.1042757-1-chengzhihao1@huawei.com +Reviewed-by: Yang Erkun +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/nsfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nsfs.c b/fs/nsfs.c +index 0f4b0fed9265f..eb232f5292f8f 100644 +--- a/fs/nsfs.c ++++ b/fs/nsfs.c +@@ -235,7 +235,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, + else + tsk = find_task_by_pid_ns(arg, pid_ns); + if (!tsk) +- break; ++ return ret; + + switch (ioctl) { + case NS_GET_PID_FROM_PIDNS: +-- +2.53.0 + diff --git a/queue-6.12/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-6.12/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..e4c5e1d42d --- /dev/null +++ b/queue-6.12/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From d7375f65b5dfa218c979731e1ad132053fc5904b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index 050b3709e0204..1a1ffe93ba10c 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1482,6 +1482,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-6.12/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch b/queue-6.12/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch new file mode 100644 index 0000000000..07b55a3fd6 --- /dev/null +++ b/queue-6.12/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch @@ -0,0 +1,56 @@ +From 68df8023c80b82f6f7d71b840d9dff87202fe0d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:57:57 +0200 +Subject: ntfs3: fix OOB write in attr_wof_frame_info() + +From: 0xkato <0xkkato@gmail.com> + +[ Upstream commit 859d777646b56dd878b136392f3d03fb8153b559 ] + +In attr_wof_frame_info(), the offset-table read range for a nonresident +WofCompressedData stream is: + + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ... + ntfs_read_run(sbi, run, addr, from, to - from); + +A crafted image sets WofCompressedData.nres.data_size to 0xfff while the +file is large enough to request frame 1024 (offset 0x400000). This gives +from=0x1000, to=0xfff. The unsigned (to - from) wraps to 0xffffffffffffffff +and ntfs_read_write_run() overflows the single-page offs_folio via memcpy. + +Triggered by pread() on a mounted NTFS image. Depending on adjacent +memory layout at the time of the overflow, KASAN reports this as +slab-out-of-bounds, use-after-free, or slab-use-after-free all at +ntfs_read_write_run(). Secondary corruption/panic paths were also observed. + +Reject the read when the offset-table page is outside the stream. + +Signed-off-by: 0xkato <0xkkato@gmail.com> +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index 4390c0e4bfb78..cddeb5425dfb9 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1471,6 +1471,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr, + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ++ if (from >= wof_size) { ++ _ntfs_bad_inode(&ni->vfs_inode); ++ err = -EINVAL; ++ goto out1; ++ } ++ + err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME, + ARRAY_SIZE(WOF_NAME), run, + from, to); +-- +2.53.0 + diff --git a/queue-6.12/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-6.12/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..22390681b6 --- /dev/null +++ b/queue-6.12/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From 2705d86eb61a91b0f253e95974d2e04c97023cac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index b50c9dff327d2..7f6d652226f3b 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -433,6 +433,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-6.12/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-6.12/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..2867ab603c --- /dev/null +++ b/queue-6.12/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 638f5961a2188cf0278f7a97d971a0b950070f43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 9e2d370b4ca81..9ee74b9e88bfd 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3959,3 +3959,4 @@ module_exit(nvme_fc_exit_module); + + MODULE_DESCRIPTION("NVMe host FC transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 913e6e5a80705..fd146bebe8491 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2433,3 +2433,4 @@ module_exit(nvme_rdma_cleanup_module); + + MODULE_DESCRIPTION("NVMe host RDMA transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 77df3432dfb78..3415d95f2531e 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -3067,3 +3067,4 @@ module_exit(nvme_tcp_cleanup_module); + + MODULE_DESCRIPTION("NVMe host TCP transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-6.12/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-6.12/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..f575adc60a --- /dev/null +++ b/queue-6.12/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From 6f52bf727a03ad545e56c22fa9939680d8ca69ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 758a187a8ab33..396b0324f5196 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3643,6 +3643,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-6.12/nvme-core-fix-parameter-name-in-comment.patch b/queue-6.12/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..d5cd483387 --- /dev/null +++ b/queue-6.12/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From 90eae267180b28e6829dc6b1cd06bcdce17ed1ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 122de4e35d450..bfaa33f1f3fc8 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2811,7 +2811,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-6.12/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch b/queue-6.12/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch new file mode 100644 index 0000000000..c9e7d6dd02 --- /dev/null +++ b/queue-6.12/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch @@ -0,0 +1,110 @@ +From 765c0d1b703ad31488bf0cbac4b98e33b40ae926 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:08:48 +0530 +Subject: nvme-loop: do not cancel I/O and admin tagset during ctrl + reset/shutdown + +From: Nilay Shroff + +[ Upstream commit 886f35201591ded7958e16fe3750871d3ca0bcdf ] + +Cancelling the I/O and admin tagsets during nvme-loop controller reset +or shutdown is unnecessary. The subsequent destruction of the I/O and +admin queues already waits for all in-flight target operations to +complete. + +Cancelling the tagsets first also opens a race window. After a request +tag has been cancelled, a late completion from the target may still +arrive before the queues are destroyed. In that case the completion path +may access a request whose tag has already been cancelled or freed, +which can lead to a kernel crash. Please see below the kernel crash +encountered while running blktests nvme/040: + +run blktests nvme/040 at 2026-03-08 06:34:27 +loop0: detected capacity change from 0 to 2097152 +nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +nvme nvme6: creating 96 I/O queues. +nvme nvme6: new ctrl: "blktests-subsystem-1" +nvme_log_error: 1 callbacks suppressed +block nvme6n1: no usable path - requeuing I/O +nvme6c6n1: Read(0x2) @ LBA 2096384, 128 blocks, Host Aborted Command (sct 0x3 / sc 0x71) +blk_print_req_error: 1 callbacks suppressed +I/O error, dev nvme6c6n1, sector 2096384 op 0x0:(READ) flags 0x2880700 phys_seg 1 prio class 2 +block nvme6n1: no usable path - requeuing I/O +Kernel attempted to read user page (236) - exploit attempt? (uid: 0) +BUG: Kernel NULL pointer dereference on read at 0x00000236 +Faulting instruction address: 0xc000000000961274 +Oops: Kernel access of bad area, sig: 11 [#1] +LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries +Modules linked in: nvme_loop nvme_fabrics loop nvmet null_blk rpadlpar_io rpaphp xsk_diag bonding rfkill nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink pseries_rng dax_pmem vmx_crypto drm drm_panel_orientation_quirks xfs mlx5_core nvme bnx2x sd_mod nd_pmem nd_btt nvme_core sg papr_scm tls libnvdimm ibmvscsi ibmveth scsi_transport_srp nvme_keyring nvme_auth mdio hkdf pseries_wdt dm_mirror dm_region_hash dm_log dm_mod fuse [last unloaded: loop] +CPU: 25 UID: 0 PID: 0 Comm: swapper/25 Kdump: loaded Not tainted 7.0.0-rc3+ #14 PREEMPT +Hardware name: IBM,9043-MRX Power11 (architected) 0x820200 0xf000007 of:IBM,FW1120.00 (RF1120_128) hv:phyp pSeries +NIP: c000000000961274 LR: c008000009af1808 CTR: c00000000096124c +REGS: c0000007ffc0f910 TRAP: 0300 Not tainted (7.0.0-rc3+) +MSR: 8000000000009033 CR: 22222222 XER: 00000000 +CFAR: c008000009af232c DAR: 0000000000000236 DSISR: 40000000 IRQMASK: 0 +GPR00: c008000009af17fc c0000007ffc0fbb0 c000000001c78100 c0000000be05cc00 +GPR04: 0000000000000001 0000000000000000 0000000000000007 0000000000000000 +GPR08: 0000000000000000 0000000000000000 0000000000000002 c008000009af2318 +GPR12: c00000000096124c c0000007ffdab880 0000000000000000 0000000000000000 +GPR16: 0000000000000010 0000000000000000 0000000000000004 0000000000000000 +GPR20: 0000000000000001 c000000002ca2b00 0000000100043bb2 000000000000000a +GPR24: 000000000000000a 0000000000000000 0000000000000000 0000000000000000 +GPR28: c000000084021d40 c000000084021d50 c0000000be05cd60 c0000000be05cc00 +NIP [c000000000961274] blk_mq_complete_request_remote+0x28/0x2d4 +LR [c008000009af1808] nvme_loop_queue_response+0x110/0x290 [nvme_loop] +Call Trace: + 0xc00000000502c640 (unreliable) + nvme_loop_queue_response+0x104/0x290 [nvme_loop] + __nvmet_req_complete+0x80/0x498 [nvmet] + nvmet_req_complete+0x24/0xf8 [nvmet] + nvmet_bio_done+0x58/0xcc [nvmet] + bio_endio+0x250/0x390 + blk_update_request+0x2e8/0x68c + blk_mq_end_request+0x30/0x5c + lo_complete_rq+0x94/0x110 [loop] + blk_complete_reqs+0x78/0x98 + handle_softirqs+0x148/0x454 + do_softirq_own_stack+0x3c/0x50 + __irq_exit_rcu+0x18c/0x1b4 + irq_exit+0x1c/0x34 + do_IRQ+0x114/0x278 + hardware_interrupt_common_virt+0x28c/0x290 + +Since the queue teardown path already guarantees that all target-side +operations have completed, cancelling the tagsets is redundant and +unsafe. So avoid cancelling the I/O and admin tagsets during controller +reset and shutdown. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Nilay Shroff +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/loop.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index a9d112d34d4f4..538ee32b7d245 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -408,7 +408,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + { + if (ctrl->ctrl.queue_count > 1) { + nvme_quiesce_io_queues(&ctrl->ctrl); +- nvme_cancel_tagset(&ctrl->ctrl); + nvme_loop_destroy_io_queues(ctrl); + } + +@@ -416,7 +415,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + if (nvme_ctrl_state(&ctrl->ctrl) == NVME_CTRL_LIVE) + nvme_disable_ctrl(&ctrl->ctrl, true); + +- nvme_cancel_admin_tagset(&ctrl->ctrl); + nvme_loop_destroy_admin_queue(ctrl); + } + +-- +2.53.0 + diff --git a/queue-6.12/nvme-tcp-teardown-circular-locking-fixes.patch b/queue-6.12/nvme-tcp-teardown-circular-locking-fixes.patch new file mode 100644 index 0000000000..36cbd906ce --- /dev/null +++ b/queue-6.12/nvme-tcp-teardown-circular-locking-fixes.patch @@ -0,0 +1,305 @@ +From 7d2b3b86af61186e0851070dc6d69c1cc259e1e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:16:28 -0700 +Subject: nvme-tcp: teardown circular locking fixes + +From: Chaitanya Kulkarni + +[ Upstream commit 26bb12b9caafa2e62d638104bf2732f610cdbb0b ] + +When a controller reset is triggered via sysfs (by writing to +/sys/class/nvme//reset_controller), the reset work tears down +and re-establishes all queues. The socket release using fput() defers +the actual cleanup to task_work delayed_fput workqueue. This deferred +cleanup can race with the subsequent queue re-allocation during reset, +potentially leading to use-after-free or resource conflicts. + +Replace fput() with __fput_sync() to ensure synchronous socket release, +guaranteeing that all socket resources are fully cleaned up before the +function returns. This prevents races during controller reset where +new queue setup may begin before the old socket is fully released. + +* Call chain during reset: + nvme_reset_ctrl_work() + -> nvme_tcp_teardown_ctrl() + -> nvme_tcp_teardown_io_queues() + -> nvme_tcp_free_io_queues() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_teardown_admin_queue() + -> nvme_tcp_free_admin_queue() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_setup_ctrl() <-- race with deferred fput + +memalloc_noreclaim_save() sets PF_MEMALLOC which is intended for tasks +performing memory reclaim work that need reserve access. While PF_MEMALLOC +prevents the task from entering direct reclaim (causing __need_reclaim() to +return false), it does not strip __GFP_IO from gfp flags. The allocator can +therefore still trigger writeback I/O when __GFP_IO remains set, which is +unsafe when the caller holds block layer locks. + +Switch to memalloc_noio_save() which sets PF_MEMALLOC_NOIO. This causes +current_gfp_context() to strip __GFP_IO|__GFP_FS from every allocation in +the scope, making it safe to allocate memory while holding elevator_lock and +set->srcu. + +* The issue can be reproduced using blktests: + + nvme_trtype=tcp ./check nvme/005 +blktests (master) # nvme_trtype=tcp ./check nvme/005 +nvme/005 (tr=tcp) (reset local loopback target) [failed] + runtime 0.725s ... 0.798s + something found in dmesg: + [ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 + + [...] + ... + (See '/root/blktests/results/nodev_tr_tcp/nvme/005.dmesg' for the entire message) +blktests (master) # cat /root/blktests/results/nodev_tr_tcp/nvme/005.dmesg +[ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 +[ 108.526983] loop0: detected capacity change from 0 to 2097152 +[ 108.555606] nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +[ 108.572531] nvmet_tcp: enabling port 0 (127.0.0.1:4420) +[ 108.613061] nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.616832] nvme nvme0: creating 48 I/O queues. +[ 108.630791] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.661892] nvme nvme0: new ctrl: NQN "blktests-subsystem-1", addr 127.0.0.1:4420, hostnqn: nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349 +[ 108.746639] nvmet: Created nvm controller 2 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.748466] nvme nvme0: creating 48 I/O queues. +[ 108.802984] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.829983] nvme nvme0: Removing ctrl: NQN "blktests-subsystem-1" +[ 108.854288] block nvme0n1: no available path - failing I/O +[ 108.854344] block nvme0n1: no available path - failing I/O +[ 108.854373] Buffer I/O error on dev nvme0n1, logical block 1, async page read + +[ 108.891693] ====================================================== +[ 108.895912] WARNING: possible circular locking dependency detected +[ 108.900184] 6.17.0nvme+ #3 Tainted: G N +[ 108.903913] ------------------------------------------------------ +[ 108.908171] nvme/2734 is trying to acquire lock: +[ 108.911957] ffff88810210e610 (set->srcu){.+.+}-{0:0}, at: __synchronize_srcu+0x17/0x170 +[ 108.917587] + but task is already holding lock: +[ 108.921570] ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 108.927361] + which lock already depends on the new lock. + +[ 108.933018] + the existing dependency chain (in reverse order) is: +[ 108.938223] + -> #4 (&q->elevator_lock){+.+.}-{4:4}: +[ 108.942988] __mutex_lock+0xa2/0x1150 +[ 108.945873] elevator_change+0xa8/0x1c0 +[ 108.948925] elv_iosched_store+0xdf/0x140 +[ 108.952043] kernfs_fop_write_iter+0x16a/0x220 +[ 108.955367] vfs_write+0x378/0x520 +[ 108.957598] ksys_write+0x67/0xe0 +[ 108.959721] do_syscall_64+0x76/0xbb0 +[ 108.962052] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 108.965145] + -> #3 (&q->q_usage_counter(io)){++++}-{0:0}: +[ 108.968923] blk_alloc_queue+0x30e/0x350 +[ 108.972117] blk_mq_alloc_queue+0x61/0xd0 +[ 108.974677] scsi_alloc_sdev+0x2a0/0x3e0 +[ 108.977092] scsi_probe_and_add_lun+0x1bd/0x430 +[ 108.979921] __scsi_add_device+0x109/0x120 +[ 108.982504] ata_scsi_scan_host+0x97/0x1c0 +[ 108.984365] async_run_entry_fn+0x2d/0x130 +[ 108.986109] process_one_work+0x20e/0x630 +[ 108.987830] worker_thread+0x184/0x330 +[ 108.989473] kthread+0x10a/0x250 +[ 108.990852] ret_from_fork+0x297/0x300 +[ 108.992491] ret_from_fork_asm+0x1a/0x30 +[ 108.994159] + -> #2 (fs_reclaim){+.+.}-{0:0}: +[ 108.996320] fs_reclaim_acquire+0x99/0xd0 +[ 108.998058] kmem_cache_alloc_node_noprof+0x4e/0x3c0 +[ 109.000123] __alloc_skb+0x15f/0x190 +[ 109.002195] tcp_send_active_reset+0x3f/0x1e0 +[ 109.004038] tcp_disconnect+0x50b/0x720 +[ 109.005695] __tcp_close+0x2b8/0x4b0 +[ 109.007227] tcp_close+0x20/0x80 +[ 109.008663] inet_release+0x31/0x60 +[ 109.010175] __sock_release+0x3a/0xc0 +[ 109.011778] sock_close+0x14/0x20 +[ 109.013263] __fput+0xee/0x2c0 +[ 109.014673] delayed_fput+0x31/0x50 +[ 109.016183] process_one_work+0x20e/0x630 +[ 109.017897] worker_thread+0x184/0x330 +[ 109.019543] kthread+0x10a/0x250 +[ 109.020929] ret_from_fork+0x297/0x300 +[ 109.022565] ret_from_fork_asm+0x1a/0x30 +[ 109.024194] + -> #1 (sk_lock-AF_INET-NVME){+.+.}-{0:0}: +[ 109.026634] lock_sock_nested+0x2e/0x70 +[ 109.028251] tcp_sendmsg+0x1a/0x40 +[ 109.029783] sock_sendmsg+0xed/0x110 +[ 109.031321] nvme_tcp_try_send_cmd_pdu+0x13e/0x260 [nvme_tcp] +[ 109.034263] nvme_tcp_try_send+0xb3/0x330 [nvme_tcp] +[ 109.036375] nvme_tcp_queue_rq+0x342/0x3d0 [nvme_tcp] +[ 109.038528] blk_mq_dispatch_rq_list+0x297/0x800 +[ 109.040448] __blk_mq_sched_dispatch_requests+0x3db/0x5f0 +[ 109.042677] blk_mq_sched_dispatch_requests+0x29/0x70 +[ 109.044787] blk_mq_run_work_fn+0x76/0x1b0 +[ 109.046535] process_one_work+0x20e/0x630 +[ 109.048245] worker_thread+0x184/0x330 +[ 109.049890] kthread+0x10a/0x250 +[ 109.051331] ret_from_fork+0x297/0x300 +[ 109.053024] ret_from_fork_asm+0x1a/0x30 +[ 109.054740] + -> #0 (set->srcu){.+.+}-{0:0}: +[ 109.056850] __lock_acquire+0x1468/0x2210 +[ 109.058614] lock_sync+0xa5/0x110 +[ 109.060048] __synchronize_srcu+0x49/0x170 +[ 109.061802] elevator_switch+0xc9/0x330 +[ 109.063950] elevator_change+0x128/0x1c0 +[ 109.065675] elevator_set_none+0x4c/0x90 +[ 109.067316] blk_unregister_queue+0xa8/0x110 +[ 109.069165] __del_gendisk+0x14e/0x3c0 +[ 109.070824] del_gendisk+0x75/0xa0 +[ 109.072328] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.074365] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.076652] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.078775] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.081009] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.083082] kernfs_fop_write_iter+0x16a/0x220 +[ 109.085009] vfs_write+0x378/0x520 +[ 109.086539] ksys_write+0x67/0xe0 +[ 109.087982] do_syscall_64+0x76/0xbb0 +[ 109.089577] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.091665] + other info that might help us debug this: + +[ 109.095478] Chain exists of: + set->srcu --> &q->q_usage_counter(io) --> &q->elevator_lock + +[ 109.099544] Possible unsafe locking scenario: + +[ 109.101708] CPU0 CPU1 +[ 109.103402] ---- ---- +[ 109.105103] lock(&q->elevator_lock); +[ 109.106530] lock(&q->q_usage_counter(io)); +[ 109.109022] lock(&q->elevator_lock); +[ 109.111391] sync(set->srcu); +[ 109.112586] + *** DEADLOCK *** + +[ 109.114772] 5 locks held by nvme/2734: +[ 109.116189] #0: ffff888101925410 (sb_writers#4){.+.+}-{0:0}, at: ksys_write+0x67/0xe0 +[ 109.119143] #1: ffff88817a914e88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x10f/0x220 +[ 109.123141] #2: ffff8881046313f8 (kn->active#185){++++}-{0:0}, at: sysfs_remove_file_self+0x26/0x50 +[ 109.126543] #3: ffff88810470e1d0 (&set->update_nr_hwq_lock){++++}-{4:4}, at: del_gendisk+0x6d/0xa0 +[ 109.129891] #4: ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 109.133149] + stack backtrace: +[ 109.134817] CPU: 6 UID: 0 PID: 2734 Comm: nvme Tainted: G N 6.17.0nvme+ #3 PREEMPT(voluntary) +[ 109.134819] Tainted: [N]=TEST +[ 109.134820] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 +[ 109.134821] Call Trace: +[ 109.134823] +[ 109.134824] dump_stack_lvl+0x75/0xb0 +[ 109.134828] print_circular_bug+0x26a/0x330 +[ 109.134831] check_noncircular+0x12f/0x150 +[ 109.134834] __lock_acquire+0x1468/0x2210 +[ 109.134837] ? __synchronize_srcu+0x17/0x170 +[ 109.134838] lock_sync+0xa5/0x110 +[ 109.134840] ? __synchronize_srcu+0x17/0x170 +[ 109.134842] __synchronize_srcu+0x49/0x170 +[ 109.134843] ? mark_held_locks+0x49/0x80 +[ 109.134845] ? _raw_spin_unlock_irqrestore+0x2d/0x60 +[ 109.134847] ? kvm_clock_get_cycles+0x14/0x30 +[ 109.134853] ? ktime_get_mono_fast_ns+0x36/0xb0 +[ 109.134858] elevator_switch+0xc9/0x330 +[ 109.134860] elevator_change+0x128/0x1c0 +[ 109.134862] ? kernfs_put.part.0+0x86/0x290 +[ 109.134864] elevator_set_none+0x4c/0x90 +[ 109.134866] blk_unregister_queue+0xa8/0x110 +[ 109.134868] __del_gendisk+0x14e/0x3c0 +[ 109.134870] del_gendisk+0x75/0xa0 +[ 109.134872] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.134879] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.134887] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.134893] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.134899] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.134905] kernfs_fop_write_iter+0x16a/0x220 +[ 109.134908] vfs_write+0x378/0x520 +[ 109.134911] ksys_write+0x67/0xe0 +[ 109.134913] do_syscall_64+0x76/0xbb0 +[ 109.134915] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.134916] RIP: 0033:0x7fd68a737317 +[ 109.134917] Code: 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 109.134919] RSP: 002b:00007ffded1546d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 109.134920] RAX: ffffffffffffffda RBX: 000000000054f7e0 RCX: 00007fd68a737317 +[ 109.134921] RDX: 0000000000000001 RSI: 00007fd68a855719 RDI: 0000000000000003 +[ 109.134921] RBP: 0000000000000003 R08: 0000000030407850 R09: 00007fd68a7cd4e0 +[ 109.134922] R10: 00007fd68a65b130 R11: 0000000000000246 R12: 00007fd68a855719 +[ 109.134923] R13: 00000000304074c0 R14: 00000000304074c0 R15: 0000000030408660 +[ 109.134926] +[ 109.962756] Key type psk unregistered + +Reviewed-by: Christoph Hellwig +Reviewed-by: Sagi Grimberg +Reviewed-by: Hannes Reinecke +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 3415d95f2531e..674604a1c624b 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1466,7 +1466,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) + { + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; +- unsigned int noreclaim_flag; ++ unsigned int noio_flag; + + if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) + return; +@@ -1476,11 +1476,25 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) + + page_frag_cache_drain(&queue->pf_cache); + +- noreclaim_flag = memalloc_noreclaim_save(); +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /** ++ * Prevent memory reclaim from triggering block I/O during socket ++ * teardown. The socket release path fput -> tcp_close -> ++ * tcp_disconnect -> tcp_send_active_reset may allocate memory, and ++ * allowing reclaim to issue I/O could deadlock if we're being called ++ * from block device teardown (e.g., del_gendisk -> elevator cleanup) ++ * which holds locks that the I/O completion path needs. ++ */ ++ noio_flag = memalloc_noio_save(); ++ ++ /** ++ * Release the socket synchronously. During reset in ++ * nvme_reset_ctrl_work(), queue teardown is immediately followed by ++ * re-allocation. fput() defers socket cleanup to delayed_fput_work ++ * in workqueue context, which can race with new queue setup. ++ */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; +- memalloc_noreclaim_restore(noreclaim_flag); ++ memalloc_noio_restore(noio_flag); + + kfree(queue->pdu); + mutex_destroy(&queue->send_mutex); +@@ -1940,8 +1954,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, + if (queue->hdr_digest || queue->data_digest) + nvme_tcp_free_crypto(queue); + err_sock: +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /* Use sync variant - see nvme_tcp_free_queue() for explanation */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; + err_destroy_mutex: + mutex_destroy(&queue->send_mutex); +-- +2.53.0 + diff --git a/queue-6.12/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch b/queue-6.12/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch new file mode 100644 index 0000000000..70361f91a1 --- /dev/null +++ b/queue-6.12/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch @@ -0,0 +1,48 @@ +From f98f35f5e79b8cf1f1b2d43f1d6e3a90fb8b27fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:56:58 -0400 +Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error + path + +From: Shivam Kumar + +[ Upstream commit 4606467a75cfc16721937272ed29462a750b60c8 ] + +In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, +nvmet_req_uninit() is called unconditionally. However, if the command +arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() +had returned false and percpu_ref_tryget_live() was never executed. The +unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a +refcount underflow, leading to a WARNING in +percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and +eventually a permanent workqueue deadlock. + +Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling +nvmet_req_uninit(), matching the existing pattern in +nvmet_tcp_execute_request(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Shivam Kumar +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 6c64af6a7c07a..f8a9eba261204 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1383,7 +1383,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + queue->idx, cmd->req.cmd->common.command_id, + queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), + le32_to_cpu(cmd->exp_ddgst)); +- nvmet_req_uninit(&cmd->req); ++ if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) ++ nvmet_req_uninit(&cmd->req); + nvmet_tcp_free_cmd_buffers(cmd); + nvmet_tcp_fatal_error(queue); + ret = -EPROTO; +-- +2.53.0 + diff --git a/queue-6.12/nvmet-tcp-don-t-free-sq-on-authentication-success.patch b/queue-6.12/nvmet-tcp-don-t-free-sq-on-authentication-success.patch new file mode 100644 index 0000000000..dc4ce619f3 --- /dev/null +++ b/queue-6.12/nvmet-tcp-don-t-free-sq-on-authentication-success.patch @@ -0,0 +1,59 @@ +From 4d65f9cb9e9431707549339c0d6071dfc92bdc5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 15:17:53 +1000 +Subject: nvmet-tcp: Don't free SQ on authentication success + +From: Alistair Francis + +[ Upstream commit 2e6eb6b277f593b98f151ea8eff1beb558bbea3b ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +This patch ensures we don't free the TLS key on success as we might need +it again in the future. + +Signed-off-by: Alistair Francis +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Wilfred Mallawa +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/fabrics-cmd-auth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c +index 3f2857c17d956..4c5fd7d271453 100644 +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -342,9 +342,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) + goto complete; + } + /* Final states, clear up variables */ +- nvmet_auth_sq_free(req->sq); +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { ++ nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); ++ } + + complete: + nvmet_req_complete(req, status); +@@ -515,9 +516,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) + status = nvmet_copy_to_sgl(req, 0, d, al); + kfree(d); + done: +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) +- nvmet_auth_sq_free(req->sq); +- else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { + nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); + } +-- +2.53.0 + diff --git a/queue-6.12/objtool-support-clang-rax-drap-sequence.patch b/queue-6.12/objtool-support-clang-rax-drap-sequence.patch new file mode 100644 index 0000000000..1b671b191d --- /dev/null +++ b/queue-6.12/objtool-support-clang-rax-drap-sequence.patch @@ -0,0 +1,113 @@ +From a6ac90609871ddee11f234013de41cb833f05478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 17:47:56 -0700 +Subject: objtool: Support Clang RAX DRAP sequence + +From: Josh Poimboeuf + +[ Upstream commit 96f3b16a9de552538b810f773645d43f3b661b50 ] + +Recent Clang can use RAX as a temporary register for the DRAP stack +alignment sequence. Add support for that. + +Fixes the following warning: + + vmlinux.o: error: objtool: vmw_host_printf+0xd: unknown CFA base reg 0 + +Closes: https://lore.kernel.org/cefefdd1-7b82-406d-8ff4-e4b167e45ee6@app.fastmail.com +Reported-by: Arnd Bergmann +Signed-off-by: Josh Poimboeuf +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/3f33dc720b83dc6d3a2b7094f75a5c90a0b1cbc5.1773708458.git.jpoimboe@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/orc_types.h | 1 + + arch/x86/kernel/unwind_orc.c | 8 ++++++++ + tools/arch/x86/include/asm/orc_types.h | 1 + + tools/objtool/arch/x86/decode.c | 3 +++ + tools/objtool/arch/x86/orc.c | 5 +++++ + 5 files changed, 18 insertions(+) + +diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h +index 46d7e06763c9f..c34a21f32cf57 100644 +--- a/arch/x86/include/asm/orc_types.h ++++ b/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c +index d4705a348a804..e98f12df1a2c1 100644 +--- a/arch/x86/kernel/unwind_orc.c ++++ b/arch/x86/kernel/unwind_orc.c +@@ -563,6 +563,14 @@ bool unwind_next_frame(struct unwind_state *state) + } + break; + ++ case ORC_REG_AX: ++ if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) { ++ orc_warn_current("missing AX value at %pB\n", ++ (void *)state->ip); ++ goto err; ++ } ++ break; ++ + default: + orc_warn("unknown SP base reg %d at %pB\n", + orc->sp_reg, (void *)state->ip); +diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h +index 46d7e06763c9f..c34a21f32cf57 100644 +--- a/tools/arch/x86/include/asm/orc_types.h ++++ b/tools/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c +index f96b7b47babd5..c9d0d7579e641 100644 +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -809,6 +809,9 @@ int arch_decode_hint_reg(u8 sp_reg, int *base) + case ORC_REG_DX: + *base = CFI_DX; + break; ++ case ORC_REG_AX: ++ *base = CFI_AX; ++ break; + default: + return -1; + } +diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c +index b6cd943e87f93..5ce06b50033cb 100644 +--- a/tools/objtool/arch/x86/orc.c ++++ b/tools/objtool/arch/x86/orc.c +@@ -71,6 +71,9 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct + case CFI_DX: + orc->sp_reg = ORC_REG_DX; + break; ++ case CFI_AX: ++ orc->sp_reg = ORC_REG_AX; ++ break; + default: + WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); + return -1; +@@ -139,6 +142,8 @@ static const char *reg_name(unsigned int reg) + return "bp(ind)"; + case ORC_REG_SP_INDIRECT: + return "sp(ind)"; ++ case ORC_REG_AX: ++ return "ax"; + default: + return "?"; + } +-- +2.53.0 + diff --git a/queue-6.12/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch b/queue-6.12/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch new file mode 100644 index 0000000000..de3a2dfa6c --- /dev/null +++ b/queue-6.12/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch @@ -0,0 +1,48 @@ +From f223c37b42c35a79047e38915d5546cc9316e309 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 02:08:06 +0000 +Subject: orangefs: add usercopy whitelist to orangefs_op_cache + +From: Ziyi Guo + +[ Upstream commit f855f4ab123b2b9c93465288c03fbb07a5903bb3 ] + +orangefs_op_cache is created with kmem_cache_create(), which provides +no usercopy whitelist. orangefs_devreq_read() copies the tag and upcall +fields directly from slab objects to userspace via copy_to_user(). With +CONFIG_HARDENED_USERCOPY enabled, this triggers usercopy_abort(). + +Switch to kmem_cache_create_usercopy() with a whitelist covering the +tag and upcall fields, matching the pattern already used by +orangefs_inode_cache in super.c. + +Signed-off-by: Ziyi Guo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/orangefs-cache.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c +index e75e173a91862..0bdb99e897447 100644 +--- a/fs/orangefs/orangefs-cache.c ++++ b/fs/orangefs/orangefs-cache.c +@@ -19,10 +19,14 @@ static struct kmem_cache *op_cache; + + int op_cache_initialize(void) + { +- op_cache = kmem_cache_create("orangefs_op_cache", ++ op_cache = kmem_cache_create_usercopy("orangefs_op_cache", + sizeof(struct orangefs_kernel_op_s), + 0, + 0, ++ offsetof(struct orangefs_kernel_op_s, tag), ++ offsetof(struct orangefs_kernel_op_s, upcall) + ++ sizeof(struct orangefs_upcall_s) - ++ offsetof(struct orangefs_kernel_op_s, tag), + NULL); + + if (!op_cache) { +-- +2.53.0 + diff --git a/queue-6.12/orangefs-validate-getxattr-response-length.patch b/queue-6.12/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..b5921ee1b0 --- /dev/null +++ b/queue-6.12/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From 00c302618c4ac997ee7db3250635e7728d5410cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index eee3c5ed1bbbb..2366770c2b750 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-6.12/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch b/queue-6.12/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch new file mode 100644 index 0000000000..1cc0a8174a --- /dev/null +++ b/queue-6.12/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch @@ -0,0 +1,78 @@ +From a1395c241abe93727aa14595d82237e0522b66b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 18:07:25 -0400 +Subject: orangefs_readahead: don't overflow the bufmap slot. + +From: Mike Marshall + +[ Upstream commit 415e507cdefc510c01de8ab6644163327ee9a5d0 ] + +generic/340 showed that this caller of wait_for_direct_io was +sometimes asking for more than a bufmap slot could hold. This splits +the calls up if needed. + +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/inode.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index 63d7c1ca0dfd3..b8c5059e973fb 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -245,6 +245,8 @@ static void orangefs_readahead(struct readahead_control *rac) + loff_t new_start = readahead_pos(rac); + int ret; + size_t new_len = 0; ++ size_t this_size; ++ size_t remaining; + + loff_t bytes_remaining = inode->i_size - readahead_pos(rac); + loff_t pages_remaining = bytes_remaining / PAGE_SIZE; +@@ -260,17 +262,33 @@ static void orangefs_readahead(struct readahead_control *rac) + offset = readahead_pos(rac); + i_pages = &rac->mapping->i_pages; + +- iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); ++ iov_iter_xarray(&iter, ITER_DEST, i_pages, ++ offset, readahead_length(rac)); + +- /* read in the pages. */ +- if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, +- &offset, &iter, readahead_length(rac), +- inode->i_size, NULL, NULL, rac->file)) < 0) +- gossip_debug(GOSSIP_FILE_DEBUG, +- "%s: wait_for_direct_io failed. \n", __func__); +- else +- ret = 0; ++ remaining = readahead_length(rac); ++ while (remaining) { ++ if (remaining > 4194304) ++ this_size = 4194304; ++ else ++ this_size = remaining; ++ ++ /* read in the pages. */ ++ if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, ++ &offset, &iter, this_size, ++ inode->i_size, NULL, NULL, rac->file)) < 0) { ++ gossip_debug(GOSSIP_FILE_DEBUG, ++ "%s: wait_for_direct_io failed. :%d: \n", ++ __func__, ret); ++ goto cleanup; ++ } else { ++ ret = 0; ++ } ++ ++ remaining -= this_size; ++ offset += this_size; ++ } + ++cleanup: + /* clean up. */ + while ((folio = readahead_folio(rac))) { + if (!ret) +-- +2.53.0 + diff --git a/queue-6.12/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-6.12/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..00f4f127f8 --- /dev/null +++ b/queue-6.12/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From aadb2669cce7ad54068ed0b5fa508940dae00db4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index 997841c698935..76d6d38a3802a 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -79,7 +79,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index ed645c7a4e4b4..9e6d608cc85bc 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -43,6 +43,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -74,7 +83,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -167,7 +177,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -189,7 +200,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -223,6 +235,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -287,7 +309,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 825e6b3056f15..1351864ea6709 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -72,12 +72,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-6.12/pci-avoid-flr-for-amd-npu-device.patch b/queue-6.12/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..c8b7aa4aa5 --- /dev/null +++ b/queue-6.12/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From 0f8b04b7fd79c8c11df68bfb0b1268f7d39bd590 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 3d05ea35c536f..e2921d9f2ec6b 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5566,6 +5566,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * Mediatek MT7922 802.11ax PCI Express Wireless Network Adapter +@@ -5578,6 +5579,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MEDIATEK, 0x0616, quirk_no_flr); +-- +2.53.0 + diff --git a/queue-6.12/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch b/queue-6.12/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch new file mode 100644 index 0000000000..f08bbd38f1 --- /dev/null +++ b/queue-6.12/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch @@ -0,0 +1,42 @@ +From 65a1b6fa5ca5bad824ea0741f4fcb1dfbdd2bda0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 14:52:11 -0500 +Subject: PCI/DPC: Hold pci_dev reference during error recovery + +From: Sizhe Liu + +[ Upstream commit a1ed752bc7cb77b740cee671567d9508ae74becd ] + +The AER and EDR error handling paths hold a reference on the pci_dev during +recovery. Hold a reference during the DPC recovery path as well. + +Signed-off-by: Sizhe Liu +[bhelgaas: split to separate patch] +Signed-off-by: Bjorn Helgaas +https://patch.msgid.link/20260214081130.1878424-1-liusizhe5@huawei.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/dpc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index cdc54315d879f..8e1c960f69709 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -369,11 +369,13 @@ static irqreturn_t dpc_handler(int irq, void *context) + return IRQ_HANDLED; + } + ++ pci_dev_get(pdev); + dpc_process_error(pdev); + + /* We configure DPC so it only triggers on ERR_FATAL */ + pcie_do_recovery(pdev, pci_channel_io_frozen, dpc_reset_link); + ++ pci_dev_put(pdev); + return IRQ_HANDLED; + } + +-- +2.53.0 + diff --git a/queue-6.12/pci-prevent-assignment-to-unsupported-bridge-windows.patch b/queue-6.12/pci-prevent-assignment-to-unsupported-bridge-windows.patch new file mode 100644 index 0000000000..ad10e446f2 --- /dev/null +++ b/queue-6.12/pci-prevent-assignment-to-unsupported-bridge-windows.patch @@ -0,0 +1,76 @@ +From 93183e3905c9d27b60fcbdda3a3762e429adb304 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:53:32 +0000 +Subject: PCI: Prevent assignment to unsupported bridge windows + +From: Ahmed Naseef + +[ Upstream commit 92427ab4378faa168d6953d0f8574b8fc1edcc14 ] + +Previously, pci_read_bridge_io() and pci_read_bridge_mmio_pref() +unconditionally set resource type flags (IORESOURCE_IO or IORESOURCE_MEM | +IORESOURCE_PREFETCH) when reading bridge window registers. For windows that +are not implemented in hardware, this may cause the allocator to assign +space for a window that doesn't exist. + +For example, the EcoNET EN7528 SoC Root Port doesn't support the +prefetchable window, but since a downstream device had a prefetchable BAR, +the allocator mistakenly assigned a prefetchable window: + + pci 0001:00:01.0: [14c3:0811] type 01 class 0x060400 PCIe Root Port + pci 0001:00:01.0: PCI bridge to [bus 01-ff] + pci 0001:00:01.0: bridge window [mem 0x28000000-0x280fffff]: assigned + pci 0001:00:01.0: bridge window [mem 0x28100000-0x282fffff pref]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28100000-0x281fffff 64bit pref]: assigned + +pci_read_bridge_windows() already detects unsupported windows by testing +register writability and sets dev->io_window/pref_window accordingly. + +Check dev->io_window/pref_window so we don't set the resource flags for +unsupported windows, which prevents the allocator from assigning space to +them. + +After this commit, the prefetchable BAR is correctly allocated from the +non-prefetchable window: + + pci 0001:00:01.0: bridge window [mem 0x28000000-0x281fffff]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28000000-0x280fffff 64bit pref]: assigned + +Suggested-by: Bjorn Helgaas +Link: https://lore.kernel.org/all/20260113210259.GA715789@bhelgaas/ +Signed-off-by: Ahmed Naseef +Signed-off-by: Caleb James DeLisle +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260312165332.569772-4-cjd@cjdns.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index d8c5a957b70e5..981884ecfa87e 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -349,6 +349,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; + ++ if (!dev->io_window) ++ return; ++ + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; + if (dev->io_window_1k) { +@@ -410,6 +413,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, + pci_bus_addr_t base, limit; + struct pci_bus_region region; + ++ if (!dev->pref_window) ++ return; ++ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-6.12/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..1cd75cccf7 --- /dev/null +++ b/queue-6.12/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From 318e25bde04543b70679db3aa6432a6423f86142 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 368c50abd4fc4..744d5c3b1adce 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -44,6 +44,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1428,6 +1429,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-6.12/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-6.12/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..f407b5d6a6 --- /dev/null +++ b/queue-6.12/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 5d35a08dea27d8958e98106e328b9006b5ce1fc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/pci/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c +index 78748e8d2dbae..0e72a4591b64c 100644 +--- a/drivers/pci/vgaarb.c ++++ b/drivers/pci/vgaarb.c +@@ -1164,6 +1164,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1195,7 +1196,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-6.12/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-6.12/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..fbd4ccb30f --- /dev/null +++ b/queue-6.12/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From fbb94d3fe5fb5f245c2d1b148faa44cded2cc2ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index d34ee6f04f18f..e64941e6ed8b5 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -451,6 +451,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-6.12/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..ec976b2104 --- /dev/null +++ b/queue-6.12/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From 9f28590c7aed015991875614cefca82668fd1416 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index debf36ce57857..a4d2e6a26ee42 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1216,6 +1216,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-realtek-fix-return-value-and-silence-log-for.patch b/queue-6.12/pinctrl-realtek-fix-return-value-and-silence-log-for.patch new file mode 100644 index 0000000000..25a2364a03 --- /dev/null +++ b/queue-6.12/pinctrl-realtek-fix-return-value-and-silence-log-for.patch @@ -0,0 +1,47 @@ +From 8f765ee9db2d48b4e3fbee78df1e1913cdaffa43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:52:32 +0800 +Subject: pinctrl: realtek: Fix return value and silence log for unsupported + configs + +From: Tzuyi Chang + +[ Upstream commit 6a6b238c66dc69cd784baf03b170c50f7e5f24d9 ] + +Treating unsupported configurations as errors causes upper layers (like the +GPIO subsystem) to interpret optional features as hard failures, aborting +operations or printing unnecessary error logs. + +For example, during gpiod_get(), the GPIO framework attempts to set +PIN_CONFIG_PERSIST_STATE. Since this driver does not support it, false +error reports are generated in dmesg. + +Fix this by returning -ENOTSUPP and demoting the log level to dev_dbg. + +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Tzuyi Chang +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 4c876d1f6ad59..9633d3deaa6f3 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -456,8 +456,8 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + break; + + default: +- dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param); +- return -EINVAL; ++ dev_dbg(data->dev, "unsupported pinconf: %d\n", (u32)param); ++ return -ENOTSUPP; + } + + ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val); +-- +2.53.0 + diff --git a/queue-6.12/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-6.12/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..470738ee0d --- /dev/null +++ b/queue-6.12/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From c8448c64e94e7972182d2a98124d2402775e1caf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 7d2f39f19acbf..2fff4a7460dd0 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-6.12/powerpc-fix-dead-default-for-guest_state_buffer_test.patch b/queue-6.12/powerpc-fix-dead-default-for-guest_state_buffer_test.patch new file mode 100644 index 0000000000..ea0246212f --- /dev/null +++ b/queue-6.12/powerpc-fix-dead-default-for-guest_state_buffer_test.patch @@ -0,0 +1,54 @@ +From 785b9b42aed3019e212f32bbbe3b25f1c2fe1e0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 17:15:45 +0100 +Subject: powerpc: fix dead default for GUEST_STATE_BUFFER_TEST + +From: Julian Braha + +[ Upstream commit aef656a0e6c01796190bb5bd2bdba1c644ed7811 ] + +The GUEST_STATE_BUFFER_TEST config option should default +to KUNIT_ALL_TESTS so that if all tests are enabled then +it is included, but currently the 'default KUNIT_ALL_TESTS' +statement is shadowed by 'def_tristate n', +meaning that this second default statement is currently dead code. + +It looks to me like the commit +6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +intended to set the default to KUNIT_ALL_TESTS, but mistakenly +missed the def_tristate. + +This dead code was found by kconfirm, a static analysis tool for Kconfig. + +Fixes: 6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +Signed-off-by: Julian Braha +Tested-by: Gautam Menghani +Reviewed-by: Amit Machhiwal +Reviewed-by: Harsh Prateek Bora +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260405161545.161006-1-julianbraha@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/Kconfig.debug | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug +index 0bbec4afc0d59..1e2b51280e602 100644 +--- a/arch/powerpc/Kconfig.debug ++++ b/arch/powerpc/Kconfig.debug +@@ -83,11 +83,10 @@ config MSI_BITMAP_SELFTEST + depends on DEBUG_KERNEL + + config GUEST_STATE_BUFFER_TEST +- def_tristate n ++ def_tristate KUNIT_ALL_TESTS + prompt "Enable Guest State Buffer unit tests" + depends on KUNIT + depends on KVM_BOOK3S_HV_POSSIBLE +- default KUNIT_ALL_TESTS + help + The Guest State Buffer is a data format specified in the PAPR. + It is by hcalls to communicate the state of L2 guests between +-- +2.53.0 + diff --git a/queue-6.12/powerpc-time-remove-redundant-preempt_disable-enable.patch b/queue-6.12/powerpc-time-remove-redundant-preempt_disable-enable.patch new file mode 100644 index 0000000000..84b349e88d --- /dev/null +++ b/queue-6.12/powerpc-time-remove-redundant-preempt_disable-enable.patch @@ -0,0 +1,98 @@ +From d80f58863c13d062532705312962184eb59adb04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:13 +0530 +Subject: powerpc/time: Remove redundant preempt_disable|enable() calls from + arch_irq_work_raise() + +From: Sayali Patil + +[ Upstream commit 31467b23823ffec1f6fff407f8e3ca9af8b7491a ] + +A kernel panic is observed when handling machine check exceptions from +real mode. + + BUG: Unable to handle kernel data access on read at 0xc00000006be21300 + Oops: Kernel access of bad area, sig: 11 [#1] + MSR: 8000000000001003 CR: 88222248 XER: 00000005 + CFAR: c00000000003ffc4 DAR: c00000006be21300 DSISR: 40000000 IRQMASK: 0 + NIP [c000000000029e40] arch_irq_work_raise+0x10/0x70 + LR [c00000000003ffc8] machine_check_queue_event+0xa8/0x150 + Call Trace: + [c0000000179d3c70] [c00000000003ff64] machine_check_queue_event+0x44/0x150 + [c0000000179d3d30] [c0000000000084e0] machine_check_early_common+0x1f0/0x2c0 + +The crash occurs because arch_irq_work_raise() calls preempt_disable() +from machine check exception (MCE) handlers running in real mode. In +this context, accessing the preempt_count can fault, leading to the panic. + +The preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +was originally added by commit 0fe1ac48bef0 ("powerpc/perf_event: Fix +oops due to perf_event_do_pending call") to avoid races while raising +irq work from exception context. + +Later, commit 471ba0e686cb ("irq_work: Do not raise an IPI when +queueing work on the local CPU") added preemption protection in +irq_work_queue() path, while commit 20b876918c06 ("irq_work: Use per +cpu atomics instead of regular atomics") added equivalent +protection in irq_work_queue_on() before reaching arch_irq_work_raise(): + + irq_work_queue() / irq_work_queue_on() + -> preempt_disable() + -> __irq_work_queue_local() + -> irq_work_raise() + -> arch_irq_work_raise() + +As a result, callers other than mce_irq_work_raise() already execute +with preemption disabled, making the additional +preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +redundant. + +The arch_irq_work_raise() function executes in NMI context when called +from MCE handler. Hence we will not be preempted or scheduled out since +we are in NMI context with MSR[EE]=0. Therefore, it is safe to remove +the preempt_disable()/preempt_enable() calls from here. + +Remove it to avoid accessing preempt_count from real mode context. + +Fixes: cc15ff327569 ("powerpc/mce: Avoid using irq_work_queue() in realmode") +Suggested-by: Mahesh Salgaonkar +Acked-by: Shrikanth Hegde +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Sayali Patil +[Maddy: Fixed the commit title] +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260513081413.222490-1-sayalip@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/time.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index 0ff9f038e800d..ce7f91172ec2b 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -458,6 +458,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); + + #endif /* 32 vs 64 bit */ + ++/* ++ * Must be called with preemption disabled since it updates ++ * per-CPU irq_work state and programs the local CPU decrementer. ++ */ + void arch_irq_work_raise(void) + { + /* +@@ -471,10 +475,8 @@ void arch_irq_work_raise(void) + * which could get tangled up if we're messing with the same state + * here. + */ +- preempt_disable(); + set_irq_work_pending_flag(); + set_dec(1); +- preempt_enable(); + } + + static void set_dec_or_work(u64 val) +-- +2.53.0 + diff --git a/queue-6.12/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-6.12/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..d125efa882 --- /dev/null +++ b/queue-6.12/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From 63512d7f763a07edb999bebbe273b6d117573a68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index c70994c6a265e..fa48e84d51c86 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3005,12 +3005,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-6.12/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch b/queue-6.12/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch new file mode 100644 index 0000000000..417041830d --- /dev/null +++ b/queue-6.12/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch @@ -0,0 +1,69 @@ +From f3ea8e047322ba1ecd8ec1e4ee852754e94c3741 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 21:51:55 +0300 +Subject: pstore: fix ftrace dump, when ECC is enabled + +From: Andrey Skvortsov + +[ Upstream commit 4ef6255cc56343bc90d82420b49dab1b11dee414 ] + +total_size is sum of record->size and record->ecc_notice_size (ECC: No +errors detected). When ECC is not used, then there is no problem. +When ECC is enabled, then ftrace dump is decoded incorrectly after +restart. + +First this affects starting offset calculation, that breaks +reading of all ftrace records. + + CPU:66 ts:51646260179894273 3818ffff80008002 fe00ffff800080f0 0x3818ffff80008002 <- 0xfe00ffff800080f0 + CPU:66 ts:56589664458375169 3818ffff80008002 ff02ffff800080f0 0x3818ffff80008002 <- 0xff02ffff800080f0 + CPU:67 ts:13194139533313 afe4ffff80008002 1ffff800080f0 0xafe4ffff80008002 <- 0x1ffff800080f0 + CPU:67 ts:13194139533313 b7d0ffff80008001 100ffff80008002 0xb7d0ffff80008001 <- 0x100ffff80008002 + CPU:67 ts:51646260179894273 8de0ffff80008001 202ffff80008002 0x8de0ffff80008001 <- 0x202ffff80008002 + +Second ECC notice message is printed like ftrace record and as a +result couple of last records are completely wrong. + +For example, when the starting offset is fixed: + + CPU:0 ts:113 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:0 ts:114 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:100 ts:28259048229270629 6f4e203a4343450a 2073726f72726520 0x6f4e203a4343450a <- 0x2073726f72726520 + +Signed-off-by: Andrey Skvortsov +Tested-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260215185156.317394-1-andrej.skvortzov@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/inode.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index 9de6b280c4f41..59e2916aba8a9 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -74,9 +74,9 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) + if (!data) + return NULL; + +- data->off = ps->total_size % REC_SIZE; ++ data->off = ps->record->size % REC_SIZE; + data->off += *pos * REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return_ptr(data); +@@ -94,7 +94,7 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos) + + (*pos)++; + data->off += REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return data; +-- +2.53.0 + diff --git a/queue-6.12/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-6.12/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..55727ab9f7 --- /dev/null +++ b/queue-6.12/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 65f93c6376d5e8c970de86ee5f6908eabde8ae0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index 14dfa6008467e..2e4d990f07ad4 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -207,6 +207,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-6.12/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-6.12/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..6d4a722781 --- /dev/null +++ b/queue-6.12/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From a5359e89047d7bf11fed8c959bb6ff4d4490a1a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 8c8688f99f0ab..be7c7b71a1843 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -28,7 +28,6 @@ + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + #define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -80,7 +79,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -151,9 +150,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -161,6 +162,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-6.12/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch b/queue-6.12/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch new file mode 100644 index 0000000000..d138c8a41d --- /dev/null +++ b/queue-6.12/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch @@ -0,0 +1,70 @@ +From eca81153a5a06c4d080b338da0ba987173f8887b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 06:36:59 +0100 +Subject: ring-buffer: Enforce read ordering of trace_buffer cpumask and + buffers + +From: Vincent Donnefort + +[ Upstream commit 20ad8b0888be392eb2c4c3654805eb8594952373 ] + +On CPU hotplug, if it is the first time a trace_buffer sees a CPU, a +ring_buffer_per_cpu will be allocated and its corresponding bit toggled +in the cpumask. Many readers check this cpumask to know if they can +safely read the ring_buffer_per_cpu but they are doing so without memory +ordering and may observe the cpumask bit set while having NULL buffer +pointer. + +Enforce the memory read ordering by sending an IPI to all online CPUs. +The hotplug path is a slow-path anyway and it saves us from adding read +barriers in numerous call sites. + +Link: https://patch.msgid.link/20260401053659.3458961-1-vdonnefort@google.com +Signed-off-by: Vincent Donnefort +Suggested-by: Steven Rostedt (Google) +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/ring_buffer.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index ccfaae8795f00..332c7968c1c24 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -7319,6 +7319,12 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu) + return 0; + } + ++static void rb_cpu_sync(void *data) ++{ ++ /* Not really needed, but documents what is happening */ ++ smp_rmb(); ++} ++ + /* + * We only allocate new buffers, never free them if the CPU goes down. + * If we were to free the buffer, then the user would lose any trace that was in +@@ -7357,7 +7363,18 @@ int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node) + cpu); + return -ENOMEM; + } +- smp_wmb(); ++ ++ /* ++ * Ensure trace_buffer readers observe the newly allocated ++ * ring_buffer_per_cpu before they check the cpumask. Instead of using a ++ * read barrier for all readers, send an IPI. ++ */ ++ if (unlikely(system_state == SYSTEM_RUNNING)) { ++ on_each_cpu(rb_cpu_sync, NULL, 1); ++ /* Not really needed, but documents what is happening */ ++ smp_wmb(); ++ } ++ + cpumask_set_cpu(cpu, buffer->cpumask); + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch b/queue-6.12/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch new file mode 100644 index 0000000000..56f3434df2 --- /dev/null +++ b/queue-6.12/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch @@ -0,0 +1,87 @@ +From 51e170634732db6887b8042f4a51702baf6ee0e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 00:52:12 -0500 +Subject: riscv: mm: Fixup no5lvl failure when vaddr is invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Guo Ren (Alibaba DAMO Academy) + +[ Upstream commit db909bd7986c10da074917af3dae83a60fa65093 ] + +Unlike no4lvl, no5lvl still continues to detect satp, which +requires va=pa mapping. When pa=0x800000000000, no5lvl +would fail in Sv48 mode due to an illegal VA value of +0x800000000000. + +So, prevent detecting the satp flow for no5lvl, when +vaddr is invalid. Add the is_vaddr_valid() function for +checking. + +Fixes: 26e7aacb83df ("riscv: Allow to downgrade paging mode from the command line") +Cc: Alexandre Ghiti +Cc: Björn Töpel +Signed-off-by: Guo Ren (Alibaba DAMO Academy) +Tested-by: Fangyu Yu +Link: https://patch.msgid.link/20260125055212.433163-1-guoren@kernel.org +[pjw@kernel.org: cleaned up commit message] +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/mm/init.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 8d167e09f1fea..8cd8bc9b82cb2 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -807,6 +807,27 @@ static void __init set_mmap_rnd_bits_max(void) + mmap_rnd_bits_max = MMAP_VA_BITS - PAGE_SHIFT - 3; + } + ++static bool __init is_vaddr_valid(unsigned long va) ++{ ++ unsigned long up = 0; ++ ++ switch (satp_mode) { ++ case SATP_MODE_39: ++ up = 1UL << 38; ++ break; ++ case SATP_MODE_48: ++ up = 1UL << 47; ++ break; ++ case SATP_MODE_57: ++ up = 1UL << 56; ++ break; ++ default: ++ return false; ++ } ++ ++ return (va < up) || (va >= (ULONG_MAX - up + 1)); ++} ++ + /* + * There is a simple way to determine if 4-level is supported by the + * underlying hardware: establish 1:1 mapping in 4-level page table mode +@@ -842,6 +863,9 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + set_satp_mode_pmd + PMD_SIZE, + PMD_SIZE, PAGE_KERNEL_EXEC); + retry: ++ if (!is_vaddr_valid(set_satp_mode_pmd)) ++ goto out; ++ + create_pgd_mapping(early_pg_dir, + set_satp_mode_pmd, + pgtable_l5_enabled ? +@@ -864,6 +888,7 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + disable_pgtable_l4(); + } + ++out: + memset(early_pg_dir, 0, PAGE_SIZE); + memset(early_p4d, 0, PAGE_SIZE); + memset(early_pud, 0, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-6.12/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch b/queue-6.12/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch new file mode 100644 index 0000000000..e0da029c5c --- /dev/null +++ b/queue-6.12/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch @@ -0,0 +1,50 @@ +From 0c4c4f6006d0d7cb07cb381f9f150326d2016d45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:47:40 +0530 +Subject: rtc: ti-k3: Add support to resume from IO DDR low power mode + +From: Akashdeep Kaur + +[ Upstream commit 0e9b12ee74c57617bb362deb3c82e35fe49694b5 ] + +Restore the RTC HW context which may be lost when system enters +certain low power mode (IO+DDR mode). +Check if the RTC registers are locked which would indicate loss of +context (reset) and restore the context as needed. + +Signed-off-by: Akashdeep Kaur +Reviewed-by: Vignesh Raghavendra +Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-ti-k3.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c +index ec759d8f7023c..e801f5b9d7574 100644 +--- a/drivers/rtc/rtc-ti-k3.c ++++ b/drivers/rtc/rtc-ti-k3.c +@@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) + static int __maybe_unused ti_k3_rtc_resume(struct device *dev) + { + struct ti_k3_rtc *priv = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (k3rtc_check_unlocked(priv)) { ++ /* RTC locked implies low power mode exit where RTC loses context */ ++ ret = k3rtc_configure(dev); ++ if (ret) ++ return ret; ++ } + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); +- return 0; ++ return ret; + } + + static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); +-- +2.53.0 + diff --git a/queue-6.12/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch b/queue-6.12/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch new file mode 100644 index 0000000000..9a7a265609 --- /dev/null +++ b/queue-6.12/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch @@ -0,0 +1,73 @@ +From bc53a804456ecf97ffff84dc9d2dbf3204f70886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:10:06 +0100 +Subject: s390/bpf: Do not increment tailcall count when prog is NULL + +From: Ilya Leoshkevich + +[ Upstream commit e4094d56c5592dd90aa619f9480265b0689ed3d9 ] + +Currently tail calling a non-existent prog results in tailcall count +increment. This is what the interpreter is doing, but this is clearly +wrong, so replace load-and-increment and compare-and-jump with load +and compare-and-jump, conditionally followed by increment and store. + +Reported-by: Hari Bathini +Signed-off-by: Ilya Leoshkevich +Link: https://lore.kernel.org/r/20260217161058.101346-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index c3ad3cf86ca64..a3093bd6de8b4 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -1865,20 +1865,21 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + jit->prg); + + /* +- * if (tail_call_cnt++ >= MAX_TAIL_CALL_CNT) ++ * if (tail_call_cnt >= MAX_TAIL_CALL_CNT) + * goto out; ++ * ++ * tail_call_cnt is read into %w0, which needs to be preserved ++ * until it's incremented and flushed. + */ + + off = jit->frame_off + + offsetof(struct prog_frame, tail_call_cnt); +- /* lhi %w0,1 */ +- EMIT4_IMM(0xa7080000, REG_W0, 1); +- /* laal %w1,%w0,off(%r15) */ +- EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); +- /* clij %w1,MAX_TAIL_CALL_CNT-1,0x2,out */ ++ /* ly %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0058, REG_W0, REG_0, REG_15, off); ++ /* clij %w0,MAX_TAIL_CALL_CNT,0xa,out */ + patch_2_clij = jit->prg; +- EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT - 1, +- 2, jit->prg); ++ EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W0, MAX_TAIL_CALL_CNT, ++ 0xa, jit->prg); + + /* + * prog = array->ptrs[index]; +@@ -1897,6 +1898,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + patch_3_brc = jit->prg; + EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); + ++ /* tail_call_cnt++; */ ++ /* ahi %w0,1 */ ++ EMIT4_IMM(0xa70a0000, REG_W0, 1); ++ /* sty %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, REG_0, REG_15, off); ++ + /* + * Restore registers before calling function + */ +-- +2.53.0 + diff --git a/queue-6.12/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch b/queue-6.12/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch new file mode 100644 index 0000000000..492d576b07 --- /dev/null +++ b/queue-6.12/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch @@ -0,0 +1,101 @@ +From cf4dc69f879b0d0079ce92c5e746103ecdf92ec9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 19:59:29 +0800 +Subject: sched: Fix incorrect schedstats for rt and dl thread + +From: Dengjun Su + +[ Upstream commit c0e1832ba6dad7057acf3f485a87e0adccc23141 ] + +For RT and DL thread, only 'set_next_task_(rt/dl)' will call +'update_stats_wait_end_(rt/dl)' to update schedstats information. +However, during the migration process, +'update_stats_wait_start_(rt/dl)' will be called twice, which +will cause the values of wait_max and wait_sum to be incorrect. +The specific output as follows: +$ cat /proc/6046/task/6046/sched | grep wait +wait_start : 0.000000 +wait_max : 496717.080029 +wait_sum : 7921540.776553 + +A complete schedstats information update flow of migrate should be +__update_stats_wait_start() [enter queue A, stage 1] -> +__update_stats_wait_end() [leave queue A, stage 2] -> +__update_stats_wait_start() [enter queue B, stage 3] -> +__update_stats_wait_end() [start running on queue B, stage 4] + + Stage 1: prev_wait_start is 0, and in the end, wait_start records the + time of entering the queue. + Stage 2: task_on_rq_migrating(p) is true, and wait_start is updated to + the waiting time on queue A. + Stage 3: prev_wait_start is the waiting time on queue A, wait_start is + the time of entering queue B, and wait_start is expected to be greater + than prev_wait_start. Under this condition, wait_start is updated to + (the moment of entering queue B) - (the waiting time on queue A). + Stage 4: the final wait time = (time when starting to run on queue B) + - (time of entering queue B) + (waiting time on queue A) = waiting + time on queue B + waiting time on queue A. + +The current problem is that stage 2 does not call __update_stats_wait_end +to update wait_start, which causes the final computed wait time = waiting +time on queue B + the moment of entering queue A, leading to incorrect +wait_max and wait_sum. + +Add 'update_stats_wait_end_(rt/dl)' in 'update_stats_dequeue_(rt/dl)' to +update schedstats information when dequeue_task. + +Signed-off-by: Dengjun Su +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260204115959.3183567-1-dengjun.su@mediatek.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 4 ++++ + kernel/sched/rt.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 1ef891f8e3f2f..6677352f7ef35 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -2154,10 +2154,14 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, + int flags) + { + struct task_struct *p = dl_task_of(dl_se); ++ struct rq *rq = rq_of_dl_rq(dl_rq); + + if (!schedstat_enabled()) + return; + ++ if (p != rq->curr) ++ update_stats_wait_end_dl(dl_rq, dl_se); ++ + if ((flags & DEQUEUE_SLEEP)) { + unsigned int state; + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index fb6edf97e60c7..cd91f2ac65ef9 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1341,13 +1341,18 @@ update_stats_dequeue_rt(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, + int flags) + { + struct task_struct *p = NULL; ++ struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!schedstat_enabled()) + return; + +- if (rt_entity_is_task(rt_se)) ++ if (rt_entity_is_task(rt_se)) { + p = rt_task_of(rt_se); + ++ if (p != rq->curr) ++ update_stats_wait_end_rt(rt_rq, rt_se); ++ } ++ + if ((flags & DEQUEUE_SLEEP) && p) { + unsigned int state; + +-- +2.53.0 + diff --git a/queue-6.12/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-6.12/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..fc7bdeedff --- /dev/null +++ b/queue-6.12/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From 664defe872631c9383a18ecc2e2a13434a2312ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-6.12/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch b/queue-6.12/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch new file mode 100644 index 0000000000..2703490554 --- /dev/null +++ b/queue-6.12/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch @@ -0,0 +1,117 @@ +From e5a51edd264dccf48d95c1e7bc0856eb9ca9e4c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:03 -0800 +Subject: scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in + lpfc_sli_abort_ring() + +From: Justin Tee + +[ Upstream commit 2da10bcaa58a389ca60f8e788180e0dca00739bc ] + +When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is +cleared but the phba->txcmplq_cnt is not reset to zero. This can +sometimes result in a phba->txcmplq_cnt that never reaches zero, which +hangs the cleanup process. + +Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also +ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_sli.c | 66 +++++++++++++----------------------- + 1 file changed, 24 insertions(+), 42 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 7dba06fa82d85..67def61074e4f 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -4562,59 +4562,41 @@ void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { + LIST_HEAD(tx_completions); +- LIST_HEAD(txcmplq_completions); ++ spinlock_t *plock; /* for transmit queue access */ + struct lpfc_iocbq *iocb, *next_iocb; + int offline; + +- if (pring->ringno == LPFC_ELS_RING) { ++ if (phba->sli_rev >= LPFC_SLI_REV4) ++ plock = &pring->ring_lock; ++ else ++ plock = &phba->hbalock; ++ ++ if (pring->ringno == LPFC_ELS_RING) + lpfc_fabric_abort_hba(phba); +- } ++ + offline = pci_channel_offline(phba->pcidev); + +- /* Error everything on txq and txcmplq +- * First do the txq. +- */ +- if (phba->sli_rev >= LPFC_SLI_REV4) { +- spin_lock_irq(&pring->ring_lock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; ++ /* Cancel everything on txq */ ++ spin_lock_irq(plock); ++ list_splice_init(&pring->txq, &tx_completions); ++ pring->txq_cnt = 0; + +- if (offline) { +- list_splice_init(&pring->txcmplq, +- &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&pring->ring_lock); ++ if (offline) { ++ /* Cancel everything on txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; ++ list_splice_init(&pring->txcmplq, &tx_completions); ++ pring->txcmplq_cnt = 0; + } else { +- spin_lock_irq(&phba->hbalock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; +- +- if (offline) { +- list_splice_init(&pring->txcmplq, &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&phba->hbalock); ++ /* Issue ABTS for everything on the txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + } ++ spin_unlock_irq(plock); + +- if (offline) { +- /* Cancel all the IOCBs from the completions list */ +- lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, +- IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); +- } else { +- /* Make sure HBA is alive */ ++ if (!offline) + lpfc_issue_hb_tmo(phba); +- } ++ + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); +-- +2.53.0 + diff --git a/queue-6.12/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-6.12/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..fc1c712366 --- /dev/null +++ b/queue-6.12/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 579531fcbcefc55b7c36125d2b0f33b8f5a6701c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 106bccaac4276..e3363a083ba77 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1132,6 +1132,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1142,22 +1162,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-6.12/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch b/queue-6.12/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch new file mode 100644 index 0000000000..85f9a65d93 --- /dev/null +++ b/queue-6.12/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch @@ -0,0 +1,38 @@ +From 389ab3e27ad2d53e2e5de681528390df093d0809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 13:41:34 -0500 +Subject: scsi: ufs: core: Disable timestamp for Kioxia THGJFJT0E25BAIP + +From: Aaron Kling + +[ Upstream commit e423f1c7195645e18945fba0bd8f0a32e39286e7 ] + +Kioxia has another product that does not support the qTimestamp +attribute. + +Signed-off-by: Aaron Kling +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260403-thgjfjt0e25baip-no-timestamp-v1-1-1ddb34225133@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/core/ufshcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 22d3cb0ddbcaa..6bfb8c1f3eeed 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -295,6 +295,9 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGLF2G9D8KBADG", + .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE }, ++ { .wmanufacturerid = UFS_VENDOR_TOSHIBA, ++ .model = "THGJFJT0E25BAIP", ++ .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGJFJT1E45BATP", + .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, +-- +2.53.0 + diff --git a/queue-6.12/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-6.12/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..5b5065e6ff --- /dev/null +++ b/queue-6.12/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From ce1d6cba2591cfb4b2129f051929893da05a1d66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index 6845da9902818..5172d33c57f13 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -1159,6 +1159,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-6.12/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-6.12/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..7c6aa4c87d --- /dev/null +++ b/queue-6.12/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 634ad55244fab6d53d14b24467682703dc7ba05a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index 5dfe4e599ad68..0e2d47e24277e 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -135,6 +135,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + const struct qcom_geni_device_data *dev_data; +@@ -238,7 +239,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1359,11 +1360,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) { + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series new file mode 100644 index 0000000000..a3b8bdc3f4 --- /dev/null +++ b/queue-6.12/series @@ -0,0 +1,311 @@ +hid-uclogic-fix-regression-of-input-name-assignment.patch +riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch +alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch +btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-make-legacy-configs-user-selectable.patch +netfilter-exclude-legacy-tables-on-preempt_rt.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-x_tables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch +test_kprobes-clear-kprobes-between-test-runs.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +ice-fix-setting-rss-vsi-hash-for-e830.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +net-lan966x-avoid-unregistering-netdev-on-register-f.patch +nfsd-fix-infinite-loop-in-layout-state-revocation.patch +irqchip-ath79-cpu-remove-unused-function.patch +ublk-reject-max_sectors-smaller-than-page_sectors-in.patch +nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch +irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch +tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch +powerpc-fix-dead-default-for-guest_state_buffer_test.patch +netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch +netfs-fix-overrun-check-in-netfs_extract_user_iter.patch +netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch +netfs-defer-the-emission-of-trace_netfs_folio.patch +netfs-fix-streaming-write-being-overwritten.patch +netfs-fix-potential-deadlock-in-write-through-mode.patch +netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch +netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch +netfs-fix-partial-invalidation-of-streaming-write-fo.patch +netfs-fix-a-few-minor-bugs-in-netfs_page_mkwrite.patch +netfs-remove-unnecessary-references-to-pages.patch +netfs-fix-folio-private-handling-in-netfs_perform_wr.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +blk-integrity-remove-seed-for-user-mapped-buffers.patch +block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch +block-recompute-nr_integrity_segments-in-blk_insert_.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +block-modify-bio_integrity_map_user-to-accept-iov_it.patch +block-drop-direction-param-from-bio_integrity_copy_u.patch +blk-integrity-use-simpler-alignment-check.patch +blk-integrity-enable-p2p-source-and-destination.patch +block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch +accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch +net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +x86-mce-add-wrapper-for-struct-mce-to-export-vendor-.patch +x86-mce-make-several-functions-return-bool.patch +x86-mce-make-four-functions-return-bool.patch +x86-mce-inject-remove-call-to-mce_notify_irq.patch +x86-mce-restore-mca-polling-interval-halving.patch +powerpc-time-remove-redundant-preempt_disable-enable.patch +net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +net-phy-dp83tc811-add-reading-of-abilities.patch +x86-xen-fix-xen_e820_swap_entry_with_ram.patch +alsa-scarlett2-add-missing-error-check-when-initiali.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +nvmet-tcp-don-t-free-sq-on-authentication-success.patch +nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch +pstore-fix-ftrace-dump-when-ecc-is-enabled.patch +exfat-fix-s_maxbytes.patch +blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch +io_uring-cancel-validate-opcode-for-ioring_async_can.patch +erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch +exfat-fix-incorrect-directory-checksum-after-rename-.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +objtool-support-clang-rax-drap-sequence.patch +s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +wifi-mac80211-set-band-information-only-for-non-mld-.patch +wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch +wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch +ipv4-validate-ipv4_devconf-attributes-properly.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch +wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch +wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch +wifi-mt76-mt7925-skip-scan-process-during-suspend.patch +wifi-mac80211-properly-handle-error-in-ieee80211_add.patch +wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch +wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch +wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch +net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-mlx5e-xsk-increase-size-for-chunk_size-param.patch +wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch +ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch +bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch +bluetooth-btmtk-add-mt7902-mcu-support.patch +bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch +bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch +bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch +nouveau-pci-quiesce-gpu-on-shutdown.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch +drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch +drm-amd-display-fix-dcn401_optimize_bandwidth.patch +dm-vdo-indexer-validate-saved-zone-count.patch +dm-vdo-slab-depot-validate-old-zone-count-on-load.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +pci-avoid-flr-for-amd-npu-device.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-ipu-bridge-add-ov5675-sensor-config.patch +media-i2c-imx258-add-missing-mutex-protection-for-fo.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch +drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch +drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +pci-dpc-hold-pci_dev-reference-during-error-recovery.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch +iommu-iova-add-null-check-in-iova_magazine_free.patch +drm-amd-display-remove-duplicate-format-modifier.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch +drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-renesas-vsp1-initialize-format-on-all-pads.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +drm-gem-dma-set-vm_dontdump-for-mmap.patch +pci-prevent-assignment-to-unsupported-bridge-windows.patch +alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +alsa-asihpi-detect-truncated-control-names.patch +dm-integrity-fix-mismatched-queue-limits.patch +alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch +drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +drm-amd-display-merge-pipes-for-validate.patch +drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch +asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +iommu-amd-invalidate-irt-cache-for-dma-aliases.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch +alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch +alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-validate-outarg-offset-and-size-in-notify-store.patch +fuse-mark-dax-inode-releases-as-blocking.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch +memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch +arm64-tegra-fix-snps-blen-properties.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +ima-define-and-use-a-digest_size-field-in-the-ima_al.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch +orangefs-validate-getxattr-response-length.patch +orangefs_readahead-don-t-overflow-the-bufmap-slot.patch +ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +hid-logitech-hidpp-fix-race-condition-when-accessing.patch +hid-playstation-validate-num_touch_reports-in-dualsh.patch +bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch +pinctrl-realtek-fix-return-value-and-silence-log-for.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +ipmi-ssif_bmc-cancel-response-timer-on-remove.patch +i3c-master-move-bus_init-error-suppression.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +thunderbolt-disable-clx-on-titan-ridge-based-devices.patch +usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch +tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch +nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +ntfs3-fix-oob-write-in-attr_wof_frame_info.patch +scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +coda_flag_children-fix-a-uaf.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch +um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch +smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch +smb-server-stop-sending-fake-security-descriptors.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +smb-client-compress-fix-counting-in-lz77-match-findi.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch +iio-abi-fix-current_trigger-description.patch +bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch +9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch +io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch +asoc-qcom-x1e80100-limit-speaker-volumes.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch +dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch +nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch +rculist-add-list_splice_rcu-for-private-lists.patch +btrfs-apply-first-key-check-for-readahead-when-possi.patch +nvme-tcp-teardown-circular-locking-fixes.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-6.12/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch b/queue-6.12/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch new file mode 100644 index 0000000000..ef6f650db0 --- /dev/null +++ b/queue-6.12/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch @@ -0,0 +1,37 @@ +From 83724d1af5488e229511f1038aa7d79872fd75e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:07 -0300 +Subject: smb: client: compress: fix bad encoding on last LZ77 flag + +From: Enzo Matsumiya + +[ Upstream commit a13e942a03feea211c67a97bc6a57f82aa56e4b6 ] + +End-of-stream flag could lead to UB because of int promotion +(overwriting signed bit). + +Fix it by changing operand from '1' to '1UL'. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index 96e8a8057a772..cdd6b53766b0a 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -221,7 +221,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + } + + flag <<= (32 - flag_count); +- flag |= (1 << (32 - flag_count)) - 1; ++ flag |= (1UL << (32 - flag_count)) - 1; + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-- +2.53.0 + diff --git a/queue-6.12/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch b/queue-6.12/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch new file mode 100644 index 0000000000..a7545e80ca --- /dev/null +++ b/queue-6.12/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch @@ -0,0 +1,131 @@ +From fa28dc3f350fcb98b322214ea592822adec76fe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:06 -0300 +Subject: smb: client: compress: fix buffer overrun in lz77_compress() + +From: Enzo Matsumiya + +[ Upstream commit 4c221711b23745e2fb961ee517e9ed96ce76f9cb ] + +@dst buffer is allocated with same size as @src, which, for good +compression cases, works fine. + +However, when compression goes bad (e.g. random bytes payloads), the +compressed size can increase significantly, and even by stopping the +main loop at 7/8 of @slen, writing leftover literals could write past +the end of @dst because of LZ77 metadata. + +To fix this, add lz77_compressed_alloc_size() helper to compute the +correct allocation size for @dst, accounting for metadata and worst +cast scenario (all literals). + +While this is overprovisioning memory, it's not only correct, but also +allows lz77_compress() main loop to run without ever checking @dst +limits (i.e. a perf improvement). + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress.c | 6 +----- + fs/smb/client/compress/lz77.c | 14 ++++---------- + fs/smb/client/compress/lz77.h | 28 ++++++++++++++++++++++++++++ + 3 files changed, 33 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c +index db709f5cd2e1f..d00f56f6c4ef3 100644 +--- a/fs/smb/client/compress.c ++++ b/fs/smb/client/compress.c +@@ -314,11 +314,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s + goto err_free; + } + +- /* +- * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8 +- * of @slen. +- */ +- dlen = slen; ++ dlen = lz77_compressed_alloc_size(slen); + dst = kvzalloc(dlen, GFP_KERNEL); + if (!dst) { + ret = -ENOMEM; +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index cdd6b53766b0a..c1e7fada6e61c 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -137,6 +137,10 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + long flag = 0; + u64 *htable; + ++ /* This is probably a bug, so throw a warning. */ ++ if (WARN_ON_ONCE(*dlen < lz77_compressed_alloc_size(slen))) ++ return -EINVAL; ++ + srcp = src; + end = src + slen; + dstp = dst; +@@ -180,15 +184,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + continue; + } + +- /* +- * Bail out if @dstp reached >= 7/8 of @slen -- already compressed badly, not worth +- * going further. +- */ +- if (unlikely(dstp - dst >= slen - (slen >> 3))) { +- *dlen = slen; +- goto out; +- } +- + dstp = lz77_write_match(dstp, &nib, dist, len); + srcp += len; + +@@ -225,7 +220,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-out: + kvfree(htable); + + if (*dlen < slen) +diff --git a/fs/smb/client/compress/lz77.h b/fs/smb/client/compress/lz77.h +index cdcb191b48a23..2603eab9e071c 100644 +--- a/fs/smb/client/compress/lz77.h ++++ b/fs/smb/client/compress/lz77.h +@@ -11,5 +11,33 @@ + + #include + ++/** ++ * lz77_compressed_alloc_size() - Compute compressed buffer size. ++ * @size: uncompressed (src) size ++ * ++ * Compute allocation size for the compressed buffer based on uncompressed size. ++ * Accounts for metadata and overprovision for the worst case scenario. ++ * ++ * LZ77 metadata is a 4-byte flag that is written: ++ * - on dst begin (pos 0) ++ * - every 32 literals or matches ++ * - on end-of-stream (possibly, if last write was another flag) ++ * ++ * Worst case scenario is an all-literal compression, which means: ++ * metadata bytes = 4 + ((@size / 32) * 4) + 4, or, simplified, (@size >> 3) + 8 ++ * ++ * The worst case scenario rarely happens, but such overprovisioning also allows lz77_compress() ++ * main loop to run without ever bound checking dst, which is a huge perf improvement, while also ++ * being safe when compression goes bad. ++ * ++ * Return: required (*) allocation size for compressed buffer. ++ * ++ * (*) checked once in the beginning of lz77_compress() ++ */ ++static __always_inline u32 lz77_compressed_alloc_size(const u32 size) ++{ ++ return size + (size >> 3) + 8; ++} ++ + int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen); + #endif /* _SMB_COMPRESS_LZ77_H */ +-- +2.53.0 + diff --git a/queue-6.12/smb-client-compress-fix-counting-in-lz77-match-findi.patch b/queue-6.12/smb-client-compress-fix-counting-in-lz77-match-findi.patch new file mode 100644 index 0000000000..ff22f17bab --- /dev/null +++ b/queue-6.12/smb-client-compress-fix-counting-in-lz77-match-findi.patch @@ -0,0 +1,78 @@ +From 86a3a6f11b19a5c48b0a164e944a907d0aed0f23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:08 -0300 +Subject: smb: client: compress: fix counting in LZ77 match finding + +From: Enzo Matsumiya + +[ Upstream commit 20d4f9efe008be1b673f43d38d3d99fb1fd4cd68 ] + +- lz77_match_len() increments @cur before checking for equality, + leading to off-by-one match len in some cases. + + Fix by moving pointers increment to inside the loop. + Also rename @wnd arg to @match (more accurate name). +- both lz77_match_len() and lz77_compress() checked for + "buf + step < end" when the correct is "<=" for such cases. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index c1e7fada6e61c..61cdf1c146127 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -48,17 +48,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v) + put_unaligned_le32(v, ptr); + } + +-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end) ++static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end) + { + const void *start = cur; + u64 diff; + + /* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */ + do { +- diff = lz77_read64(cur) ^ lz77_read64(wnd); ++ diff = lz77_read64(cur) ^ lz77_read64(match); + if (!diff) { + cur += LZ77_STEP_SIZE; +- wnd += LZ77_STEP_SIZE; ++ match += LZ77_STEP_SIZE; + + continue; + } +@@ -67,10 +67,13 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons + cur += count_trailing_zeros(diff) >> 3; + + return (cur - start); +- } while (likely(cur + LZ77_STEP_SIZE < end)); ++ } while (likely(cur + LZ77_STEP_SIZE <= end)); + +- while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++)) +- ; ++ /* Fallback to byte-by-byte comparison for last <8 bytes. */ ++ while (cur < end && lz77_read8(cur) == lz77_read8(match)) { ++ cur++; ++ match++; ++ } + + return (cur - start); + } +@@ -195,7 +198,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + flag_pos = dstp; + dstp += 4; + } +- } while (likely(srcp + LZ77_STEP_SIZE < end)); ++ } while (likely(srcp + LZ77_STEP_SIZE <= end)); + + while (srcp < end) { + u32 c = umin(end - srcp, 32 - flag_count); +-- +2.53.0 + diff --git a/queue-6.12/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-6.12/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..83a1b196ac --- /dev/null +++ b/queue-6.12/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From a6fb0adaa271cafc2ef626fd6611d788bffa85c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index 3ea35e9ea253c..c5e48280878c4 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -4916,6 +4916,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + goto free_dw; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + dw->len = len; +-- +2.53.0 + diff --git a/queue-6.12/smb-server-stop-sending-fake-security-descriptors.patch b/queue-6.12/smb-server-stop-sending-fake-security-descriptors.patch new file mode 100644 index 0000000000..c02c423604 --- /dev/null +++ b/queue-6.12/smb-server-stop-sending-fake-security-descriptors.patch @@ -0,0 +1,71 @@ +From a6f748dcfb720a30a3ec483ed3dfb1939abbe076 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 10:14:50 +0900 +Subject: smb: server: stop sending fake security descriptors + +From: Marios Makassikis + +[ Upstream commit 5efb579e0d1ee02b85e3ce2da691c88c93111060 ] + +in smb2_get_info_sec, a dummy security descriptor (SD) is returned if +the requested information is not supported. + +the code is currently wrong, as DACL_PROTECTED is set in the type field, +but there is no DACL is present. + +instead of faking a security, report a STATUS_NOT_SUPPORTED error. + +this seems to fix a "Error 0x80090006: Invalid Signature" on file +transfers with Windows 11 clients (25H2, build 26200.8246). + +capturing traffic shows that the client is sending a GET_INFO/SEC_INFO +request, with the additional_info field set to 0x20 +(ATTRIBUTE_SECURITY_INFORMATION). Returning an empty SD +(with only SELF_RELATIVE set) does not fix the error. + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 700d9da3c65a9..b72983ae9aca9 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -5726,20 +5726,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", + addition_info); + +- pntsd = kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), +- KSMBD_DEFAULT_GFP); +- if (!pntsd) +- return -ENOMEM; +- +- pntsd->revision = cpu_to_le16(1); +- pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); +- pntsd->osidoffset = 0; +- pntsd->gsidoffset = 0; +- pntsd->sacloffset = 0; +- pntsd->dacloffset = 0; +- +- secdesclen = sizeof(struct smb_ntsd); +- goto iov_pin; ++ rsp->hdr.Status = STATUS_NOT_SUPPORTED; ++ return -EINVAL; + } + + if (work->next_smb2_rcv_hdr_off) { +@@ -5806,7 +5794,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + if (rc) + goto err_out; + +-iov_pin: + rsp->OutputBufferLength = cpu_to_le32(secdesclen); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), + rsp, work->response_buf); +-- +2.53.0 + diff --git a/queue-6.12/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-6.12/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..d9c3fc23ee --- /dev/null +++ b/queue-6.12/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From 5cd42aac8475161f1628fe305ced863c80c76f38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 207d578547cd9..b4883c365ba33 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -375,7 +375,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-6.12/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-6.12/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..d29f240084 --- /dev/null +++ b/queue-6.12/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From 74e91679cfb8ac1d457fc0a7ec8a48c3a264812b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 965330eec80a8..d0b43d50b83ce 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-6.12/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-6.12/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..e2cf7cd1ea --- /dev/null +++ b/queue-6.12/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From d75d95f768860c1887fb662b490215696732db90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index bf4e5f49030b7..dd39cabb39001 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1172,7 +1172,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-6.12/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch b/queue-6.12/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch new file mode 100644 index 0000000000..bc268333a5 --- /dev/null +++ b/queue-6.12/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch @@ -0,0 +1,52 @@ +From 20c2f1c983c7ec251421c9d04ddffed1515d50ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 12:08:46 +0000 +Subject: tcp: Fix out-of-bounds access for twsk in tcp_ao_established_key(). + +From: Kuniyuki Iwashima + +[ Upstream commit 03cb001ef87b3f8d859cf7f96329acf3d6235d29 ] + +lockdep_sock_is_held() was added in tcp_ao_established_key() +by the cited commit. + +It can be called from tcp_v[46]_timewait_ack() with twsk. + +Since it does not have sk->sk_lock, the lockdep annotation +results in out-of-bound access. + + $ pahole -C tcp_timewait_sock vmlinux | grep size + /* size: 288, cachelines: 5, members: 8 */ + $ pahole -C sock vmlinux | grep sk_lock + socket_lock_t sk_lock; /* 440 192 */ + +Let's not use lockdep_sock_is_held() for TCP_TIME_WAIT. + +Fixes: 6b2d11e2d8fc ("net/tcp: Add missing lockdep annotations for TCP-AO hlist traversals") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260508120853.4098365-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_ao.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c +index 72957523c2eca..be38712265c37 100644 +--- a/net/ipv4/tcp_ao.c ++++ b/net/ipv4/tcp_ao.c +@@ -116,7 +116,8 @@ struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, + { + struct tcp_ao_key *key; + +- hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) { ++ hlist_for_each_entry_rcu(key, &ao->head, node, ++ sk_fullsock(sk) && lockdep_sock_is_held(sk)) { + if ((sndid >= 0 && key->sndid != sndid) || + (rcvid >= 0 && key->rcvid != rcvid)) + continue; +-- +2.53.0 + diff --git a/queue-6.12/test_kprobes-clear-kprobes-between-test-runs.patch b/queue-6.12/test_kprobes-clear-kprobes-between-test-runs.patch new file mode 100644 index 0000000000..a903cdccc2 --- /dev/null +++ b/queue-6.12/test_kprobes-clear-kprobes-between-test-runs.patch @@ -0,0 +1,128 @@ +From 650657fd6c16c4319da286eabe5750cce3802d95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: test_kprobes: clear kprobes between test runs + +From: Martin Kaiser + +[ Upstream commit ef5581bb30efb939cc2bf093475c6cc85258e5cd ] + +Running the kprobes sanity tests twice makes all tests fail and +eventually crashes the kernel. + +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # Totals: pass:5 fail:0 skip:0 total:5 + ok 1 kprobes_test +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # test_kprobe: EXPECTATION FAILED at lib/tests/test_kprobes.c:64 + Expected 0 == register_kprobe(&kp), but + register_kprobe(&kp) == -22 (0xffffffffffffffea) +... + Unable to handle kernel paging request ... + +The testsuite defines several kprobes and kretprobes as static variables +that are preserved across test runs. + +After register_kprobe and unregister_kprobe, a kprobe contains some +leftover data that must be cleared before the kprobe can be registered +again. The tests are setting symbol_name to define the probe location. +Address and flags must be cleared. + +The existing code clears some of the probes between subsequent tests, but +not between two test runs. The leftover data from a previous test run +makes the registrations fail in the next run. + +Move the cleanups for all kprobes into kprobes_test_init, this function +is called before each single test (including the first test of a test +run). + +Link: https://lore.kernel.org/all/20260507134615.1010905-1-martin@kaiser.cx/ + +Fixes: e44e81c5b90f ("kprobes: convert tests to kunit") +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + lib/test_kprobes.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/lib/test_kprobes.c b/lib/test_kprobes.c +index b7582010125c3..06e729e4de051 100644 +--- a/lib/test_kprobes.c ++++ b/lib/test_kprobes.c +@@ -12,6 +12,12 @@ + + #define div_factor 3 + ++#define KP_CLEAR(_kp) \ ++do { \ ++ (_kp).addr = NULL; \ ++ (_kp).flags = 0; \ ++} while (0) ++ + static u32 rand1, preh_val, posth_val; + static u32 (*target)(u32 value); + static u32 (*recursed_target)(u32 value); +@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test) + + current_test = test; + +- /* addr and flags should be cleard for reusing kprobe. */ +- kp.addr = NULL; +- kp.flags = 0; +- + KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2)); + preh_val = 0; + posth_val = 0; +@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test) + struct kretprobe *rps[2] = {&rp, &rp2}; + + current_test = test; +- /* addr and flags should be cleard for reusing kprobe. */ +- rp.kp.addr = NULL; +- rp.kp.flags = 0; + KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2)); + + krph_val = 0; +@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test) + unsigned long myretaddr = (unsigned long)__builtin_return_address(0); + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + /* + * Run the stacktrace_driver() to record correct return address in +@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + struct kretprobe *rps[2] = {&rp3, &rp4}; + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + //KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver()); + +@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + + static int kprobes_test_init(struct kunit *test) + { ++ KP_CLEAR(kp); ++ KP_CLEAR(kp2); ++ KP_CLEAR(kp_missed); ++#ifdef CONFIG_KRETPROBES ++ KP_CLEAR(rp.kp); ++ KP_CLEAR(rp2.kp); ++#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE ++ KP_CLEAR(rp3.kp); ++ KP_CLEAR(rp4.kp); ++#endif ++#endif ++ + target = kprobe_target; + target2 = kprobe_target2; + recursed_target = kprobe_recursed_target; +-- +2.53.0 + diff --git a/queue-6.12/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch b/queue-6.12/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch new file mode 100644 index 0000000000..e09a2f0390 --- /dev/null +++ b/queue-6.12/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch @@ -0,0 +1,53 @@ +From b91b61f25f9f9a99d26ddb49b2d44898f267364c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:25:57 -0800 +Subject: thunderbolt: Disable CLx on Titan Ridge-based devices with old + firmware + +From: Rene Sapiens + +[ Upstream commit 59b03d12b1f6d14d936a3ebec225f8d914dc3b70 ] + +Thunderbolt 3 devices based on Titan Ridge routers with NVM firmware +version < 0x65 have been observed to become unstable when CL states are +enabled. This can lead to link disconnect events and the device failing +to enumerate. + +Enable CLx on Titan Ridge only when the running NVM firmware version +is >= 0x65. + +Signed-off-by: Rene Sapiens +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +--- + drivers/thunderbolt/quirks.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c +index e81de9c30eac9..9f7914ac2f48c 100644 +--- a/drivers/thunderbolt/quirks.c ++++ b/drivers/thunderbolt/quirks.c +@@ -23,6 +23,9 @@ static void quirk_dp_credit_allocation(struct tb_switch *sw) + + static void quirk_clx_disable(struct tb_switch *sw) + { ++ if (tb_switch_is_titan_ridge(sw) && sw->nvm && sw->nvm->major >= 0x65) ++ return; ++ + sw->quirks |= QUIRK_NO_CLX; + tb_sw_dbg(sw, "disabling CL states\n"); + } +@@ -61,6 +64,10 @@ static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link }, + { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link }, ++ ++ /* Intel Titan Ridge CLx is unstable on early firmware versions */ ++ { 0x8086, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE, 0x0000, 0x0000, ++ quirk_clx_disable }, + /* + * Intel Goshen Ridge NVM 27 and before report wrong number of + * DP buffers. +-- +2.53.0 + diff --git a/queue-6.12/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-6.12/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..65a6532559 --- /dev/null +++ b/queue-6.12/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 3be5778f3b2ca0ccec56b33bf82660697cf8e3c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index 07729d376f018..9230cb116294a 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1711,6 +1711,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1718,7 +1721,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-6.12/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-6.12/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..66df57aa29 --- /dev/null +++ b/queue-6.12/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From 3c4fe1828d496617f362cd75cfe29985bed38a3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index deb9635cb48dc..cf4a395d905d4 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1430,9 +1430,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1555,8 +1555,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-6.12/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch b/queue-6.12/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch new file mode 100644 index 0000000000..845b4f2196 --- /dev/null +++ b/queue-6.12/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch @@ -0,0 +1,63 @@ +From 0fae8a77afde5e6cf5763ce1c2d8a299119bc441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 11:28:54 +0000 +Subject: tty: serial: samsung_tty: avoid dev_dbg deadlock + +From: Alyssa Milburn + +[ Upstream commit 43c2b86ff633c34831c8430925ba73d7c20da1ad ] + +commit a05025d0ce72 ("tty: serial: samsung_tty: use standard +debugging macros") changed the debug prints to dev_dbg, which can +result in deadlocks: + +s3c24xx_serial_set_termios can be called with the port lock, and then +calls dev_dbg, which needs the console mutex. At the same time, +s3c24xx_serial_console_write can be called with the console lock +(e.g., inside console_unlock), and needs the port lock. + +To avoid this, move one dev_dbg call and just delete the other. + +Signed-off-by: Alyssa Milburn +Link: https://patch.msgid.link/aXny9km6N1v9eoXU@zall.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/samsung_tty.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index 0d184ee2f9cec..976edb12f21c4 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -1560,12 +1560,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + ulcon |= S3C2410_LCON_PNONE; + } + +- uart_port_lock_irqsave(port, &flags); +- + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", + ulcon, quot, udivslot); + ++ uart_port_lock_irqsave(port, &flags); ++ + wr_regl(port, S3C2410_ULCON, ulcon); + wr_regl(port, S3C2410_UBRDIV, quot); + +@@ -1585,12 +1585,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + if (ourport->info->has_divslot) + wr_regl(port, S3C2443_DIVSLOT, udivslot); + +- dev_dbg(port->dev, +- "uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", +- rd_regl(port, S3C2410_ULCON), +- rd_regl(port, S3C2410_UCON), +- rd_regl(port, S3C2410_UFCON)); +- + /* + * Update the per-port timeout. + */ +-- +2.53.0 + diff --git a/queue-6.12/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch b/queue-6.12/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch new file mode 100644 index 0000000000..4418c3dde7 --- /dev/null +++ b/queue-6.12/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch @@ -0,0 +1,52 @@ +From 3d7a31c462e5c5927bfa42bd4f8e4427bb265b0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 22:48:43 +0800 +Subject: ublk: reject max_sectors smaller than PAGE_SECTORS in parameter + validation + +From: Ming Lei + +[ Upstream commit 1860c2f85922917d8a46f16a6f4bd2298ffa0fb5 ] + +blk_validate_limits() requires max_hw_sectors >= PAGE_SECTORS and fires +a WARN_ON_ONCE if this invariant is violated. ublk_validate_params() +only checked the upper bound of max_sectors against max_io_buf_bytes, +allowing userspace to pass small values (including zero) that trigger +the warning when blk_mq_alloc_disk() is called from +ublk_ctrl_start_dev(). + +Before 494ea040bcb5, ublk used blk_queue_max_hw_sectors() which silently +clamped small values up to PAGE_SECTORS. The conversion to passing +queue_limits directly to blk_mq_alloc_disk() lost that clamping and now +hits blk_validate_limits()'s WARN_ON_ONCE instead. + +Validate that max_sectors is at least PAGE_SECTORS in +ublk_validate_params() so invalid values are rejected early with +-EINVAL instead of reaching the block layer. + +Fixes: 494ea040bcb5 ("ublk: pass queue_limits to blk_mq_alloc_disk") +Signed-off-by: Ming Lei +Link: https://patch.msgid.link/20260510144843.769031-1-tom.leiming@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index c6a59f02944fc..6854b847bccef 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -540,6 +540,9 @@ static int ublk_validate_params(const struct ublk_device *ub) + if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9)) + return -EINVAL; + ++ if (p->max_sectors < PAGE_SECTORS) ++ return -EINVAL; ++ + if (ublk_dev_is_zoned(ub) && !p->chunk_sectors) + return -EINVAL; + } else +-- +2.53.0 + diff --git a/queue-6.12/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch b/queue-6.12/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch new file mode 100644 index 0000000000..584c4c5e33 --- /dev/null +++ b/queue-6.12/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch @@ -0,0 +1,60 @@ +From 6dbb0aada1d6ae152923e75e92daf19867429b63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:20:42 -0700 +Subject: um: Disable GCOV_PROFILE_ALL on 32-bit UML with Clang 20/21 + +From: Kees Cook + +[ Upstream commit 6522fe5c1b007c376fc5f2de1016c99a18b0af8e ] + +Clang 20 and 21 miscompute __builtin_object_size() when -fprofile-arcs +is active on 32-bit UML targets, which passes incorrect object size +calculations for local variables through always_inline copy_to_user() +and check_copy_size(), causing spurious compile-time errors: + + include/linux/ucopysize.h:52:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small + +The regression was introduced in LLVM commit 02b8ee281947 ("[llvm] +Improve llvm.objectsize computation by computing GEP, alloca and malloc +parameters bound"), which shipped in Clang 20. It was fixed in LLVM +by commit 45b697e610fd ("[MemoryBuiltins] Consider index type size +when aggregating gep offsets"), which was backported to the LLVM 22.x +release branch. + +The bug requires 32-bit UML + GCOV_PROFILE_ALL (which uses -fprofile-arcs), +though the exact trigger depends on optimizer decisions influenced by other +enabled configs. + +Prevent the bad combination by disabling UML's ARCH_HAS_GCOV_PROFILE_ALL +on 32-bit when using Clang 20.x or 21.x. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604030531.O6FveVgn-lkp@intel.com/ +Suggested-by: Nathan Chancellor +Assisted-by: Claude:claude-opus-4-6[1m] +Signed-off-by: Kees Cook +Link: https://patch.msgid.link/20260409052038.make.995-kees@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/Kconfig | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/um/Kconfig b/arch/um/Kconfig +index c89575d05021f..09efac857032d 100644 +--- a/arch/um/Kconfig ++++ b/arch/um/Kconfig +@@ -7,7 +7,9 @@ config UML + default y + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +- select ARCH_HAS_GCOV_PROFILE_ALL ++ # Clang 20 & 21 miscompute __builtin_object_size() under -fprofile-arcs ++ # on 32-bit, causing spurious compile-time errors in check_copy_size(). ++ select ARCH_HAS_GCOV_PROFILE_ALL if !(!64BIT && CLANG_VERSION >= 200000 && CLANG_VERSION < 220100) + select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER +-- +2.53.0 + diff --git a/queue-6.12/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch b/queue-6.12/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch new file mode 100644 index 0000000000..25293b43d2 --- /dev/null +++ b/queue-6.12/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch @@ -0,0 +1,155 @@ +From 8458412d2549963a6751603c73feb41952ed94b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 13:14:52 +0100 +Subject: usb: dwc3: Support USB3340x ULPI PHY high-speed negotiation. + +From: Ingo Rohloff + +[ Upstream commit a28de63356575612954d4e5d5f48a2488f50e16d ] + +The Microchip USB3340x ULPI PHY requires a delay when switching to the +high-speed transmitter. See: + http://ww1.microchip.com/downloads/en/DeviceDoc/80000645A.pdf + Module 2 "Device Enumeration Failure with Link IP Systems" + +For details on the behavior and fix, refer to the AMD (formerly Xilinx) +forum post: "USB stuck in full speed mode with USB3340 ULPI PHY, ZynqMP." + +This patch uses the USB PHY Vendor-ID and Product-ID to detect the +USB3340 PHY and then applies the necessary fix if this PHY is found. + +Signed-off-by: Ingo Rohloff +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260305121452.54082-2-ingo.rohloff@lauterbach.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/core.c | 20 ++++++++++++++++++++ + drivers/usb/dwc3/core.h | 4 ++++ + drivers/usb/dwc3/ulpi.c | 25 +++++++++++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 2cdb073aff724..d2473f40e1f78 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -778,6 +778,24 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + return 0; + } + ++static void dwc3_ulpi_setup(struct dwc3 *dwc) ++{ ++ int index; ++ u32 reg; ++ ++ /* Don't do anything if there is no ULPI PHY */ ++ if (!dwc->ulpi) ++ return; ++ ++ if (dwc->enable_usb2_transceiver_delay) { ++ for (index = 0; index < dwc->num_usb2_ports; index++) { ++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); ++ reg |= DWC3_GUSB2PHYCFG_XCVRDLY; ++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); ++ } ++ } ++} ++ + /** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -1352,6 +1370,8 @@ static int dwc3_core_init(struct dwc3 *dwc) + dwc->ulpi_ready = true; + } + ++ dwc3_ulpi_setup(dwc); ++ + if (!dwc->phys_ready) { + ret = dwc3_core_get_phy(dwc); + if (ret) +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index eb8b8f3e52167..bfdcd226d07ed 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -302,6 +302,7 @@ + #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) + #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) + #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) ++#define DWC3_GUSB2PHYCFG_XCVRDLY BIT(9) + #define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3) + #define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) + #define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10) +@@ -1154,6 +1155,8 @@ struct dwc3_scratchpad_array { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @enable_usb2_transceiver_delay: Set to insert a delay before the ++ * assertion of the TxValid signal during a HS Chirp. + * @sys_wakeup: set if the device may do system wakeup. + * @wakeup_configured: set if the device is configured for remote wakeup. + * @suspended: set to track suspend event due to U3/L2. +@@ -1393,6 +1396,7 @@ struct dwc3 { + unsigned dis_metastability_quirk:1; + + unsigned dis_split_quirk:1; ++ unsigned enable_usb2_transceiver_delay:1; + unsigned async_callbacks:1; + unsigned sys_wakeup:1; + unsigned wakeup_configured:1; +diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c +index f23f4c9a557e9..29a8e155e4dfa 100644 +--- a/drivers/usb/dwc3/ulpi.c ++++ b/drivers/usb/dwc3/ulpi.c +@@ -10,10 +10,13 @@ + #include + #include + #include ++#include + + #include "core.h" + #include "io.h" + ++#define USB_VENDOR_MICROCHIP 0x0424 ++ + #define DWC3_ULPI_ADDR(a) \ + ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \ + DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ +@@ -83,6 +86,26 @@ static const struct ulpi_ops dwc3_ulpi_ops = { + .write = dwc3_ulpi_write, + }; + ++static void dwc3_ulpi_detect_config(struct dwc3 *dwc) ++{ ++ struct ulpi *ulpi = dwc->ulpi; ++ ++ switch (ulpi->id.vendor) { ++ case USB_VENDOR_MICROCHIP: ++ switch (ulpi->id.product) { ++ case 0x0009: ++ /* Microchip USB3340 ULPI PHY */ ++ dwc->enable_usb2_transceiver_delay = true; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ + int dwc3_ulpi_init(struct dwc3 *dwc) + { + /* Register the interface */ +@@ -92,6 +115,8 @@ int dwc3_ulpi_init(struct dwc3 *dwc) + return PTR_ERR(dwc->ulpi); + } + ++ dwc3_ulpi_detect_config(dwc); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-6.12/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..9ad761045c --- /dev/null +++ b/queue-6.12/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From 1e5c2e8d0aa9f27d653553010a3dfd310bcc5dbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index f995cfa9b99e1..49baf24c77927 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-6.12/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-6.12/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..f57f912285 --- /dev/null +++ b/queue-6.12/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From 34c6c9953eca3e04396bca2ed7841b2a3ac6161d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8f47a3b87871..f8d1d1167ef4b 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -674,7 +674,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -682,11 +682,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.12/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-6.12/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..fcb76c11ce --- /dev/null +++ b/queue-6.12/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From 7dbba0e34ebfb685e86908d1ecb545843fbda9fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8d1d1167ef4b..a5837c0feb058 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -782,6 +782,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-6.12/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-6.12/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..af9a23ef7b --- /dev/null +++ b/queue-6.12/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From 0ac5cbd45241152f1e518c1674c1da804d8a29cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index ba9e7c616e129..f8f47a3b87871 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -677,7 +677,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -708,14 +708,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-6.12/virtiofs-add-fuse-protocol-validation.patch b/queue-6.12/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..f8e96ec79c --- /dev/null +++ b/queue-6.12/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From 6a05e6ba82e014f62c543e56ba61d91befe784ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index c81f7b888c385..d0d8582656af9 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -752,6 +752,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -762,10 +783,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct page *page; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -821,6 +838,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-6.12/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-6.12/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..15cf586cba --- /dev/null +++ b/queue-6.12/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From 924c3f5c0b6e253cd9b0c1111ad1b6ffcdeebcbf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index e1e472b3a301e..f57257cebf9c5 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -2256,10 +2256,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-6.12/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch b/queue-6.12/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch new file mode 100644 index 0000000000..fb6429d4c8 --- /dev/null +++ b/queue-6.12/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch @@ -0,0 +1,45 @@ +From 17e7e8b85507d6b5e89c00252f8aeed06798b311 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:43 +0200 +Subject: wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending + +From: Emmanuel Grumbach + +[ Upstream commit 5562b3bbeede8be25092064720e4a942e9fd3e3e ] + +Otherwise we may send garbage. + +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.2d494b0f4692.I9afd0fa6b2ea5a27118144ac4e3bbbedc2089c10@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index 2b9a684cf61d5..5a3b8b006bb70 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -937,7 +937,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) + + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + { +- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; ++ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; + struct iwl_geo_tx_power_profiles_resp *resp; + u16 len; + int ret; +@@ -989,7 +989,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) + { + u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); +- union iwl_geo_tx_power_profiles_cmd cmd; ++ union iwl_geo_tx_power_profiles_cmd cmd = {}; + u16 len; + u32 n_bands; + u32 n_profiles; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch b/queue-6.12/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch new file mode 100644 index 0000000000..f5c2ee10a4 --- /dev/null +++ b/queue-6.12/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch @@ -0,0 +1,64 @@ +From 54ab4b36929449e704843a15c05ff613afed2e9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 14:13:46 +0200 +Subject: wifi: mac80211: properly handle error in + ieee80211_add_virtual_monitor + +From: Miri Korenblit + +[ Upstream commit 876565d4a826f3f04ef36f1cef6123ed4b150aa3 ] + +In case of an error in ieee80211_add_virtual_monitor, +SDATA_STATE_RUNNING should be cleared as it was set in this function. +Do it there instead of in the error path of ieee80211_do_open. + +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260320141312.5546126313b1.I689dba2f54069b259702e8d246cedf79a73b82c6@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/iface.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 7e1b6a9d9f3ad..ead04d9e85e01 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1188,14 +1188,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) + } + } + +- set_bit(SDATA_STATE_RUNNING, &sdata->state); +- + ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); + if (ret) { + kfree(sdata); + return ret; + } + ++ set_bit(SDATA_STATE_RUNNING, &sdata->state); ++ + mutex_lock(&local->iflist_mtx); + rcu_assign_pointer(local->monitor_sdata, sdata); + mutex_unlock(&local->iflist_mtx); +@@ -1208,6 +1208,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) + mutex_unlock(&local->iflist_mtx); + synchronize_net(); + drv_remove_interface(local, sdata); ++ clear_bit(SDATA_STATE_RUNNING, &sdata->state); + kfree(sdata); + return ret; + } +@@ -1495,8 +1496,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) + sdata->bss = NULL; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + list_del(&sdata->u.vlan.list); +- /* might already be clear but that doesn't matter */ +- clear_bit(SDATA_STATE_RUNNING, &sdata->state); + return res; + } + +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch b/queue-6.12/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch new file mode 100644 index 0000000000..815679a88c --- /dev/null +++ b/queue-6.12/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch @@ -0,0 +1,53 @@ +From ba548901ddadf3f022709b9c530d3eff297003d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:28:28 +0100 +Subject: wifi: mac80211: Remove deleted sta links in + ieee80211_ml_reconf_work() + +From: Lorenzo Bianconi + +[ Upstream commit 84674b03d8bf3a850f023a98136c27909f0a2b61 ] + +Delete stale station links announced in the reconfiguration IE +transmitted by the AP in the beacon frames. + +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260309-mac80211-reconf-remove-sta-link-v2-1-1582aac720c6@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 20e5f513a27a3..3dfbaa0d76687 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -6173,6 +6173,7 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + container_of(work, struct ieee80211_sub_if_data, + u.mgd.ml_reconf_work.work); + u16 new_valid_links, new_active_links, new_dormant_links; ++ struct sta_info *sta; + int ret; + + if (!sdata->u.mgd.removed_links) +@@ -6208,6 +6209,16 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + } + } + ++ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); ++ if (sta) { ++ unsigned long removed_links = sdata->u.mgd.removed_links; ++ unsigned int link_id; ++ ++ for_each_set_bit(link_id, &removed_links, ++ IEEE80211_MLD_MAX_NUM_LINKS) ++ ieee80211_sta_free_link(sta, link_id); ++ } ++ + new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links; + + ret = ieee80211_vif_set_links(sdata, new_valid_links, +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-set-band-information-only-for-non-mld-.patch b/queue-6.12/wifi-mac80211-set-band-information-only-for-non-mld-.patch new file mode 100644 index 0000000000..eef6ed27b8 --- /dev/null +++ b/queue-6.12/wifi-mac80211-set-band-information-only-for-non-mld-.patch @@ -0,0 +1,78 @@ +From f8d7f843ce06d8697d1a53278a8261f3799e1eb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 15:31:25 +0530 +Subject: wifi: mac80211: set band information only for non-MLD when probing + stations using NULL frame + +From: Suraj P Kizhakkethil + +[ Upstream commit 73e7df69edb6f1271ea0fa876794761e6c73e76a ] + +Currently, when sending a NULL frame to probe a station, the band +information is derived from the chanctx_conf in the mac80211 vif's +bss_conf. However, for AP MLD, chanctx_conf is not assigned to the +vif's bss_conf; instead it is assigned on a per-link basis. As a result, +for AP MLD, sending a NULL packet to probe will trigger a warning. + +WARNING: net/mac80211/cfg.c:4635 at ieee80211_probe_client+0x1a8/0x1d8 [mac80211], CPU#2: hostapd/244 +Call trace: + ieee80211_probe_client+0x1a8/0x1d8 [mac80211] (P) + nl80211_probe_client+0xac/0x170 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + genl_rcv_msg+0x200/0x280 + netlink_rcv_skb+0x38/0xf0 + genl_rcv+0x34/0x48 + netlink_unicast+0x314/0x3a0 + netlink_sendmsg+0x150/0x390 + ____sys_sendmsg+0x1f4/0x21c + ___sys_sendmsg+0x98/0xc0 + __sys_sendmsg+0x74/0xcc + __arm64_sys_sendmsg+0x20/0x34 + invoke_syscall.constprop.0+0x4c/0xd0 + do_el0_svc+0x3c/0xd0 + el0_svc+0x28/0xc0 + el0t_64_sync_handler+0x98/0xdc + el0t_64_sync+0x154/0x158 +---[ end trace 0000000000000000 ]--- + +For NULL packets sent to probe stations, set the band information only +for non-MLD, since MLD transmissions does not rely on band. + +Signed-off-by: Suraj P Kizhakkethil +Link: https://patch.msgid.link/20260213100126.1414398-2-suraj.kizhakkethil@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/cfg.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 0abb687fd58d5..e94cb1e3904be 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4224,12 +4224,17 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, + + qos = sta->sta.wme; + +- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- ret = -EINVAL; +- goto unlock; ++ if (ieee80211_vif_is_mld(&sdata->vif)) { ++ /* MLD transmissions must not rely on the band */ ++ band = 0; ++ } else { ++ chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ ret = -EINVAL; ++ goto unlock; ++ } ++ band = chanctx_conf->def.chan->band; + } +- band = chanctx_conf->def.chan->band; + + if (qos) { + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch b/queue-6.12/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch new file mode 100644 index 0000000000..a35081d162 --- /dev/null +++ b/queue-6.12/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch @@ -0,0 +1,51 @@ +From de3128f64c0245c61d2d9c75e32349632848a452 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:17:22 +0530 +Subject: wifi: mac80211: use ap_addr for 4-address NULL frame destination + +From: Tamizh Chelvam Raja + +[ Upstream commit 594be50a3f0a6b7389f40f7acbf0dd731beb5204 ] + +Currently ieee80211_send_4addr_nullfunc() uses deflink.u.mgd.bssid +for addr1 and addr3 fields. In MLO configurations, deflink.u.mgd.bssid +represents link 0's BSSID and is not updated when link 0 is not an +assoc link. This causes 4-address NULL frames to be sent to the +wrong address, preventing WDS AP_VLAN interface creation on the peer AP. + +To fix this use sdata->vif.cfg.ap_addr instead, which contains the AP's MLD +address populated during authentication/association and remains +valid regardless of which links are active. + +This ensures 4-address NULL frames reach the correct AP, allowing +proper WDS operation over MLO connections. + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Tamizh Chelvam Raja +Link: https://patch.msgid.link/20260326164723.553927-3-tamizh.raja@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 3dfbaa0d76687..a64fca8d14572 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2071,9 +2071,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; +- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch b/queue-6.12/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch new file mode 100644 index 0000000000..1f9ff483f5 --- /dev/null +++ b/queue-6.12/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch @@ -0,0 +1,51 @@ +From 73cd1b4205952fef72d8a6a8547f49f39ece885e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 03:52:10 +0000 +Subject: wifi: mt76: add missing lock protection in mt76_sta_state for + sta_event callback + +From: Ziyi Guo + +[ Upstream commit f0168f2f9a1eca55d3ae09d8250b94e82b67cac3 ] + +mt76_sta_state() calls the sta_event callback without holding dev->mutex. +However, mt7915_mac_sta_event() (MT7915 implementation of this callback) +calls mt7915_mac_twt_teardown_flow() which has +lockdep_assert_held(&dev->mt76.mutex) indicating that callers must +hold this lock. + +The locking pattern in mt76_sta_state() is inconsistent: +- mt76_sta_add() acquires dev->mutex before calling dev->drv->sta_add +- mt76_sta_remove() acquires dev->mutex before calling __mt76_sta_remove +- But sta_event callback is called without acquiring the lock + +Add mutex_lock()/mutex_unlock() around the mt7915_mac_twt_teardown_flow +invocation to fix the missing lock protection and maintain consistency +with the existing locking pattern. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260131035210.2198259-1-n7l8m4@u.northwestern.edu +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index f49dcdde3f2c6..013c9f7b766c3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -793,8 +793,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); + + case MT76_STA_EVENT_DISASSOC: ++ mutex_lock(&dev->mt76.mutex); + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); ++ mutex_unlock(&dev->mt76.mutex); + + mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch b/queue-6.12/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch new file mode 100644 index 0000000000..66cd023f85 --- /dev/null +++ b/queue-6.12/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch @@ -0,0 +1,54 @@ +From 2c2c1227957d25aef72c4314c0e818f04452dc65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:10:32 -0800 +Subject: wifi: mt76: fix list corruption in mt76_wcid_cleanup + +From: Zac Bowling + +[ Upstream commit 34163942195410372fb138bea806c9b34e2f5257 ] + +mt76_wcid_cleanup() was not removing wcid entries from sta_poll_list +before mt76_reset_device() reinitializes the master list. This leaves +stale pointers in wcid->poll_list, causing list corruption when +mt76_wcid_add_poll() later checks list_empty() and tries to add the +entry back. + +The fix adds proper cleanup of poll_list in mt76_wcid_cleanup(), +matching how tx_list is already handled. This is similar to what +mt7996_mac_sta_deinit_link() already does correctly. + +Fixes list corruption warnings like: + list_add corruption. prev->next should be next (ffffffff...) + +Signed-off-by: Zac Bowling +Link: https://patch.msgid.link/20260120201043.38225-3-zac@zacbowling.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 5373f8c419b04..a9a9d850f6156 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1577,6 +1577,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) + + idr_destroy(&wcid->pktid); + ++ /* Remove from sta_poll_list to prevent list corruption after reset. ++ * Without this, mt76_reset_device() reinitializes sta_poll_list but ++ * leaves wcid->poll_list with stale pointers, causing list corruption ++ * when mt76_wcid_add_poll() checks list_empty(). ++ */ ++ spin_lock_bh(&dev->sta_poll_lock); ++ if (!list_empty(&wcid->poll_list)) ++ list_del_init(&wcid->poll_list); ++ spin_unlock_bh(&dev->sta_poll_lock); ++ + spin_lock_bh(&phy->tx_lock); + + if (!list_empty(&wcid->tx_list)) +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-6.12/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..079eb7b02d --- /dev/null +++ b/queue-6.12/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From e72d973ca067d072c385962ec441fa5072e1b1bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index 4a49a3036a46b..c671d60bdfa5c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -533,6 +533,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch b/queue-6.12/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch new file mode 100644 index 0000000000..3360139cbf --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch @@ -0,0 +1,42 @@ +From 86bd192b72f3eea424e29656a59eefbf0dc67b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 17:22:30 -0600 +Subject: wifi: mt76: mt7925: resolve link after acquiring mt76 mutex + +From: Sean Wang + +[ Upstream commit beec58f36983f826fe90287a90edff46b32e8a89 ] + +mt792x_sta_to_link() uses rcu_dereference_protected() and therefore +expects mt76.mutex to be held. Move the lookup after +mt792x_mutex_acquire() to make the locking explicit and correct. + +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20260306232238.2039675-12-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index d39c7f8da5d38..cdeb4c8924d41 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1075,11 +1075,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + ++ mt792x_mutex_acquire(dev); ++ + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + +- mt792x_mutex_acquire(dev); +- + if (ieee80211_vif_is_mld(vif)) { + link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); + } else { +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch b/queue-6.12/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch new file mode 100644 index 0000000000..4c4009dafe --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch @@ -0,0 +1,49 @@ +From f956c46fc84748718379edf7664002b22c99364b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 19:40:07 +0800 +Subject: wifi: mt76: mt7925: Skip scan process during suspend. + +From: Michael Lo + +[ Upstream commit 8c7e19612b01567f641d3ffe21e47fa21c331171 ] + +We are experiencing command timeouts because an upper layer triggers +an unexpected scan while the system/device is in suspend. +The upper layer should not initiate scans until the NIC has fully resumed. +We want to prevent scans during suspend and avoid timeouts without harming +power management or user experience. + +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260112114007.2115873-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 5fc95c8623647..d39c7f8da5d38 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1349,10 +1349,18 @@ static bool is_valid_alpha2(const char *alpha2) + void mt7925_scan_work(struct work_struct *work) + { + struct mt792x_phy *phy; ++ struct mt792x_dev *dev; ++ struct mt76_connac_pm *pm; + + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + scan_work.work); + ++ dev = phy->dev; ++ pm = &dev->pm; ++ ++ if (pm->suspended) ++ return; ++ + while (true) { + struct mt76_dev *mdev = &phy->dev->mt76; + struct sk_buff *skb; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch b/queue-6.12/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch new file mode 100644 index 0000000000..4a59b1d776 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch @@ -0,0 +1,49 @@ +From b204633b3e4cfe11849091991fc7ee4f8aa0d6d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:22:31 +0800 +Subject: wifi: mt76: mt792x: Fix a potential deadlock in high-load situations + +From: Leon Yen + +[ Upstream commit bb2f07819d063a58756186cac6465341956ac0a4 ] + +A deadlock may occur between two works, ps_work and mac_work, if their work +functions run simultaneously as they attempt to cancel each other by +calling cancel_delayed_work_sync(). + +mt792x_mac_work() -> ... -> cancel_delayed_work_sync(&pm->ps_work); +mt792x_pm_power_save_work() -> cancel_delayed_work_sync(&mphy->mac_work); + +In high-load situations, they are queued but may not have chance to be +executed until the CPUs are released. Once the CPUs are available, there +is a high possibility that the ps_work function and mac_work function will +be executed simultaneously, resulting in a possible deadlock. + +This patch replaces cancel_delayed_work_sync() with cancel_delayed_work() +in ps_work to eliminate the deadlock and make the code easier to maintain. + +Signed-off-by: Leon Yen +Tested-by: Chia-Lin Kao (AceLan) +Link: https://patch.msgid.link/20251215122231.3180648-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +index 05978d9c7b916..ac75d795f65de 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +@@ -378,7 +378,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) + } + + if (!mt792x_mcu_fw_pmctrl(dev)) { +- cancel_delayed_work_sync(&mphy->mac_work); ++ cancel_delayed_work(&mphy->mac_work); + return; + } + out: +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch b/queue-6.12/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch new file mode 100644 index 0000000000..82cca9eb59 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch @@ -0,0 +1,66 @@ +From b8e51b2e217af871dc3c567eddc9951c4a5889c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:24:00 +0000 +Subject: wifi: mt76: mt7996: reset device after MCU message timeout + +From: Chad Monroe + +[ Upstream commit d2b860454ea2df8f336e9b859da7ffb27f43444d ] + +Trigger a full reset after MCU message timeout. + +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/6e05ed063f3763ad3457633c56b60a728a49a6f0.1765203753.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 +++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 6f8167bb86136..959cc386ae8c4 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2100,6 +2100,11 @@ void mt7996_reset(struct mt7996_dev *dev) + return; + } + ++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { ++ set_bit(MT76_MCU_RESET, &dev->mphy.state); ++ wake_up(&dev->mt76.mcu.wait); ++ } ++ + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 54567a5893449..4dd871d17e8b3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -194,6 +194,7 @@ static int + mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) + { ++ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_mcu_rxd *rxd; + struct mt7996_mcu_uni_event *event; + int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); +@@ -202,6 +203,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + if (!skb) { + dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", + cmd, seq); ++ ++ if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { ++ dev->recovery.restart = true; ++ wake_up(&dev->mt76.mcu.wait); ++ queue_work(dev->mt76.wq, &dev->reset_work); ++ wake_up(&dev->reset_wait); ++ } ++ + return -ETIMEDOUT; + } + +-- +2.53.0 + diff --git a/queue-6.12/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-6.12/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..497da6d99d --- /dev/null +++ b/queue-6.12/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From 8c83ccb1822bec52130fc5c5c3c78ac434180697 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index 85fd5090e0b8a..c853600c0fef2 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index dccc139cabb29..699c64e8d07e7 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-6.12/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-6.12/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..9cc085cd96 --- /dev/null +++ b/queue-6.12/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From 3afd38fc6bd60e18af79018999952549ab3c03df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index dae7ca1488650..da2cecfeb93a0 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -416,7 +416,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + pkt_info->mac_id = rtwvif->mac_id; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-6.12/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch b/queue-6.12/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch new file mode 100644 index 0000000000..c0a21d3f1a --- /dev/null +++ b/queue-6.12/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch @@ -0,0 +1,78 @@ +From af59912e57557c56d98b834ef6e0a17cb9954e95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:21:55 +0000 +Subject: wifi: rtw89: retry efuse physical map dump on transient failure + +From: Christian Hewitt + +[ Upstream commit d92f6ad6483e6d430c8273eeb7be97ce85244bd5 ] + +On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse +physical map dump intermittently fails with -EBUSY during probe. +The failure occurs in rtw89_dump_physical_efuse_map_ddv() where +read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY +bit after 1 second. + +The root cause is a timing race during boot: the WiFi driver's +chip initialization (firmware download via PCIe) overlaps with +Bluetooth firmware download to the same combo chip via USB. This +can leave the efuse controller temporarily unavailable when the +WiFi driver attempts to read the efuse map. + +The firmware download path retries up to 5 times, but the efuse +read that follows has no similar logic. Address this by adding +retry loop logic (also up to 5 attempts) around physical efuse +map dump. + +Signed-off-by: Christian Hewitt +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260317112155.1939569-1-christianshewitt@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/efuse.c | 23 ++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c +index e1236079a84a1..562f4e3536475 100644 +--- a/drivers/net/wireless/realtek/rtw89/efuse.c ++++ b/drivers/net/wireless/realtek/rtw89/efuse.c +@@ -162,8 +162,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + +-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, +- u32 dump_addr, u32 dump_size, bool dav) ++static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) + { + int ret; + +@@ -185,6 +185,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + ++static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) ++{ ++ int retry; ++ int ret; ++ ++ for (retry = 0; retry < 5; retry++) { ++ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr, ++ dump_size, dav); ++ if (!ret) ++ return 0; ++ ++ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n", ++ dav, retry); ++ } ++ ++ return ret; ++} ++ + #define invalid_efuse_header(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) + #define invalid_efuse_content(word_en, i) \ +-- +2.53.0 + diff --git a/queue-6.12/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch b/queue-6.12/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch new file mode 100644 index 0000000000..687193516d --- /dev/null +++ b/queue-6.12/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch @@ -0,0 +1,53 @@ +From e6d27d508b254fa082034966ac243d8b14cfd267 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 14:15:51 +0800 +Subject: wifi: rtw89: ser: Wi-Fi 7 reset HALT C2H after reading it + +From: Zong-Zhe Yang + +[ Upstream commit 0cae26a78b14fe1292b0f50f28ebabe6801f3885 ] + +When a SER (system error recovery) interrupt happens, driver reads HALT C2H +register to get the error status via MAC. For Wi-Fi 7 chipset, driver needs +to reset HALT C2H register after reading it to make FW aware that. + +Signed-off-by: Zong-Zhe Yang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260213061552.29997-12-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/mac.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c +index 31465893f866d..595b85e21ff06 100644 +--- a/drivers/net/wireless/realtek/rtw89/mac.c ++++ b/drivers/net/wireless/realtek/rtw89/mac.c +@@ -812,6 +812,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; ++ const struct rtw89_chip_info *chip = rtwdev->chip; + u32 err, err_scnr; + int ret; + +@@ -834,11 +835,15 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + err = MAC_AX_ERR_RXI300; + + if (rtw89_mac_suppress_log(rtwdev, err)) +- return err; ++ goto bottom; + + rtw89_fw_st_dbg_dump(rtwdev); + mac->dump_err_status(rtwdev, err); + ++bottom: ++ if (chip->chip_gen != RTW89_CHIP_AX) ++ rtw89_write32(rtwdev, R_AX_HALT_C2H, 0); ++ + return err; + } + EXPORT_SYMBOL(rtw89_mac_get_err_status); +-- +2.53.0 + diff --git a/queue-6.12/x86-mce-add-wrapper-for-struct-mce-to-export-vendor-.patch b/queue-6.12/x86-mce-add-wrapper-for-struct-mce-to-export-vendor-.patch new file mode 100644 index 0000000000..898e646a92 --- /dev/null +++ b/queue-6.12/x86-mce-add-wrapper-for-struct-mce-to-export-vendor-.patch @@ -0,0 +1,996 @@ +From f2903658891409d08f233f202b34d0a4ffd16687 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Oct 2024 19:36:27 +0000 +Subject: x86/mce: Add wrapper for struct mce to export vendor specific info + +From: Avadhut Naik + +[ Upstream commit 750fd23926f1507cc826b5a4fdd4bfc7283e7723 ] + +Currently, exporting new additional machine check error information +involves adding new fields for the same at the end of the struct mce. +This additional information can then be consumed through mcelog or +tracepoint. + +However, as new MSRs are being added (and will be added in the future) +by CPU vendors on their newer CPUs with additional machine check error +information to be exported, the size of struct mce will balloon on some +CPUs, unnecessarily, since those fields are vendor-specific. Moreover, +different CPU vendors may export the additional information in varying +sizes. + +The problem particularly intensifies since struct mce is exposed to +userspace as part of UAPI. It's bloating through vendor-specific data +should be avoided to limit the information being sent out to userspace. + +Add a new structure mce_hw_err to wrap the existing struct mce. The same +will prevent its ballooning since vendor-specifc data, if any, can now be +exported through a union within the wrapper structure and through +__dynamic_array in mce_record tracepoint. + +Furthermore, new internal kernel fields can be added to the wrapper +struct without impacting the user space API. + + [ bp: Restore reverse x-mas tree order of function vars declarations. ] + +Suggested-by: Borislav Petkov (AMD) +Signed-off-by: Avadhut Naik +Signed-off-by: Yazen Ghannam +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Qiuxu Zhuo +Link: https://lore.kernel.org/r/20241022194158.110073-2-avadhut.naik@amd.com +Stable-dep-of: ea324444ece9 ("x86/mce: Restore MCA polling interval halving") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/mce.h | 14 +- + arch/x86/kernel/cpu/mce/amd.c | 27 ++-- + arch/x86/kernel/cpu/mce/apei.c | 45 ++++--- + arch/x86/kernel/cpu/mce/core.c | 207 ++++++++++++++++------------- + arch/x86/kernel/cpu/mce/genpool.c | 18 +-- + arch/x86/kernel/cpu/mce/inject.c | 6 +- + arch/x86/kernel/cpu/mce/internal.h | 4 +- + include/trace/events/mce.h | 42 +++--- + 8 files changed, 202 insertions(+), 161 deletions(-) + +diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h +index 3b9970117a0fa..4e45f45673a33 100644 +--- a/arch/x86/include/asm/mce.h ++++ b/arch/x86/include/asm/mce.h +@@ -187,6 +187,16 @@ enum mce_notifier_prios { + MCE_PRIO_HIGHEST = MCE_PRIO_CEC + }; + ++/** ++ * struct mce_hw_err - Hardware Error Record. ++ * @m: Machine Check record. ++ */ ++struct mce_hw_err { ++ struct mce m; ++}; ++ ++#define to_mce_hw_err(mce) container_of(mce, struct mce_hw_err, m) ++ + struct notifier_block; + extern void mce_register_decode_chain(struct notifier_block *nb); + extern void mce_unregister_decode_chain(struct notifier_block *nb); +@@ -221,8 +231,8 @@ static inline int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, + u64 lapic_id) { return -EINVAL; } + #endif + +-void mce_prep_record(struct mce *m); +-void mce_log(struct mce *m); ++void mce_prep_record(struct mce_hw_err *err); ++void mce_log(struct mce_hw_err *err); + DECLARE_PER_CPU(struct device *, mce_device); + + /* Maximum number of MCA banks per CPU. */ +diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c +index dac4564e1d7ca..3011a16c4a947 100644 +--- a/arch/x86/kernel/cpu/mce/amd.c ++++ b/arch/x86/kernel/cpu/mce/amd.c +@@ -777,29 +777,30 @@ bool amd_mce_usable_address(struct mce *m) + + static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) + { +- struct mce m; ++ struct mce_hw_err err; ++ struct mce *m = &err.m; + +- mce_prep_record(&m); ++ mce_prep_record(&err); + +- m.status = status; +- m.misc = misc; +- m.bank = bank; +- m.tsc = rdtsc(); ++ m->status = status; ++ m->misc = misc; ++ m->bank = bank; ++ m->tsc = rdtsc(); + +- if (m.status & MCI_STATUS_ADDRV) { +- m.addr = addr; ++ if (m->status & MCI_STATUS_ADDRV) { ++ m->addr = addr; + +- smca_extract_err_addr(&m); ++ smca_extract_err_addr(m); + } + + if (mce_flags.smca) { +- rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m.ipid); ++ rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m->ipid); + +- if (m.status & MCI_STATUS_SYNDV) +- rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m.synd); ++ if (m->status & MCI_STATUS_SYNDV) ++ rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m->synd); + } + +- mce_log(&m); ++ mce_log(&err); + } + + DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error) +diff --git a/arch/x86/kernel/cpu/mce/apei.c b/arch/x86/kernel/cpu/mce/apei.c +index 3885fe05f01ec..7f582b4ca1cae 100644 +--- a/arch/x86/kernel/cpu/mce/apei.c ++++ b/arch/x86/kernel/cpu/mce/apei.c +@@ -28,7 +28,8 @@ + + void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err) + { +- struct mce m; ++ struct mce_hw_err err; ++ struct mce *m; + int lsb; + + if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) +@@ -44,22 +45,23 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err) + else + lsb = PAGE_SHIFT; + +- mce_prep_record(&m); +- m.bank = -1; ++ mce_prep_record(&err); ++ m = &err.m; ++ m->bank = -1; + /* Fake a memory read error with unknown channel */ +- m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f; +- m.misc = (MCI_MISC_ADDR_PHYS << 6) | lsb; ++ m->status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f; ++ m->misc = (MCI_MISC_ADDR_PHYS << 6) | lsb; + + if (severity >= GHES_SEV_RECOVERABLE) +- m.status |= MCI_STATUS_UC; ++ m->status |= MCI_STATUS_UC; + + if (severity >= GHES_SEV_PANIC) { +- m.status |= MCI_STATUS_PCC; +- m.tsc = rdtsc(); ++ m->status |= MCI_STATUS_PCC; ++ m->tsc = rdtsc(); + } + +- m.addr = mem_err->physical_addr; +- mce_log(&m); ++ m->addr = mem_err->physical_addr; ++ mce_log(&err); + } + EXPORT_SYMBOL_GPL(apei_mce_report_mem_error); + +@@ -67,8 +69,9 @@ int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) + { + const u64 *i_mce = ((const u64 *) (ctx_info + 1)); + bool apicid_found = false; ++ struct mce_hw_err err; + unsigned int cpu; +- struct mce m; ++ struct mce *m; + + if (!boot_cpu_has(X86_FEATURE_SMCA)) + return -EINVAL; +@@ -108,18 +111,20 @@ int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) + if (!apicid_found) + return -EINVAL; + +- mce_prep_record_common(&m); +- mce_prep_record_per_cpu(cpu, &m); ++ m = &err.m; ++ memset(&err, 0, sizeof(struct mce_hw_err)); ++ mce_prep_record_common(m); ++ mce_prep_record_per_cpu(cpu, m); + +- m.bank = (ctx_info->msr_addr >> 4) & 0xFF; +- m.status = *i_mce; +- m.addr = *(i_mce + 1); +- m.misc = *(i_mce + 2); ++ m->bank = (ctx_info->msr_addr >> 4) & 0xFF; ++ m->status = *i_mce; ++ m->addr = *(i_mce + 1); ++ m->misc = *(i_mce + 2); + /* Skipping MCA_CONFIG */ +- m.ipid = *(i_mce + 4); +- m.synd = *(i_mce + 5); ++ m->ipid = *(i_mce + 4); ++ m->synd = *(i_mce + 5); + +- mce_log(&m); ++ mce_log(&err); + + return 0; + } +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index d8f3d9af8acf0..8735ca370803f 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -88,7 +88,7 @@ struct mca_config mca_cfg __read_mostly = { + .monarch_timeout = -1 + }; + +-static DEFINE_PER_CPU(struct mce, mces_seen); ++static DEFINE_PER_CPU(struct mce_hw_err, hw_errs_seen); + static unsigned long mce_need_notify; + + /* +@@ -119,8 +119,6 @@ BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain); + + void mce_prep_record_common(struct mce *m) + { +- memset(m, 0, sizeof(struct mce)); +- + m->cpuid = cpuid_eax(1); + m->cpuvendor = boot_cpu_data.x86_vendor; + m->mcgcap = __rdmsr(MSR_IA32_MCG_CAP); +@@ -138,9 +136,12 @@ void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m) + m->socketid = topology_physical_package_id(cpu); + } + +-/* Do initial initialization of a struct mce */ +-void mce_prep_record(struct mce *m) ++/* Do initial initialization of struct mce_hw_err */ ++void mce_prep_record(struct mce_hw_err *err) + { ++ struct mce *m = &err->m; ++ ++ memset(err, 0, sizeof(struct mce_hw_err)); + mce_prep_record_common(m); + mce_prep_record_per_cpu(smp_processor_id(), m); + } +@@ -148,9 +149,9 @@ void mce_prep_record(struct mce *m) + DEFINE_PER_CPU(struct mce, injectm); + EXPORT_PER_CPU_SYMBOL_GPL(injectm); + +-void mce_log(struct mce *m) ++void mce_log(struct mce_hw_err *err) + { +- if (!mce_gen_pool_add(m)) ++ if (!mce_gen_pool_add(err)) + irq_work_queue(&mce_irq_work); + } + EXPORT_SYMBOL_GPL(mce_log); +@@ -171,8 +172,10 @@ void mce_unregister_decode_chain(struct notifier_block *nb) + } + EXPORT_SYMBOL_GPL(mce_unregister_decode_chain); + +-static void __print_mce(struct mce *m) ++static void __print_mce(struct mce_hw_err *err) + { ++ struct mce *m = &err->m; ++ + pr_emerg(HW_ERR "CPU %d: Machine Check%s: %Lx Bank %d: %016Lx\n", + m->extcpu, + (m->mcgstatus & MCG_STATUS_MCIP ? " Exception" : ""), +@@ -214,9 +217,11 @@ static void __print_mce(struct mce *m) + m->microcode); + } + +-static void print_mce(struct mce *m) ++static void print_mce(struct mce_hw_err *err) + { +- __print_mce(m); ++ struct mce *m = &err->m; ++ ++ __print_mce(err); + + if (m->cpuvendor != X86_VENDOR_AMD && m->cpuvendor != X86_VENDOR_HYGON) + pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n"); +@@ -251,7 +256,7 @@ static const char *mce_dump_aux_info(struct mce *m) + return NULL; + } + +-static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) ++static noinstr void mce_panic(const char *msg, struct mce_hw_err *final, char *exp) + { + struct llist_node *pending; + struct mce_evt_llist *l; +@@ -282,20 +287,22 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) + pending = mce_gen_pool_prepare_records(); + /* First print corrected ones that are still unlogged */ + llist_for_each_entry(l, pending, llnode) { +- struct mce *m = &l->mce; ++ struct mce_hw_err *err = &l->err; ++ struct mce *m = &err->m; + if (!(m->status & MCI_STATUS_UC)) { +- print_mce(m); ++ print_mce(err); + if (!apei_err) + apei_err = apei_write_mce(m); + } + } + /* Now print uncorrected but with the final one last */ + llist_for_each_entry(l, pending, llnode) { +- struct mce *m = &l->mce; ++ struct mce_hw_err *err = &l->err; ++ struct mce *m = &err->m; + if (!(m->status & MCI_STATUS_UC)) + continue; +- if (!final || mce_cmp(m, final)) { +- print_mce(m); ++ if (!final || mce_cmp(m, &final->m)) { ++ print_mce(err); + if (!apei_err) + apei_err = apei_write_mce(m); + } +@@ -303,12 +310,12 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) + if (final) { + print_mce(final); + if (!apei_err) +- apei_err = apei_write_mce(final); ++ apei_err = apei_write_mce(&final->m); + } + if (exp) + pr_emerg(HW_ERR "Machine check: %s\n", exp); + +- memmsg = mce_dump_aux_info(final); ++ memmsg = mce_dump_aux_info(&final->m); + if (memmsg) + pr_emerg(HW_ERR "Machine check: %s\n", memmsg); + +@@ -323,9 +330,9 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) + * panic. + */ + if (kexec_crash_loaded()) { +- if (final && (final->status & MCI_STATUS_ADDRV)) { ++ if (final && (final->m.status & MCI_STATUS_ADDRV)) { + struct page *p; +- p = pfn_to_online_page(final->addr >> PAGE_SHIFT); ++ p = pfn_to_online_page(final->m.addr >> PAGE_SHIFT); + if (p) + SetPageHWPoison(p); + } +@@ -445,16 +452,18 @@ static noinstr void mce_wrmsrl(u32 msr, u64 v) + * check into our "mce" struct so that we can use it later to assess + * the severity of the problem as we read per-bank specific details. + */ +-static noinstr void mce_gather_info(struct mce *m, struct pt_regs *regs) ++static noinstr void mce_gather_info(struct mce_hw_err *err, struct pt_regs *regs) + { ++ struct mce *m; + /* + * Enable instrumentation around mce_prep_record() which calls external + * facilities. + */ + instrumentation_begin(); +- mce_prep_record(m); ++ mce_prep_record(err); + instrumentation_end(); + ++ m = &err->m; + m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); + if (regs) { + /* +@@ -574,13 +583,13 @@ EXPORT_SYMBOL_GPL(mce_is_correctable); + static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +- struct mce *m = (struct mce *)data; ++ struct mce_hw_err *err = to_mce_hw_err(data); + +- if (!m) ++ if (!err) + return NOTIFY_DONE; + + /* Emit the trace record: */ +- trace_mce_record(m); ++ trace_mce_record(err); + + set_bit(0, &mce_need_notify); + +@@ -624,13 +633,13 @@ static struct notifier_block mce_uc_nb = { + static int mce_default_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +- struct mce *m = (struct mce *)data; ++ struct mce_hw_err *err = to_mce_hw_err(data); + +- if (!m) ++ if (!err) + return NOTIFY_DONE; + +- if (mca_cfg.print_all || !m->kflags) +- __print_mce(m); ++ if (mca_cfg.print_all || !(err->m.kflags)) ++ __print_mce(err); + + return NOTIFY_DONE; + } +@@ -644,8 +653,10 @@ static struct notifier_block mce_default_nb = { + /* + * Read ADDR and MISC registers. + */ +-static noinstr void mce_read_aux(struct mce *m, int i) ++static noinstr void mce_read_aux(struct mce_hw_err *err, int i) + { ++ struct mce *m = &err->m; ++ + if (m->status & MCI_STATUS_MISCV) + m->misc = mce_rdmsrl(mca_msr_reg(i, MCA_MISC)); + +@@ -692,26 +703,28 @@ DEFINE_PER_CPU(unsigned, mce_poll_count); + void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) + { + struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); +- struct mce m; ++ struct mce_hw_err err; ++ struct mce *m; + int i; + + this_cpu_inc(mce_poll_count); + +- mce_gather_info(&m, NULL); ++ mce_gather_info(&err, NULL); ++ m = &err.m; + + if (flags & MCP_TIMESTAMP) +- m.tsc = rdtsc(); ++ m->tsc = rdtsc(); + + for (i = 0; i < this_cpu_read(mce_num_banks); i++) { + if (!mce_banks[i].ctl || !test_bit(i, *b)) + continue; + +- m.misc = 0; +- m.addr = 0; +- m.bank = i; ++ m->misc = 0; ++ m->addr = 0; ++ m->bank = i; + + barrier(); +- m.status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS)); ++ m->status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS)); + + /* + * Update storm tracking here, before checking for the +@@ -721,17 +734,17 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) + * storm status. + */ + if (!mca_cfg.cmci_disabled) +- mce_track_storm(&m); ++ mce_track_storm(m); + + /* If this entry is not valid, ignore it */ +- if (!(m.status & MCI_STATUS_VAL)) ++ if (!(m->status & MCI_STATUS_VAL)) + continue; + + /* + * If we are logging everything (at CPU online) or this + * is a corrected error, then we must log it. + */ +- if ((flags & MCP_UC) || !(m.status & MCI_STATUS_UC)) ++ if ((flags & MCP_UC) || !(m->status & MCI_STATUS_UC)) + goto log_it; + + /* +@@ -741,20 +754,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) + * everything else. + */ + if (!mca_cfg.ser) { +- if (m.status & MCI_STATUS_UC) ++ if (m->status & MCI_STATUS_UC) + continue; + goto log_it; + } + + /* Log "not enabled" (speculative) errors */ +- if (!(m.status & MCI_STATUS_EN)) ++ if (!(m->status & MCI_STATUS_EN)) + goto log_it; + + /* + * Log UCNA (SDM: 15.6.3 "UCR Error Classification") + * UC == 1 && PCC == 0 && S == 0 + */ +- if (!(m.status & MCI_STATUS_PCC) && !(m.status & MCI_STATUS_S)) ++ if (!(m->status & MCI_STATUS_PCC) && !(m->status & MCI_STATUS_S)) + goto log_it; + + /* +@@ -768,20 +781,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) + if (flags & MCP_DONTLOG) + goto clear_it; + +- mce_read_aux(&m, i); +- m.severity = mce_severity(&m, NULL, NULL, false); ++ mce_read_aux(&err, i); ++ m->severity = mce_severity(m, NULL, NULL, false); + /* + * Don't get the IP here because it's unlikely to + * have anything to do with the actual error location. + */ + +- if (mca_cfg.dont_log_ce && !mce_usable_address(&m)) ++ if (mca_cfg.dont_log_ce && !mce_usable_address(m)) + goto clear_it; + + if (flags & MCP_QUEUE_LOG) +- mce_gen_pool_add(&m); ++ mce_gen_pool_add(&err); + else +- mce_log(&m); ++ mce_log(&err); + + clear_it: + /* +@@ -905,9 +918,10 @@ static __always_inline void quirk_zen_ifu(int bank, struct mce *m, struct pt_reg + * Do a quick check if any of the events requires a panic. + * This decides if we keep the events around or clear them. + */ +-static __always_inline int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp, ++static __always_inline int mce_no_way_out(struct mce_hw_err *err, char **msg, unsigned long *validp, + struct pt_regs *regs) + { ++ struct mce *m = &err->m; + char *tmp = *msg; + int i; + +@@ -925,7 +939,7 @@ static __always_inline int mce_no_way_out(struct mce *m, char **msg, unsigned lo + + m->bank = i; + if (mce_severity(m, regs, &tmp, true) >= MCE_PANIC_SEVERITY) { +- mce_read_aux(m, i); ++ mce_read_aux(err, i); + *msg = tmp; + return 1; + } +@@ -1016,10 +1030,11 @@ static noinstr int mce_timed_out(u64 *t, const char *msg) + */ + static void mce_reign(void) + { +- int cpu; ++ struct mce_hw_err *err = NULL; + struct mce *m = NULL; + int global_worst = 0; + char *msg = NULL; ++ int cpu; + + /* + * This CPU is the Monarch and the other CPUs have run +@@ -1027,11 +1042,13 @@ static void mce_reign(void) + * Grade the severity of the errors of all the CPUs. + */ + for_each_possible_cpu(cpu) { +- struct mce *mtmp = &per_cpu(mces_seen, cpu); ++ struct mce_hw_err *etmp = &per_cpu(hw_errs_seen, cpu); ++ struct mce *mtmp = &etmp->m; + + if (mtmp->severity > global_worst) { + global_worst = mtmp->severity; +- m = &per_cpu(mces_seen, cpu); ++ err = &per_cpu(hw_errs_seen, cpu); ++ m = &err->m; + } + } + +@@ -1043,7 +1060,7 @@ static void mce_reign(void) + if (m && global_worst >= MCE_PANIC_SEVERITY) { + /* call mce_severity() to get "msg" for panic */ + mce_severity(m, NULL, &msg, true); +- mce_panic("Fatal machine check", m, msg); ++ mce_panic("Fatal machine check", err, msg); + } + + /* +@@ -1060,11 +1077,11 @@ static void mce_reign(void) + mce_panic("Fatal machine check from unknown source", NULL, NULL); + + /* +- * Now clear all the mces_seen so that they don't reappear on ++ * Now clear all the hw_errs_seen so that they don't reappear on + * the next mce. + */ + for_each_possible_cpu(cpu) +- memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce)); ++ memset(&per_cpu(hw_errs_seen, cpu), 0, sizeof(struct mce_hw_err)); + } + + static atomic_t global_nwo; +@@ -1268,13 +1285,14 @@ static noinstr bool mce_check_crashing_cpu(void) + } + + static __always_inline int +-__mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, +- unsigned long *toclear, unsigned long *valid_banks, int no_way_out, +- int *worst) ++__mc_scan_banks(struct mce_hw_err *err, struct pt_regs *regs, ++ struct mce_hw_err *final, unsigned long *toclear, ++ unsigned long *valid_banks, int no_way_out, int *worst) + { + struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); + struct mca_config *cfg = &mca_cfg; + int severity, i, taint = 0; ++ struct mce *m = &err->m; + + for (i = 0; i < this_cpu_read(mce_num_banks); i++) { + arch___clear_bit(i, toclear); +@@ -1319,7 +1337,7 @@ __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, + if (severity == MCE_NO_SEVERITY) + continue; + +- mce_read_aux(m, i); ++ mce_read_aux(err, i); + + /* assuming valid severity level != 0 */ + m->severity = severity; +@@ -1329,17 +1347,17 @@ __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, + * done in #MC context, where instrumentation is disabled. + */ + instrumentation_begin(); +- mce_log(m); ++ mce_log(err); + instrumentation_end(); + + if (severity > *worst) { +- *final = *m; ++ *final = *err; + *worst = severity; + } + } + + /* mce_clear_state will clear *final, save locally for use later */ +- *m = *final; ++ *err = *final; + + return taint; + } +@@ -1399,9 +1417,10 @@ static void kill_me_never(struct callback_head *cb) + set_mce_nospec(pfn); + } + +-static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callback_head *)) ++static void queue_task_work(struct mce_hw_err *err, char *msg, void (*func)(struct callback_head *)) + { + int count = ++current->mce_count; ++ struct mce *m = &err->m; + + /* First call, save all the details */ + if (count == 1) { +@@ -1414,11 +1433,12 @@ static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callba + + /* Ten is likely overkill. Don't expect more than two faults before task_work() */ + if (count > 10) +- mce_panic("Too many consecutive machine checks while accessing user data", m, msg); ++ mce_panic("Too many consecutive machine checks while accessing user data", ++ err, msg); + + /* Second or later call, make sure page address matches the one from first call */ + if (count > 1 && (current->mce_addr >> PAGE_SHIFT) != (m->addr >> PAGE_SHIFT)) +- mce_panic("Consecutive machine checks to different user pages", m, msg); ++ mce_panic("Consecutive machine checks to different user pages", err, msg); + + /* Do not call task_work_add() more than once */ + if (count > 1) +@@ -1467,8 +1487,10 @@ noinstr void do_machine_check(struct pt_regs *regs) + int worst = 0, order, no_way_out, kill_current_task, lmce, taint = 0; + DECLARE_BITMAP(valid_banks, MAX_NR_BANKS) = { 0 }; + DECLARE_BITMAP(toclear, MAX_NR_BANKS) = { 0 }; +- struct mce m, *final; ++ struct mce_hw_err *final; ++ struct mce_hw_err err; + char *msg = NULL; ++ struct mce *m; + + if (unlikely(mce_flags.p5)) + return pentium_machine_check(regs); +@@ -1506,13 +1528,14 @@ noinstr void do_machine_check(struct pt_regs *regs) + + this_cpu_inc(mce_exception_count); + +- mce_gather_info(&m, regs); +- m.tsc = rdtsc(); ++ mce_gather_info(&err, regs); ++ m = &err.m; ++ m->tsc = rdtsc(); + +- final = this_cpu_ptr(&mces_seen); +- *final = m; ++ final = this_cpu_ptr(&hw_errs_seen); ++ *final = err; + +- no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs); ++ no_way_out = mce_no_way_out(&err, &msg, valid_banks, regs); + + barrier(); + +@@ -1521,15 +1544,15 @@ noinstr void do_machine_check(struct pt_regs *regs) + * Assume the worst for now, but if we find the + * severity is MCE_AR_SEVERITY we have other options. + */ +- if (!(m.mcgstatus & MCG_STATUS_RIPV)) ++ if (!(m->mcgstatus & MCG_STATUS_RIPV)) + kill_current_task = 1; + /* + * Check if this MCE is signaled to only this logical processor, + * on Intel, Zhaoxin only. + */ +- if (m.cpuvendor == X86_VENDOR_INTEL || +- m.cpuvendor == X86_VENDOR_ZHAOXIN) +- lmce = m.mcgstatus & MCG_STATUS_LMCES; ++ if (m->cpuvendor == X86_VENDOR_INTEL || ++ m->cpuvendor == X86_VENDOR_ZHAOXIN) ++ lmce = m->mcgstatus & MCG_STATUS_LMCES; + + /* + * Local machine check may already know that we have to panic. +@@ -1540,12 +1563,12 @@ noinstr void do_machine_check(struct pt_regs *regs) + */ + if (lmce) { + if (no_way_out) +- mce_panic("Fatal local machine check", &m, msg); ++ mce_panic("Fatal local machine check", &err, msg); + } else { + order = mce_start(&no_way_out); + } + +- taint = __mc_scan_banks(&m, regs, final, toclear, valid_banks, no_way_out, &worst); ++ taint = __mc_scan_banks(&err, regs, final, toclear, valid_banks, no_way_out, &worst); + + if (!no_way_out) + mce_clear_state(toclear); +@@ -1560,7 +1583,7 @@ noinstr void do_machine_check(struct pt_regs *regs) + no_way_out = worst >= MCE_PANIC_SEVERITY; + + if (no_way_out) +- mce_panic("Fatal machine check on current CPU", &m, msg); ++ mce_panic("Fatal machine check on current CPU", &err, msg); + } + } else { + /* +@@ -1572,8 +1595,8 @@ noinstr void do_machine_check(struct pt_regs *regs) + * make sure we have the right "msg". + */ + if (worst >= MCE_PANIC_SEVERITY) { +- mce_severity(&m, regs, &msg, true); +- mce_panic("Local fatal machine check!", &m, msg); ++ mce_severity(m, regs, &msg, true); ++ mce_panic("Local fatal machine check!", &err, msg); + } + } + +@@ -1591,16 +1614,16 @@ noinstr void do_machine_check(struct pt_regs *regs) + goto out; + + /* Fault was in user mode and we need to take some action */ +- if ((m.cs & 3) == 3) { ++ if ((m->cs & 3) == 3) { + /* If this triggers there is no way to recover. Die hard. */ + BUG_ON(!on_thread_stack() || !user_mode(regs)); + +- if (!mce_usable_address(&m)) +- queue_task_work(&m, msg, kill_me_now); ++ if (!mce_usable_address(m)) ++ queue_task_work(&err, msg, kill_me_now); + else +- queue_task_work(&m, msg, kill_me_maybe); ++ queue_task_work(&err, msg, kill_me_maybe); + +- } else if (m.mcgstatus & MCG_STATUS_SEAM_NR) { ++ } else if (m->mcgstatus & MCG_STATUS_SEAM_NR) { + /* + * Saved RIP on stack makes it look like the machine check + * was taken in the kernel on the instruction following +@@ -1612,8 +1635,8 @@ noinstr void do_machine_check(struct pt_regs *regs) + * not occur there. Mark the page as poisoned so it won't + * be added to free list when the guest is terminated. + */ +- if (mce_usable_address(&m)) { +- struct page *p = pfn_to_online_page(m.addr >> PAGE_SHIFT); ++ if (mce_usable_address(m)) { ++ struct page *p = pfn_to_online_page(m->addr >> PAGE_SHIFT); + + if (p) + SetPageHWPoison(p); +@@ -1628,13 +1651,13 @@ noinstr void do_machine_check(struct pt_regs *regs) + * corresponding exception handler which would do that is the + * proper one. + */ +- if (m.kflags & MCE_IN_KERNEL_RECOV) { ++ if (m->kflags & MCE_IN_KERNEL_RECOV) { + if (!fixup_exception(regs, X86_TRAP_MC, 0, 0)) +- mce_panic("Failed kernel mode recovery", &m, msg); ++ mce_panic("Failed kernel mode recovery", &err, msg); + } + +- if (m.kflags & MCE_IN_KERNEL_COPYIN) +- queue_task_work(&m, msg, kill_me_never); ++ if (m->kflags & MCE_IN_KERNEL_COPYIN) ++ queue_task_work(&err, msg, kill_me_never); + } + + out: +diff --git a/arch/x86/kernel/cpu/mce/genpool.c b/arch/x86/kernel/cpu/mce/genpool.c +index 4284749ec8037..d0be6dda0c14b 100644 +--- a/arch/x86/kernel/cpu/mce/genpool.c ++++ b/arch/x86/kernel/cpu/mce/genpool.c +@@ -31,15 +31,15 @@ static LLIST_HEAD(mce_event_llist); + */ + static bool is_duplicate_mce_record(struct mce_evt_llist *t, struct mce_evt_llist *l) + { ++ struct mce_hw_err *err1, *err2; + struct mce_evt_llist *node; +- struct mce *m1, *m2; + +- m1 = &t->mce; ++ err1 = &t->err; + + llist_for_each_entry(node, &l->llnode, llnode) { +- m2 = &node->mce; ++ err2 = &node->err; + +- if (!mce_cmp(m1, m2)) ++ if (!mce_cmp(&err1->m, &err2->m)) + return true; + } + return false; +@@ -73,8 +73,8 @@ struct llist_node *mce_gen_pool_prepare_records(void) + + void mce_gen_pool_process(struct work_struct *__unused) + { +- struct llist_node *head; + struct mce_evt_llist *node, *tmp; ++ struct llist_node *head; + struct mce *mce; + + head = llist_del_all(&mce_event_llist); +@@ -83,7 +83,7 @@ void mce_gen_pool_process(struct work_struct *__unused) + + head = llist_reverse_order(head); + llist_for_each_entry_safe(node, tmp, head, llnode) { +- mce = &node->mce; ++ mce = &node->err.m; + blocking_notifier_call_chain(&x86_mce_decoder_chain, 0, mce); + gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node)); + } +@@ -94,11 +94,11 @@ bool mce_gen_pool_empty(void) + return llist_empty(&mce_event_llist); + } + +-int mce_gen_pool_add(struct mce *mce) ++int mce_gen_pool_add(struct mce_hw_err *err) + { + struct mce_evt_llist *node; + +- if (filter_mce(mce)) ++ if (filter_mce(&err->m)) + return -EINVAL; + + if (!mce_evt_pool) +@@ -110,7 +110,7 @@ int mce_gen_pool_add(struct mce *mce) + return -ENOMEM; + } + +- memcpy(&node->mce, mce, sizeof(*mce)); ++ memcpy(&node->err, err, sizeof(*err)); + llist_add(&node->llnode, &mce_event_llist); + + return 0; +diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c +index 49ed3428785d8..313fe682db339 100644 +--- a/arch/x86/kernel/cpu/mce/inject.c ++++ b/arch/x86/kernel/cpu/mce/inject.c +@@ -502,8 +502,9 @@ static void prepare_msrs(void *info) + + static void do_inject(void) + { +- u64 mcg_status = 0; + unsigned int cpu = i_mce.extcpu; ++ struct mce_hw_err err; ++ u64 mcg_status = 0; + u8 b = i_mce.bank; + + i_mce.tsc = rdtsc_ordered(); +@@ -517,7 +518,8 @@ static void do_inject(void) + i_mce.status |= MCI_STATUS_SYNDV; + + if (inj_type == SW_INJ) { +- mce_log(&i_mce); ++ err.m = i_mce; ++ mce_log(&err); + return; + } + +diff --git a/arch/x86/kernel/cpu/mce/internal.h b/arch/x86/kernel/cpu/mce/internal.h +index 43c7f3b71df59..84f810598231e 100644 +--- a/arch/x86/kernel/cpu/mce/internal.h ++++ b/arch/x86/kernel/cpu/mce/internal.h +@@ -26,12 +26,12 @@ extern struct blocking_notifier_head x86_mce_decoder_chain; + + struct mce_evt_llist { + struct llist_node llnode; +- struct mce mce; ++ struct mce_hw_err err; + }; + + void mce_gen_pool_process(struct work_struct *__unused); + bool mce_gen_pool_empty(void); +-int mce_gen_pool_add(struct mce *mce); ++int mce_gen_pool_add(struct mce_hw_err *err); + int mce_gen_pool_init(void); + struct llist_node *mce_gen_pool_prepare_records(void); + +diff --git a/include/trace/events/mce.h b/include/trace/events/mce.h +index f0f7b3cb20417..65aba1afcd070 100644 +--- a/include/trace/events/mce.h ++++ b/include/trace/events/mce.h +@@ -19,9 +19,9 @@ + + TRACE_EVENT(mce_record, + +- TP_PROTO(struct mce *m), ++ TP_PROTO(struct mce_hw_err *err), + +- TP_ARGS(m), ++ TP_ARGS(err), + + TP_STRUCT__entry( + __field( u64, mcgcap ) +@@ -46,25 +46,25 @@ TRACE_EVENT(mce_record, + ), + + TP_fast_assign( +- __entry->mcgcap = m->mcgcap; +- __entry->mcgstatus = m->mcgstatus; +- __entry->status = m->status; +- __entry->addr = m->addr; +- __entry->misc = m->misc; +- __entry->synd = m->synd; +- __entry->ipid = m->ipid; +- __entry->ip = m->ip; +- __entry->tsc = m->tsc; +- __entry->ppin = m->ppin; +- __entry->walltime = m->time; +- __entry->cpu = m->extcpu; +- __entry->cpuid = m->cpuid; +- __entry->apicid = m->apicid; +- __entry->socketid = m->socketid; +- __entry->cs = m->cs; +- __entry->bank = m->bank; +- __entry->cpuvendor = m->cpuvendor; +- __entry->microcode = m->microcode; ++ __entry->mcgcap = err->m.mcgcap; ++ __entry->mcgstatus = err->m.mcgstatus; ++ __entry->status = err->m.status; ++ __entry->addr = err->m.addr; ++ __entry->misc = err->m.misc; ++ __entry->synd = err->m.synd; ++ __entry->ipid = err->m.ipid; ++ __entry->ip = err->m.ip; ++ __entry->tsc = err->m.tsc; ++ __entry->ppin = err->m.ppin; ++ __entry->walltime = err->m.time; ++ __entry->cpu = err->m.extcpu; ++ __entry->cpuid = err->m.cpuid; ++ __entry->apicid = err->m.apicid; ++ __entry->socketid = err->m.socketid; ++ __entry->cs = err->m.cs; ++ __entry->bank = err->m.bank; ++ __entry->cpuvendor = err->m.cpuvendor; ++ __entry->microcode = err->m.microcode; + ), + + TP_printk("CPU: %d, MCGc/s: %llx/%llx, MC%d: %016Lx, IPID: %016Lx, ADDR: %016Lx, MISC: %016Lx, SYND: %016Lx, RIP: %02x:<%016Lx>, TSC: %llx, PPIN: %llx, vendor: %u, CPUID: %x, time: %llu, socket: %u, APIC: %x, microcode: %x", +-- +2.53.0 + diff --git a/queue-6.12/x86-mce-inject-remove-call-to-mce_notify_irq.patch b/queue-6.12/x86-mce-inject-remove-call-to-mce_notify_irq.patch new file mode 100644 index 0000000000..80e03746c2 --- /dev/null +++ b/queue-6.12/x86-mce-inject-remove-call-to-mce_notify_irq.patch @@ -0,0 +1,137 @@ +From 009767522aa3cc5b744e7b3473b7eb7aaf94a1e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 16:33:48 +0200 +Subject: x86/mce/inject: Remove call to mce_notify_irq() + +From: Nikolay Borisov + +[ Upstream commit 6447828875b7d768e4ef0f58765b4bd4e16bcf18 ] + +The call to mce_notify_irq() has been there since the initial version of +the soft inject mce machinery, introduced in + + ea149b36c7f5 ("x86, mce: add basic error injection infrastructure"). + +At that time it was functional since injecting an MCE resulted in the +following call chain: + + raise_mce() + ->machine_check_poll() + ->mce_log() - sets notfiy_user_bit + ->mce_notify_user() (current mce_notify_irq) consumed the bit and called the + usermode helper. + +However, with the introduction of + + 011d82611172 ("RAS: Add a Corrected Errors Collector") + +the code got moved around and the usermode helper began to be called via the +early notifier mce_first_notifier() rendering the call in raise_local() +defunct as the mce_need_notify bit (ex notify_user) is only being set from the +early notifier. + +Remove the noop call and make mce_notify_irq() static. + +No functional changes. + +Signed-off-by: Nikolay Borisov +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20250225143348.268469-1-nik.borisov@suse.com +Stable-dep-of: ea324444ece9 ("x86/mce: Restore MCA polling interval halving") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/mce.h | 2 -- + arch/x86/kernel/cpu/mce/core.c | 44 ++++++++++++++++---------------- + arch/x86/kernel/cpu/mce/inject.c | 1 - + 3 files changed, 22 insertions(+), 25 deletions(-) + +diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h +index 02e666fe73ec7..e350ef55c501d 100644 +--- a/arch/x86/include/asm/mce.h ++++ b/arch/x86/include/asm/mce.h +@@ -274,8 +274,6 @@ enum mcp_flags { + + void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); + +-bool mce_notify_irq(void); +- + DECLARE_PER_CPU(struct mce, injectm); + + /* Disable CMCI/polling for MCA bank claimed by firmware */ +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 700568ee686f0..d01cc1f33a41e 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -580,6 +580,28 @@ bool mce_is_correctable(struct mce *m) + } + EXPORT_SYMBOL_GPL(mce_is_correctable); + ++/* ++ * Notify the user(s) about new machine check events. ++ * Can be called from interrupt context, but not from machine check/NMI ++ * context. ++ */ ++static bool mce_notify_irq(void) ++{ ++ /* Not more than two messages every minute */ ++ static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); ++ ++ if (test_and_clear_bit(0, &mce_need_notify)) { ++ mce_work_trigger(); ++ ++ if (__ratelimit(&ratelimit)) ++ pr_info(HW_ERR "Machine check events logged\n"); ++ ++ return true; ++ } ++ ++ return false; ++} ++ + static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +@@ -1771,28 +1793,6 @@ static void mce_timer_delete_all(void) + del_timer_sync(&per_cpu(mce_timer, cpu)); + } + +-/* +- * Notify the user(s) about new machine check events. +- * Can be called from interrupt context, but not from machine check/NMI +- * context. +- */ +-bool mce_notify_irq(void) +-{ +- /* Not more than two messages every minute */ +- static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); +- +- if (test_and_clear_bit(0, &mce_need_notify)) { +- mce_work_trigger(); +- +- if (__ratelimit(&ratelimit)) +- pr_info(HW_ERR "Machine check events logged\n"); +- +- return true; +- } +- return false; +-} +-EXPORT_SYMBOL_GPL(mce_notify_irq); +- + static void __mcheck_cpu_mce_banks_init(void) + { + struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); +diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c +index 313fe682db339..06e3cf7229ce9 100644 +--- a/arch/x86/kernel/cpu/mce/inject.c ++++ b/arch/x86/kernel/cpu/mce/inject.c +@@ -229,7 +229,6 @@ static int raise_local(void) + } else if (m->status) { + pr_info("Starting machine check poll CPU %d\n", cpu); + raise_poll(m); +- mce_notify_irq(); + pr_info("Machine check poll done on CPU %d\n", cpu); + } else + m->finished = 0; +-- +2.53.0 + diff --git a/queue-6.12/x86-mce-make-four-functions-return-bool.patch b/queue-6.12/x86-mce-make-four-functions-return-bool.patch new file mode 100644 index 0000000000..1d7d5295b4 --- /dev/null +++ b/queue-6.12/x86-mce-make-four-functions-return-bool.patch @@ -0,0 +1,184 @@ +From 294d5b808dd154d4e595115fbf28f73f4ec5dc33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Dec 2024 22:00:59 +0800 +Subject: x86/mce: Make four functions return bool + +From: Qiuxu Zhuo + +[ Upstream commit c46945c9cac8437a674edb9d8fbe71511fb4acee ] + +Make those functions whose callers only care about success or failure return +a boolean value for better readability. Also, update the call sites +accordingly as the polarities of all the return values have been flipped. + +No functional changes. + +Suggested-by: Thomas Gleixner +Signed-off-by: Qiuxu Zhuo +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Sohil Mehta +Reviewed-by: Yazen Ghannam +Link: https://lore.kernel.org/r/20241212140103.66964-4-qiuxu.zhuo@intel.com +Stable-dep-of: ea324444ece9 ("x86/mce: Restore MCA polling interval halving") +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/core.c | 12 ++++++------ + arch/x86/kernel/cpu/mce/genpool.c | 29 ++++++++++++++--------------- + arch/x86/kernel/cpu/mce/internal.h | 4 ++-- + 3 files changed, 22 insertions(+), 23 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index eeffb49725c25..700568ee686f0 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -151,7 +151,7 @@ EXPORT_PER_CPU_SYMBOL_GPL(injectm); + + void mce_log(struct mce_hw_err *err) + { +- if (!mce_gen_pool_add(err)) ++ if (mce_gen_pool_add(err)) + irq_work_queue(&mce_irq_work); + } + EXPORT_SYMBOL_GPL(mce_log); +@@ -1909,14 +1909,14 @@ static void __mcheck_cpu_check_banks(void) + } + + /* Add per CPU specific workarounds here */ +-static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) ++static bool __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) + { + struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); + struct mca_config *cfg = &mca_cfg; + + if (c->x86_vendor == X86_VENDOR_UNKNOWN) { + pr_info("unknown CPU type - not enabling MCE support\n"); +- return -EOPNOTSUPP; ++ return false; + } + + /* This should be disabled by the BIOS, but isn't always */ +@@ -2010,7 +2010,7 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) + if (cfg->bootlog != 0) + cfg->panic_timeout = 30; + +- return 0; ++ return true; + } + + static bool __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) +@@ -2276,12 +2276,12 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c) + + __mcheck_cpu_cap_init(); + +- if (__mcheck_cpu_apply_quirks(c) < 0) { ++ if (!__mcheck_cpu_apply_quirks(c)) { + mca_cfg.disabled = 1; + return; + } + +- if (mce_gen_pool_init()) { ++ if (!mce_gen_pool_init()) { + mca_cfg.disabled = 1; + pr_emerg("Couldn't allocate MCE records pool!\n"); + return; +diff --git a/arch/x86/kernel/cpu/mce/genpool.c b/arch/x86/kernel/cpu/mce/genpool.c +index d0be6dda0c14b..3ca9c007a6668 100644 +--- a/arch/x86/kernel/cpu/mce/genpool.c ++++ b/arch/x86/kernel/cpu/mce/genpool.c +@@ -94,64 +94,63 @@ bool mce_gen_pool_empty(void) + return llist_empty(&mce_event_llist); + } + +-int mce_gen_pool_add(struct mce_hw_err *err) ++bool mce_gen_pool_add(struct mce_hw_err *err) + { + struct mce_evt_llist *node; + + if (filter_mce(&err->m)) +- return -EINVAL; ++ return false; + + if (!mce_evt_pool) +- return -EINVAL; ++ return false; + + node = (void *)gen_pool_alloc(mce_evt_pool, sizeof(*node)); + if (!node) { + pr_warn_ratelimited("MCE records pool full!\n"); +- return -ENOMEM; ++ return false; + } + + memcpy(&node->err, err, sizeof(*err)); + llist_add(&node->llnode, &mce_event_llist); + +- return 0; ++ return true; + } + +-static int mce_gen_pool_create(void) ++static bool mce_gen_pool_create(void) + { + int mce_numrecords, mce_poolsz, order; + struct gen_pool *gpool; +- int ret = -ENOMEM; + void *mce_pool; + + order = order_base_2(sizeof(struct mce_evt_llist)); + gpool = gen_pool_create(order, -1); + if (!gpool) +- return ret; ++ return false; + + mce_numrecords = max(MCE_MIN_ENTRIES, num_possible_cpus() * MCE_PER_CPU); + mce_poolsz = mce_numrecords * (1 << order); + mce_pool = kmalloc(mce_poolsz, GFP_KERNEL); + if (!mce_pool) { + gen_pool_destroy(gpool); +- return ret; ++ return false; + } +- ret = gen_pool_add(gpool, (unsigned long)mce_pool, mce_poolsz, -1); +- if (ret) { ++ ++ if (gen_pool_add(gpool, (unsigned long)mce_pool, mce_poolsz, -1)) { + gen_pool_destroy(gpool); + kfree(mce_pool); +- return ret; ++ return false; + } + + mce_evt_pool = gpool; + +- return ret; ++ return true; + } + +-int mce_gen_pool_init(void) ++bool mce_gen_pool_init(void) + { + /* Just init mce_gen_pool once. */ + if (mce_evt_pool) +- return 0; ++ return true; + + return mce_gen_pool_create(); + } +diff --git a/arch/x86/kernel/cpu/mce/internal.h b/arch/x86/kernel/cpu/mce/internal.h +index 84f810598231e..95a504ece43e8 100644 +--- a/arch/x86/kernel/cpu/mce/internal.h ++++ b/arch/x86/kernel/cpu/mce/internal.h +@@ -31,8 +31,8 @@ struct mce_evt_llist { + + void mce_gen_pool_process(struct work_struct *__unused); + bool mce_gen_pool_empty(void); +-int mce_gen_pool_add(struct mce_hw_err *err); +-int mce_gen_pool_init(void); ++bool mce_gen_pool_add(struct mce_hw_err *err); ++bool mce_gen_pool_init(void); + struct llist_node *mce_gen_pool_prepare_records(void); + + int mce_severity(struct mce *a, struct pt_regs *regs, char **msg, bool is_excp); +-- +2.53.0 + diff --git a/queue-6.12/x86-mce-make-several-functions-return-bool.patch b/queue-6.12/x86-mce-make-several-functions-return-bool.patch new file mode 100644 index 0000000000..a98e7bce14 --- /dev/null +++ b/queue-6.12/x86-mce-make-several-functions-return-bool.patch @@ -0,0 +1,199 @@ +From c1bf98397ce2be68ea748a94755f77e3b04e3d95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Dec 2024 22:00:57 +0800 +Subject: x86/mce: Make several functions return bool + +From: Qiuxu Zhuo + +[ Upstream commit c845cb8dbd2e1a804babfd13648026c3a7cfbc0b ] + +Make several functions that return 0 or 1 return a boolean value for +better readability. + +No functional changes are intended. + +Signed-off-by: Qiuxu Zhuo +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Tony Luck +Reviewed-by: Nikolay Borisov +Reviewed-by: Sohil Mehta +Reviewed-by: Yazen Ghannam +Link: https://lore.kernel.org/r/20241212140103.66964-2-qiuxu.zhuo@intel.com +Stable-dep-of: ea324444ece9 ("x86/mce: Restore MCA polling interval halving") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/mce.h | 4 ++-- + arch/x86/kernel/cpu/mce/amd.c | 10 +++++----- + arch/x86/kernel/cpu/mce/core.c | 22 +++++++++++----------- + arch/x86/kernel/cpu/mce/intel.c | 9 +++++---- + 4 files changed, 23 insertions(+), 22 deletions(-) + +diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h +index 4e45f45673a33..02e666fe73ec7 100644 +--- a/arch/x86/include/asm/mce.h ++++ b/arch/x86/include/asm/mce.h +@@ -254,7 +254,7 @@ static inline void cmci_rediscover(void) {} + static inline void cmci_recheck(void) {} + #endif + +-int mce_available(struct cpuinfo_x86 *c); ++bool mce_available(struct cpuinfo_x86 *c); + bool mce_is_memory_error(struct mce *m); + bool mce_is_correctable(struct mce *m); + bool mce_usable_address(struct mce *m); +@@ -274,7 +274,7 @@ enum mcp_flags { + + void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); + +-int mce_notify_irq(void); ++bool mce_notify_irq(void); + + DECLARE_PER_CPU(struct mce, injectm); + +diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c +index 3011a16c4a947..fd370d871690d 100644 +--- a/arch/x86/kernel/cpu/mce/amd.c ++++ b/arch/x86/kernel/cpu/mce/amd.c +@@ -380,7 +380,7 @@ static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits) + return msr_high_bits & BIT(28); + } + +-static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) ++static bool lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) + { + int msr = (hi & MASK_LVTOFF_HI) >> 20; + +@@ -388,7 +388,7 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) + pr_err(FW_BUG "cpu %d, failed to setup threshold interrupt " + "for bank %d, block %d (MSR%08X=0x%x%08x)\n", b->cpu, + b->bank, b->block, b->address, hi, lo); +- return 0; ++ return false; + } + + if (apic != msr) { +@@ -398,15 +398,15 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi) + * was set is reserved. Return early here: + */ + if (mce_flags.smca) +- return 0; ++ return false; + + pr_err(FW_BUG "cpu %d, invalid threshold interrupt offset %d " + "for bank %d, block %d (MSR%08X=0x%x%08x)\n", + b->cpu, apic, b->bank, b->block, b->address, hi, lo); +- return 0; ++ return false; + } + +- return 1; ++ return true; + }; + + /* Reprogram MCx_MISC MSR behind this threshold bank. */ +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 8735ca370803f..eeffb49725c25 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -488,10 +488,10 @@ static noinstr void mce_gather_info(struct mce_hw_err *err, struct pt_regs *regs + } + } + +-int mce_available(struct cpuinfo_x86 *c) ++bool mce_available(struct cpuinfo_x86 *c) + { + if (mca_cfg.disabled) +- return 0; ++ return false; + return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA); + } + +@@ -1776,7 +1776,7 @@ static void mce_timer_delete_all(void) + * Can be called from interrupt context, but not from machine check/NMI + * context. + */ +-int mce_notify_irq(void) ++bool mce_notify_irq(void) + { + /* Not more than two messages every minute */ + static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); +@@ -1787,9 +1787,9 @@ int mce_notify_irq(void) + if (__ratelimit(&ratelimit)) + pr_info(HW_ERR "Machine check events logged\n"); + +- return 1; ++ return true; + } +- return 0; ++ return false; + } + EXPORT_SYMBOL_GPL(mce_notify_irq); + +@@ -2013,25 +2013,25 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) + return 0; + } + +-static int __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) ++static bool __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) + { + if (c->x86 != 5) +- return 0; ++ return false; + + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + intel_p5_mcheck_init(c); + mce_flags.p5 = 1; +- return 1; ++ return true; + case X86_VENDOR_CENTAUR: + winchip_mcheck_init(c); + mce_flags.winchip = 1; +- return 1; ++ return true; + default: +- return 0; ++ return false; + } + +- return 0; ++ return false; + } + + /* +diff --git a/arch/x86/kernel/cpu/mce/intel.c b/arch/x86/kernel/cpu/mce/intel.c +index bb0a60b1ed637..2deb6a76723d2 100644 +--- a/arch/x86/kernel/cpu/mce/intel.c ++++ b/arch/x86/kernel/cpu/mce/intel.c +@@ -75,12 +75,12 @@ static u16 cmci_threshold[MAX_NR_BANKS]; + */ + #define CMCI_STORM_THRESHOLD 32749 + +-static int cmci_supported(int *banks) ++static bool cmci_supported(int *banks) + { + u64 cap; + + if (mca_cfg.cmci_disabled || mca_cfg.ignore_ce) +- return 0; ++ return false; + + /* + * Vendor check is not strictly needed, but the initial +@@ -89,10 +89,11 @@ static int cmci_supported(int *banks) + */ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL && + boot_cpu_data.x86_vendor != X86_VENDOR_ZHAOXIN) +- return 0; ++ return false; + + if (!boot_cpu_has(X86_FEATURE_APIC) || lapic_get_maxlvt() < 6) +- return 0; ++ return false; ++ + rdmsrl(MSR_IA32_MCG_CAP, cap); + *banks = min_t(unsigned, MAX_NR_BANKS, cap & 0xff); + return !!(cap & MCG_CMCI_P); +-- +2.53.0 + diff --git a/queue-6.12/x86-mce-restore-mca-polling-interval-halving.patch b/queue-6.12/x86-mce-restore-mca-polling-interval-halving.patch new file mode 100644 index 0000000000..aa09287307 --- /dev/null +++ b/queue-6.12/x86-mce-restore-mca-polling-interval-halving.patch @@ -0,0 +1,138 @@ +From 43ff39a3e61c6036fad00f194d2d12620a5f8e4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:12:00 +0100 +Subject: x86/mce: Restore MCA polling interval halving + +From: Borislav Petkov (AMD) + +[ Upstream commit ea324444ece9f301b5c4ff71b258cc68990c4d61 ] + +RongQing reported that the MCA polling interval doesn't halve when an +error gets logged. It was traced down to the commit in Fixes:, because: + + mce_timer_fn() + |-> mce_poll_banks() + |-> machine_check_poll() + |-> mce_log() + +which will queue the work and return. + +Now, back in mce_timer_fn(): + + /* + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ + if (mce_notify_irq()) + +<--- here we haven't ran the notifier chain yet so mce_need_notify is +not set yet so this won't hit and we won't halve the interval iv. + +Now the notifier chain runs. mce_early_notifier() sets the bit, does +mce_notify_irq(), that clears the bit and then the notifier chain +a little later logs the error. + +So this is a silly timing issue. + +But, that's all unnecessary. + +All it needs to happen here is, the "should we notify of a logged MCE" +mce_notify_irq() asks, should be simply a question to the mce gen pool: +"Are you empty?" + +And that then turns into a simple yes or no answer and it all +JustWorks(tm). + +So do that and also distribute the functionality where it belongs: + - Print that MCE events have been logged in mce_log() + - Trigger the mcelog tool specific work in the first notifier + +As a result, mce_notify_irq() can go now. + +Fixes: 011d82611172 ("RAS: Add a Corrected Errors Collector") +Reported-by: Li RongQing +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Qiuxu Zhuo +Tested-by: Qiuxu Zhuo +Link: https://lore.kernel.org/r/20260112082747.2842-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/core.c | 33 +++++---------------------------- + 1 file changed, 5 insertions(+), 28 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index d01cc1f33a41e..326e273646d8b 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -89,7 +89,6 @@ struct mca_config mca_cfg __read_mostly = { + }; + + static DEFINE_PER_CPU(struct mce_hw_err, hw_errs_seen); +-static unsigned long mce_need_notify; + + /* + * MCA banks polled by the period polling timer for corrected events. +@@ -151,8 +150,10 @@ EXPORT_PER_CPU_SYMBOL_GPL(injectm); + + void mce_log(struct mce_hw_err *err) + { +- if (mce_gen_pool_add(err)) ++ if (mce_gen_pool_add(err)) { ++ pr_info(HW_ERR "Machine check events logged\n"); + irq_work_queue(&mce_irq_work); ++ } + } + EXPORT_SYMBOL_GPL(mce_log); + +@@ -580,28 +581,6 @@ bool mce_is_correctable(struct mce *m) + } + EXPORT_SYMBOL_GPL(mce_is_correctable); + +-/* +- * Notify the user(s) about new machine check events. +- * Can be called from interrupt context, but not from machine check/NMI +- * context. +- */ +-static bool mce_notify_irq(void) +-{ +- /* Not more than two messages every minute */ +- static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); +- +- if (test_and_clear_bit(0, &mce_need_notify)) { +- mce_work_trigger(); +- +- if (__ratelimit(&ratelimit)) +- pr_info(HW_ERR "Machine check events logged\n"); +- +- return true; +- } +- +- return false; +-} +- + static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +@@ -613,9 +592,7 @@ static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + /* Emit the trace record: */ + trace_mce_record(err); + +- set_bit(0, &mce_need_notify); +- +- mce_notify_irq(); ++ mce_work_trigger(); + + return NOTIFY_DONE; + } +@@ -1754,7 +1731,7 @@ static void mce_timer_fn(struct timer_list *t) + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ +- if (mce_notify_irq()) ++ if (!mce_gen_pool_empty()) + iv = max(iv / 2, (unsigned long) HZ/100); + else + iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); +-- +2.53.0 + diff --git a/queue-6.12/x86-xen-fix-xen_e820_swap_entry_with_ram.patch b/queue-6.12/x86-xen-fix-xen_e820_swap_entry_with_ram.patch new file mode 100644 index 0000000000..838839dd8c --- /dev/null +++ b/queue-6.12/x86-xen-fix-xen_e820_swap_entry_with_ram.patch @@ -0,0 +1,39 @@ +From 63dcd5128450d6de2fb340faab1802362bcd9ca2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 12:24:17 +0200 +Subject: x86/xen: Fix xen_e820_swap_entry_with_ram() + +From: Juergen Gross + +[ Upstream commit 28e03f78e69cf6628b81f24777799778528a84c1 ] + +When swapping a not page-aligned E820 map entry with RAM, the start +address of the modified entry is calculated wrong (the offset into the +page is subtracted instead of being added to the page address). + +Fixes: be35d91c8880 ("xen: tolerate ACPI NVS memory overlapping with Xen allocated memory") +Reported-by: Jan Beulich +Reviewed-by: Jan Beulich +Signed-off-by: Juergen Gross +Message-ID: <20260505102417.208138-1-jgross@suse.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index 3823e52aef523..6260f65a78c5e 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -655,7 +655,7 @@ static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry) + /* Fill new entry (keep size and page offset). */ + entry->type = swap_entry->type; + entry->addr = entry_end - swap_size + +- swap_addr - swap_entry->addr; ++ swap_entry->addr - swap_addr; + entry->size = swap_entry->size; + + /* Convert old entry to RAM, align to pages. */ +-- +2.53.0 + diff --git a/queue-6.18/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch b/queue-6.18/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch new file mode 100644 index 0000000000..689fe51f26 --- /dev/null +++ b/queue-6.18/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch @@ -0,0 +1,117 @@ +From a4a8edb221c4b3a38a87c04d68a87ab446a4a8a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 23:30:22 +0800 +Subject: 9p/trans_xen: make cleanup idempotent after dataring alloc errors + +From: Yufan Chen + +[ Upstream commit 72cb9ee4f6d80962df17c9763b14e62e28fd85a2 ] + +xen_9pfs_front_alloc_dataring() tears down resources on failure but +leaves ring fields stale. If xen_9pfs_front_init() later jumps to the +common error path, xen_9pfs_front_free() may touch the same resources +again, causing duplicate/invalid gnttab_end_foreign_access() calls and +potentially dereferencing a freed intf pointer. + +Initialize dataring sentinels before allocation, gate teardown on those +sentinels, and clear ref/intf/data/irq immediately after each release. + +This keeps cleanup idempotent for partially initialized rings and +prevents repeated teardown during init failure handling. + +Signed-off-by: Yufan Chen +Reviewed-by: Stefano Stabellini +Message-ID: <20260324153023.86853-2-ericterminal@gmail.com> +Signed-off-by: Dominique Martinet +Signed-off-by: Sasha Levin +--- + net/9p/trans_xen.c | 51 +++++++++++++++++++++++++++++++++------------- + 1 file changed, 37 insertions(+), 14 deletions(-) + +diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c +index 068d57515dd58..e072cffebaa7d 100644 +--- a/net/9p/trans_xen.c ++++ b/net/9p/trans_xen.c +@@ -280,25 +280,33 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv) + + cancel_work_sync(&ring->work); + +- if (!priv->rings[i].intf) ++ if (!ring->intf) + break; +- if (priv->rings[i].irq > 0) +- unbind_from_irqhandler(priv->rings[i].irq, ring); +- if (priv->rings[i].data.in) { +- for (j = 0; +- j < (1 << priv->rings[i].intf->ring_order); ++ if (ring->irq >= 0) { ++ unbind_from_irqhandler(ring->irq, ring); ++ ring->irq = -1; ++ } ++ if (ring->data.in) { ++ for (j = 0; j < (1 << ring->intf->ring_order); + j++) { + grant_ref_t ref; + +- ref = priv->rings[i].intf->ref[j]; ++ ref = ring->intf->ref[j]; + gnttab_end_foreign_access(ref, NULL); ++ ring->intf->ref[j] = INVALID_GRANT_REF; + } +- free_pages_exact(priv->rings[i].data.in, +- 1UL << (priv->rings[i].intf->ring_order + +- XEN_PAGE_SHIFT)); ++ free_pages_exact(ring->data.in, ++ 1UL << (ring->intf->ring_order + ++ XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; + } +- gnttab_end_foreign_access(priv->rings[i].ref, NULL); +- free_page((unsigned long)priv->rings[i].intf); ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } + kfree(priv->rings); + } +@@ -331,6 +339,12 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + int ret = -ENOMEM; + void *bytes = NULL; + ++ ring->intf = NULL; ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ ring->ref = INVALID_GRANT_REF; ++ ring->irq = -1; ++ + init_waitqueue_head(&ring->wq); + spin_lock_init(&ring->lock); + INIT_WORK(&ring->work, p9_xen_response); +@@ -376,9 +390,18 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + for (i--; i >= 0; i--) + gnttab_end_foreign_access(ring->intf->ref[i], NULL); + free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; ++ } ++ if (ring->intf) { ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } +- gnttab_end_foreign_access(ring->ref, NULL); +- free_page((unsigned long)ring->intf); ++ ring->irq = -1; + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch b/queue-6.18/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch new file mode 100644 index 0000000000..88d8be35fd --- /dev/null +++ b/queue-6.18/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch @@ -0,0 +1,78 @@ +From 360fe5dafde5394cbb394d565a668587d5c6951c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 12:39:01 -0700 +Subject: accel/qaic: Add overflow check to remap_pfn_range during mmap + +From: Zack McKevitt + +[ Upstream commit aa16b2bc0f02709919e2435f531406531e5bcc69 ] + +The call to remap_pfn_range in qaic_gem_object_mmap is susceptible to +(re)mapping beyond the VMA if the BO is too large. This can cause use +after free issues when munmap() unmaps only the VMA region and not the +additional mappings. To prevent this, check the remaining size of the +VMA before remapping and truncate the remapped length if sg->length is +too large. + +Reported-by: Lukas Maar +Fixes: ff13be830333 ("accel/qaic: Add datapath") +Reviewed-by: Karol Wachowski +Signed-off-by: Zack McKevitt +Reviewed-by: Jeff Hugo +[jhugo: fix braces from checkpatch --strict] +Signed-off-by: Jeff Hugo +Link: https://patch.msgid.link/20260430193858.1178641-1-zachary.mckevitt@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/accel/qaic/qaic_data.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c +index c4f117edb266e..3335c92b0d7dc 100644 +--- a/drivers/accel/qaic/qaic_data.c ++++ b/drivers/accel/qaic/qaic_data.c +@@ -605,8 +605,11 @@ static const struct vm_operations_struct drm_vm_ops = { + static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) + { + struct qaic_bo *bo = to_qaic_bo(obj); ++ unsigned long remap_start; + unsigned long offset = 0; ++ unsigned long remap_end; + struct scatterlist *sg; ++ unsigned long length; + int ret = 0; + + if (drm_gem_is_imported(obj)) +@@ -614,11 +617,27 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc + + for (sg = bo->sgt->sgl; sg; sg = sg_next(sg)) { + if (sg_page(sg)) { ++ /* if sg is too large for the VMA, so truncate it to fit */ ++ if (check_add_overflow(vma->vm_start, offset, &remap_start)) ++ return -EINVAL; ++ if (check_add_overflow(remap_start, sg->length, &remap_end)) ++ return -EINVAL; ++ ++ if (remap_end > vma->vm_end) { ++ if (check_sub_overflow(vma->vm_end, remap_start, &length)) ++ return -EINVAL; ++ } else { ++ length = sg->length; ++ } ++ ++ if (length == 0) ++ goto out; ++ + ret = remap_pfn_range(vma, vma->vm_start + offset, page_to_pfn(sg_page(sg)), +- sg->length, vma->vm_page_prot); ++ length, vma->vm_page_prot); + if (ret) + goto out; +- offset += sg->length; ++ offset += length; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-6.18/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..c57754997c --- /dev/null +++ b/queue-6.18/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From 3d4aa18faaea92333d8d82498d83de94424a40a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 4166090db6420..0535c5714d6f3 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1078,6 +1078,8 @@ static unsigned int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-6.18/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-6.18/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..3d24a6fe42 --- /dev/null +++ b/queue-6.18/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From 07199b716008e0cc54b36e990fa7464f8812c326 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 0535c5714d6f3..b7cd84713b372 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1281,16 +1281,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-6.18/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-6.18/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..c3ae5ed78c --- /dev/null +++ b/queue-6.18/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From 3997517f62881aae8e79ccb99905e27f593bc9dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index bd40d5f088104..10d5c08252ffe 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -117,6 +117,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-6.18/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-6.18/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..02c19be2af --- /dev/null +++ b/queue-6.18/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 075c27feaf35d007b17b29b78136ede0edbed671 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 4cf959017c9d5..8478a5fc8154d 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -980,10 +980,12 @@ static int onyx_i2c_probe(struct i2c_client *client) + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.18/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-6.18/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..2a7d1e6b77 --- /dev/null +++ b/queue-6.18/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From 2ad47ef8182e3a15ff82a5cf1fdd7c0cf8e6a9de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index 7085e0b93e29b..98512f13a9ff9 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client) + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.18/alsa-asihpi-detect-truncated-control-names.patch b/queue-6.18/alsa-asihpi-detect-truncated-control-names.patch new file mode 100644 index 0000000000..30e7a3f489 --- /dev/null +++ b/queue-6.18/alsa-asihpi-detect-truncated-control-names.patch @@ -0,0 +1,93 @@ +From 0465fae05f9ce7fd62618707174b3f79f6cda272 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 18:28:08 +0800 +Subject: ALSA: asihpi: detect truncated control names + +From: Pengpeng Hou + +[ Upstream commit 18d4969e22cc3ff738257e1d7738aafc65a6d2d2 ] + +asihpi_ctl_init() builds mixer control names in the fixed 44-byte +hpi_ctl->name buffer with sprintf(). + +This is not only a defensive cleanup. The current in-tree name tables and +format strings can already exceed 44 bytes. For example, + + "Bitstream 0 Internal 0 Monitor Playback Volume" + +is 46 characters before the trailing NUL, so the current sprintf() call +writes past the end of hpi_ctl->name. + +The generated control name is used as the ALSA control element key, so +blindly truncating it is not sufficient. Switch the formatting to +snprintf() and emit an error if truncation happens, showing the +truncated name while still keeping the write bounded to hpi_ctl->name. + +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260328102808.33969-1-pengpeng@iscas.ac.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/asihpi/asihpi.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c +index fd0a67b772d1f..89724f69329d8 100644 +--- a/sound/pci/asihpi/asihpi.c ++++ b/sound/pci/asihpi/asihpi.c +@@ -1362,6 +1362,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + struct hpi_control *hpi_ctl, + char *name) + { ++ int len; + char *dir; + memset(snd_control, 0, sizeof(*snd_control)); + snd_control->name = hpi_ctl->name; +@@ -1384,23 +1385,30 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + dir = "Playback "; /* PCM Playback source, or output node */ + + if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) +- sprintf(hpi_ctl->name, "%s %d %s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + else if (hpi_ctl->dst_node_type) { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + } else { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ dir, name); + } ++ ++ if (len >= sizeof(hpi_ctl->name)) ++ pr_err("asihpi: truncated control name: %s\n", ++ hpi_ctl->name); + } + + /*------------------------------------------------------------ +-- +2.53.0 + diff --git a/queue-6.18/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-6.18/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..94837b716c --- /dev/null +++ b/queue-6.18/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 73d4b8cc177eb9122cc89f7e95885ba17ec6c5f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 2181442e3a1da..18256a6b738d6 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -185,6 +185,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset, + tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-6.18/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..f05aaa1c2d --- /dev/null +++ b/queue-6.18/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From b78315096c424cbc515cb943f7b990c67a9798c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/core/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/core/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c +index 7b276047f85a7..c897fc443467c 100644 +--- a/sound/hda/core/hdmi_chmap.c ++++ b/sound/hda/core/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch b/queue-6.18/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch new file mode 100644 index 0000000000..2138573680 --- /dev/null +++ b/queue-6.18/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch @@ -0,0 +1,62 @@ +From 884ae31a397cf3d7a525bd5787633788f82e2870 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:25:15 +0000 +Subject: ALSA: hda: cs35l41: Fix boost type for HP Dragonfly 13.5 inch G4 + +From: Leonard Lausen + +[ Upstream commit 6389dbd5c4a2d819ec342f89bd65883ab021278e ] + +The HP Dragonfly 13.5 inch G4 (SSID 103C8B63) has _DSD properties in +ACPI firmware with valid reset-gpios and cs-gpios for the four CS35L41 +amplifiers on SPI. + +However, the _DSD specifies cirrus,boost-type as Internal (0), while +the hardware requires External Boost. With Internal Boost configured, +the amplifiers trigger "Amp short error" when audio is played at +moderate-to-high volume, eventually shutting down entirely. + +Add a configuration table entry to override the boost type to +External, similar to the existing workaround for 103C89C6. All GPIO +indices are set to -1 since the _DSD provides valid reset-gpios and +cs-gpios. + +Confirmed on BIOS V90 01.11.00 (January 2026), the latest available. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=219520 +Originally-by: Nicholas Wang +Signed-off-by: Leonard Lausen +Link: https://patch.msgid.link/db84dcf91bc8dbd217b35572b177d967655ff903@lausen.nl +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l41_hda_property.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c +index 16d5ea77192f0..732ae534db360 100644 +--- a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c ++++ b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c +@@ -55,6 +55,11 @@ static const struct cs35l41_config cs35l41_config_table[] = { + { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 }, ++/* ++ * Device 103C8B63 has _DSD with valid reset-gpios and cs-gpios, however the ++ * boost type is incorrectly set to Internal. Override to External Boost. ++ */ ++ { "103C8B63", 4, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, -1, -1, -1, 0, 0, 0 }, + { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, +@@ -475,6 +480,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { + { "CSC3551", "103C8A30", generic_dsd_config }, + { "CSC3551", "103C8A31", generic_dsd_config }, + { "CSC3551", "103C8A6E", generic_dsd_config }, ++ { "CSC3551", "103C8B63", generic_dsd_config }, + { "CSC3551", "103C8BB3", generic_dsd_config }, + { "CSC3551", "103C8BB4", generic_dsd_config }, + { "CSC3551", "103C8BDD", generic_dsd_config }, +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch b/queue-6.18/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch new file mode 100644 index 0000000000..49df176990 --- /dev/null +++ b/queue-6.18/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch @@ -0,0 +1,48 @@ +From 530f88ed0e87ba9045496fab94ddeda9248e843b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:12:38 +0800 +Subject: ALSA: hda: cs35l41: Put ACPI device on missing physical node + +From: Shuhao Fu + +[ Upstream commit fca7401fe37f7abc6e54147ea560f37279231137 ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers must balance it with acpi_dev_put(). + +cs35l41_hda_read_acpi() stores the returned ACPI device in +cs35l41->dacpi. That reference is normally released by the later +probe cleanup or the remove path, but the NULL-check on +physdev exits before either of those paths can run. + +Drop the lookup reference before returning -ENODEV. + +Fixes: c34b04cc6178 ("ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_hda_read_acpi()") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428081238.GA1659932@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l41_hda.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c +index 21e00055c0c44..47263c5a021cb 100644 +--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c +@@ -1901,8 +1901,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i + + cs35l41->dacpi = adev; + physdev = get_device(acpi_get_first_physical_node(adev)); +- if (!physdev) ++ if (!physdev) { ++ acpi_dev_put(adev); + return -ENODEV; ++ } + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch b/queue-6.18/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch new file mode 100644 index 0000000000..f6fe52bfbb --- /dev/null +++ b/queue-6.18/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch @@ -0,0 +1,44 @@ +From 66be3e4b583ff7a93cfe04ff0baeae8c9637ea53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:01:39 +0800 +Subject: ALSA: hda: cs35l56: Put ACPI device after setting companion + +From: Shuhao Fu + +[ Upstream commit aa2fbece1b07954ef26488c800d126a36a8ab93e ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers are expected to balance it with acpi_dev_put(). + +When no companion is already attached, cs35l56_hda_read_acpi() looks +up an ACPI device and sets it with ACPI_COMPANION_SET(), but leaves +the lookup reference held. + +ACPI_COMPANION_SET() does not take ownership of that reference, so +drop it with acpi_dev_put() after attaching the companion. + +Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428080139.GA1649104@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l56_hda.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c +index 79c15e21d4bcb..1d25fe01066ee 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c +@@ -949,6 +949,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); ++ acpi_dev_put(adev); + } + + /* Initialize things that could be overwritten by a fixup */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch b/queue-6.18/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch new file mode 100644 index 0000000000..30ad75d938 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch @@ -0,0 +1,36 @@ +From 206ec64cb0d9ca9c7bce39cf910d7f62d3110632 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 15:20:25 -0600 +Subject: ALSA: hda/realtek: Add quirk for Acer PT316-51S headset mic + +From: Faye Nichols + +[ Upstream commit a7b56be59b47f4195ddc79ecab238c4401a60bbb ] + +The Acer PT316-51S (PCI SSID 1025:160e) with ALC287 codec does not +detect the headset microphone due to missing BIOS pin configuration +for pin 0x19. Apply ALC2XX_FIXUP_HEADSET_MIC to enable it. + +Signed-off-by: Faye Nichols +Link: https://patch.msgid.link/20260413212645.117119-1-faye.opensource@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index abb431d8a5001..f685b5dd3a2e7 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -6548,6 +6548,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), + SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch b/queue-6.18/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch new file mode 100644 index 0000000000..5bdbbb1c30 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch @@ -0,0 +1,80 @@ +From f881f64231ea52c9dc4d2f77a0c465e9eef6758e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:40:28 +0800 +Subject: ALSA: hda/realtek: Add quirk for CSL Unity BF24B + +From: Zhang Heng + +[ Upstream commit de65275fc94e2e0acc79bd016d60889bf251ccd9 ] + +The CSL Unity BF24B all-in-one PC uses a Realtek ALC662 rev3 audio +codec and requires the correct GPIO configuration to enable sound +output from both the speakers and the headphone. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221258 +Signed-off-by: Zhang Heng +Link: https://patch.msgid.link/20260409024028.1297587-1-zhangheng@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc662.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c +index 5073165d1f3cf..3abe41c7315c4 100644 +--- a/sound/hda/codecs/realtek/alc662.c ++++ b/sound/hda/codecs/realtek/alc662.c +@@ -255,6 +255,25 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, + alc_fixup_headset_mode(codec, fix, action); + } + ++static void alc662_fixup_csl_amp(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ struct alc_spec *spec = codec->spec; ++ ++ switch (action) { ++ case HDA_FIXUP_ACT_PRE_PROBE: ++ spec->gpio_mask |= 0x03; ++ spec->gpio_dir |= 0x03; ++ break; ++ case HDA_FIXUP_ACT_INIT: ++ /* need to toggle GPIO to enable the amp */ ++ alc_update_gpio_data(codec, 0x03, true); ++ msleep(100); ++ alc_update_gpio_data(codec, 0x03, false); ++ break; ++ } ++} ++ + enum { + ALC662_FIXUP_ASPIRE, + ALC662_FIXUP_LED_GPIO1, +@@ -313,6 +332,7 @@ enum { + ALC897_FIXUP_HEADSET_MIC_PIN2, + ALC897_FIXUP_UNIS_H3C_X500S, + ALC897_FIXUP_HEADSET_MIC_PIN3, ++ ALC662_FIXUP_CSL_GPIO, + }; + + static const struct hda_fixup alc662_fixups[] = { +@@ -766,11 +786,16 @@ static const struct hda_fixup alc662_fixups[] = { + { } + }, + }, ++ [ALC662_FIXUP_CSL_GPIO] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc662_fixup_csl_amp, ++ }, + }; + + static const struct hda_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), ++ SND_PCI_QUIRK(0x1022, 0xc950, "CSL Unity BF24B", ALC662_FIXUP_CSL_GPIO), + SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch b/queue-6.18/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch new file mode 100644 index 0000000000..1029ce00a2 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch @@ -0,0 +1,47 @@ +From 667b55ac6d2c3c255de53fd4fd93e119c2a8d587 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:18:54 +0800 +Subject: ALSA: hda/realtek: Add quirk for HP Spectre x360 14-ea + +From: songxiebing + +[ Upstream commit 882321ccaeea52dd645dff98bfea2f92b286e673 ] + +HP Spectre x360 Convertible 14-ea0xxx (2021 model or so) +doesn't make produce sound,The Bang & Olufsen speaker amplifier +is not enabled. + +Root causing: +The PCI subsystem ID is 103c:0000 (HP left it unset), while the codec +subsystem ID is 103c:885b. The vendor-wide catch-all +SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED) matches +103c:0000 before the codec SSID fallback is reached, so +ALC245_FIXUP_HP_X360_AMP never applies. + +So add the quirk in alc269_fixup_tbl. + +Reported-by: dzidmail +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221341 +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260413011854.96520-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index f685b5dd3a2e7..45674daa092b6 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -6783,6 +6783,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), ++ HDA_CODEC_QUIRK(0x103c, 0x885b, "HP Spectre x360 14-ea", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch b/queue-6.18/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch new file mode 100644 index 0000000000..9008a65ab7 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch @@ -0,0 +1,45 @@ +From d5dfe8a892bae963649bdf116eb0c04e369f95a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:46:18 +0100 +Subject: ALSA: hda/realtek: Add support for ASUS 2026 Commercial laptops using + CS35L41 HDA + +From: Stefan Binding + +[ Upstream commit 66a6333ba5087b00b7d6cb9ff671f4e2739383b3 ] + +Add support for laptops: +- ASUS PM5406CGA +- ASUS PM5606CGA +- ASUS P5406CCA +- ASUS P5606CCA + +Laptops use 2 CS35L41 Amps with HDA, using Internal boost, with I2C or +SPI. + +Signed-off-by: Stefan Binding +Link: https://patch.msgid.link/20260330134651.443439-3-sbinding@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index ea98cbc4310df..abb431d8a5001 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7172,6 +7172,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3391, "ASUS PM3606CKA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3601, "ASUS PM5406CGA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3611, "ASUS PM5606CGA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3701, "ASUS P5406CCA", ALC245_FIXUP_CS35L41_SPI_2), ++ SND_PCI_QUIRK(0x1043, 0x3711, "ASUS P5606CCA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), +-- +2.53.0 + diff --git a/queue-6.18/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-6.18/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..9dfc0be4ea --- /dev/null +++ b/queue-6.18/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From f3286b73b094bb11ebc6ab0a47189e5eddd343ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 495ff93fcd1db..93b5734810bb0 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1761,6 +1761,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1773,8 +1776,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-6.18/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch b/queue-6.18/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch new file mode 100644 index 0000000000..7e8008d6f9 --- /dev/null +++ b/queue-6.18/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch @@ -0,0 +1,60 @@ +From 70f7b88e86338550b66d02f23c21c34949a8c4ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 20:02:21 -0300 +Subject: ALSA: pcm: Use pcm_lib_apply_appl_ptr() in x32 sync_ptr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1e512ac1254c8e370dd18efe9da4dfc92492cdc5 ] + +snd_pcm_ioctl_sync_ptr_x32() still handles incoming appl_ptr updates +differently from the other SYNC_PTR paths. The native handler and the +32-bit compat handler both pass appl_ptr through pcm_lib_apply_appl_ptr(), +but the x32 handler still writes control->appl_ptr directly. + +That direct assignment skips the common appl_ptr validation against +runtime->boundary and also bypasses the substream ack() callback. +This makes the x32 ioctl path behave differently from the native and +compat32 cases, and it can miss the driver notification that explicit +appl_ptr synchronization relies on. + +Use pcm_lib_apply_appl_ptr() for x32 too, so appl_ptr updates are +validated consistently and drivers relying on ack() notifications +see the same behavior. + +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260321-alsa-pcm-x32-sync-ptr-v1-1-02ce655657c6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_compat.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index e86f68f1f23c1..5c846cd9fd8b1 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -430,11 +430,13 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, + if (!boundary) + boundary = 0x7fffffff; + scoped_guard(pcm_stream_lock_irq, substream) { +- /* FIXME: we should consider the boundary for the sync from app */ +- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) +- control->appl_ptr = scontrol.appl_ptr; +- else ++ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { ++ err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr); ++ if (err < 0) ++ return err; ++ } else { + scontrol.appl_ptr = control->appl_ptr % boundary; ++ } + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else +-- +2.53.0 + diff --git a/queue-6.18/alsa-scarlett2-add-missing-error-check-when-initiali.patch b/queue-6.18/alsa-scarlett2-add-missing-error-check-when-initiali.patch new file mode 100644 index 0000000000..6649665179 --- /dev/null +++ b/queue-6.18/alsa-scarlett2-add-missing-error-check-when-initiali.patch @@ -0,0 +1,41 @@ +From 3c7d76d137ced8bbd193ef4ecf76b35644a7c02c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 10:39:14 +0700 +Subject: ALSA: scarlett2: Add missing error check when initialise Autogain + Status + +From: Robertus Diawan Chris + +[ Upstream commit c0e4fffc0f474b7ed10adee4ab2bc1a66d36fc72 ] + +When initialise new control with scarlett2_add_new_ctl() function for +Autogain Status, scarlett2_add_new_ctl() might throw an error. So, add +error check after initialise new control for Autogain Status. + +This is reported by Coverity Scan with CID 1598781 as UNUSED_VALUE. + +Fixes: 0a995e38dc44 ("ALSA: scarlett2: Add support for software-controllable input gain") +Signed-off-by: Robertus Diawan Chris +Link: https://patch.msgid.link/20260508033914.111596-1-robertusdchris@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index a75a4610663e9..34be98288887c 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -6707,6 +6707,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_status_ctl, + i, 1, s, &private->autogain_status_ctls[i]); ++ if (err < 0) ++ return err; + } + + /* Add autogain target controls */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch b/queue-6.18/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch new file mode 100644 index 0000000000..412fb45824 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch @@ -0,0 +1,47 @@ +From f5b47bec67abc37d369101355ebffa9f5b3432a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 08:21:37 +0000 +Subject: ALSA: usb-audio: Add iface reset and delay quirk for HUAWEI USB-C + HEADSET + +From: Lianqin Hu + +[ Upstream commit 9575766a682f50ec4bcb85ecd438685bdc09f9cc ] + +Setting up the interface when suspended/resumeing fail on this card. +Adding a reset and delay quirk will eliminate this problem. + +usb 1-1: new full-speed USB device number 2 using xhci-hcd +usb 1-1: New USB device found, idVendor=12d1, idProduct=3a07 +usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +usb 1-1: Product: HUAWEI USB-C HEADSET +usb 1-1: Manufacturer: bestechnic +usb 1-1: SerialNumber: 0296C100000000000000000000000 + +Signed-off-by: Lianqin Hu +Link: https://patch.msgid.link/TYUPR06MB62176A18EA7A9DD0AC2826BCD2582@TYUPR06MB6217.apcprd06.prod.outlook.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 1b4cfc2b68f9d..59b4487cf9fb8 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2282,8 +2282,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ + QUIRK_FLAG_GET_SAMPLE_RATE), +- DEVICE_FLG(0x12d1, 0x3a07, /* Huawei Technologies Co., Ltd. */ +- QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), ++ DEVICE_FLG(0x12d1, 0x3a07, /* HUAWEI USB-C HEADSET */ ++ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE | ++ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch b/queue-6.18/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch new file mode 100644 index 0000000000..3be3e23f92 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch @@ -0,0 +1,43 @@ +From 4b3c39f1dbae31d05e64abf2947130186f3f1ea9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 19:01:23 -0600 +Subject: ALSA: usb-audio: Add quirk entries for NexiGo N930W webcam + +From: Johnathan Penberthy + +[ Upstream commit 17bc5dd49214b50c9eb6df0fad1d1aea287dd078 ] + +The NexiGo N930W 60fps webcam (USB ID 3443:930d) hits the same +'cannot get freq at ep 0x84' error in snd-usb-audio as its sibling +N930AF (1bcf:2283). Without QUIRK_FLAG_GET_SAMPLE_RATE the ADC clock +is never configured and the microphone streams only zero samples. + +Testing on Linux 6.17 with QUIRK_FLAG_GET_SAMPLE_RATE | +QUIRK_FLAG_MIC_RES_16 (via quirk_alias=3443930d:1bcf2283) confirmed +the microphone captures real audio after a cold USB re-enumeration. +Adding a native quirk_flags_table entry avoids the alias workaround. + +Signed-off-by: Johnathan Penberthy +Link: https://patch.msgid.link/20260417010123.3080904-1-johnathan.penberthy@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 2fa10b52fcfef..66efba7a533dc 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2409,6 +2409,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), + DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), ++ DEVICE_FLG(0x3443, 0x930d, /* NexiGo N930W 60fps Webcam */ ++ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */ + QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch b/queue-6.18/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch new file mode 100644 index 0000000000..a307be7e8b --- /dev/null +++ b/queue-6.18/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch @@ -0,0 +1,55 @@ +From fb36257a3fcb7228d8fd2ba42058ab0ef9965c12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 02:33:05 +0800 +Subject: ALSA: usb-audio: Add quirk flags for Feaulle Rainbow + +From: Rong Zhang + +[ Upstream commit 4f84e6caf38b05991b3b2afc0ddf4e48c2752d1d ] + +Feaulle Rainbow is a wired USB-C dynamic in-ear monitor (IEM) featuring +active noise cancellation (ANC). + +The supported sample rates are 48000Hz and 96000Hz at 16bit or 24bit, +but it does not support reading the current sample rate and results in +an error message printed to kmsg. Set QUIRK_FLAG_GET_SAMPLE_RATE to skip +the sample rate check. + +Its playback mixer reports val = -15360/0/128. Setting -15360 (-60dB) +mutes the playback, so QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE is needed. + +Add a quirk table entry matching VID/PID=0x0e0b/0xfa01 and applying +the mentioned quirk flags, so that it can work properly. + +Quirky device sample: + + usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00 + usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + usb 7-1: Product: Feaulle Rainbow + usb 7-1: Manufacturer: Generic + usb 7-1: SerialNumber: 20210726905926 + +Signed-off-by: Rong Zhang +Link: https://patch.msgid.link/20260409-feaulle-rainbow-v1-1-09179e09000d@rong.moe +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 59b4487cf9fb8..2fa10b52fcfef 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2272,6 +2272,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), ++ DEVICE_FLG(0x0e0b, 0xfa01, /* Feaulle Rainbow */ ++ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ + QUIRK_FLAG_FIXED_RATE), + DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch b/queue-6.18/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch new file mode 100644 index 0000000000..c7e39c28d0 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch @@ -0,0 +1,212 @@ +From 101acfc6f58ea8de3a122edcc52c7ac8c9aedc49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 11:08:41 +0000 +Subject: ALSA: usb-audio: Add quirks for Arturia AF16Rig + +From: Phil Willoughby + +[ Upstream commit 0da18c2dd1cc2a026416222ed206e2f269edf055 ] + +The AF16Rig supports 34 channels at 44.1k/48k, 18 channels at 88.2k/96k +and 10 channels at 176.4k/192k. + +This quirks is necessary because the automatic probing process we would +otherwise use fails. The root cause of that is that the AF16Rig clock is +not readable (its descriptor says that it is but the reads fail). + +Except as described below, the values in the audio format quirks were +copied from the USB descriptors of the device. The rate information is +from the datasheet of the device. The clock is the internal clock of the +AF16Rig. + +Tested-By: Phil Willoughby +I have tested all the configurations enabled by this patch. + +Cc: Jaroslav Kysela +Cc: Takashi Iwai +Signed-off-by: Phil Willoughby +Link: https://patch.msgid.link/20260328112426.14816-1-willerz@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 165 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 165 insertions(+) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index eafc0d73cca1f..8f79a15055a6a 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -3900,5 +3900,170 @@ YAMAHA_DEVICE(0x7010, "UB99"), + QUIRK_RME_DIGIFACE(0x3f8c), + QUIRK_RME_DIGIFACE(0x3fa0), + ++/* Arturia AudioFuse 16Rig Audio */ ++/* AF16Rig MIDI has USB PID 0xaf21 and appears to work OK without quirks */ ++{ ++ USB_DEVICE(0x1c75, 0xaf20), ++ QUIRK_DRIVER_INFO { ++ .vendor_name = "Arturia", ++ .product_name = "AF16Rig", ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 34, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03b8, ++ .rates = SNDRV_PCM_RATE_44100| ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 44100, ++ .rate_max = 48000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 44100, 48000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 18, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03a8, ++ .rates = SNDRV_PCM_RATE_88200| ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 88200, ++ .rate_max = 96000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 88200, 96000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 10, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 3, ++ .altset_idx = 3, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03e8, ++ .rates = SNDRV_PCM_RATE_176400| ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 176400, ++ .rate_max = 192000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 176400, 192000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 34, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03b8, ++ .rates = SNDRV_PCM_RATE_44100| ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 44100, ++ .rate_max = 48000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 44100, 48000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 18, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 2, ++ .altset_idx = 2, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03a8, ++ .rates = SNDRV_PCM_RATE_88200| ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 88200, ++ .rate_max = 96000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 88200, 96000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 10, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 3, ++ .altset_idx = 3, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03e8, ++ .rates = SNDRV_PCM_RATE_176400| ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 176400, ++ .rate_max = 192000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 176400, 192000 }, ++ .clock = 41, ++ } ++ }, ++ { QUIRK_DATA_IGNORE(3) }, /* Firmware update */ ++ QUIRK_COMPOSITE_END ++ } ++ } ++}, ++ + #undef USB_DEVICE_VENDOR_SPEC + #undef USB_AUDIO_DEVICE +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-add-studio-1824-support.patch b/queue-6.18/alsa-usb-audio-add-studio-1824-support.patch new file mode 100644 index 0000000000..22832b0d73 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-add-studio-1824-support.patch @@ -0,0 +1,80 @@ +From 50096d715e66777a0aaa820d0153f51aa62bc93c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 16:22:16 +0100 +Subject: ALSA: usb-audio: add Studio 1824 support + +From: Frederic Popp + +[ Upstream commit c4791ce96b88a444b04c7089ae2827a3b3ae1877 ] + +Adapt the already implemented support for the Studio 1824c +audio interface to the predecessor Studio 1824. + +Basically just a change adding the +different hardware ID in the relevant places. + +Tested as much as possible. +All implemented functionality seemingly works. + +Signed-off-by: Frederic Popp +Link: https://patch.msgid.link/20260308153334.50433-2-frederic.l.popp@t-online.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/format.c | 4 ++++ + sound/usb/mixer_quirks.c | 3 +++ + sound/usb/mixer_s1810c.c | 2 ++ + 3 files changed, 9 insertions(+) + +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 133595d79d927..12e95af5cc56a 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -452,6 +452,10 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, + if (chip->usb_id == USB_ID(0x194f, 0x010d) && + !s1810c_valid_sample_rate(fp, rate)) + goto skip_rate; ++ /* Filter out invalid rates on Presonus Studio 1824 */ ++ if (chip->usb_id == USB_ID(0x194f, 0x0107) && ++ !s1810c_valid_sample_rate(fp, rate)) ++ goto skip_rate; + + /* Filter out invalid rates on Focusrite devices */ + if (USB_ID_VENDOR(chip->usb_id) == 0x1235 && +diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c +index 7126a2cf9e79b..c6428d7368f5d 100644 +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -4374,6 +4374,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + err = snd_sc1810_init_mixer(mixer); + break; ++ case USB_ID(0x194f, 0x0107): /* Presonus Studio 1824 */ ++ err = snd_sc1810_init_mixer(mixer); ++ break; + case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ + err = snd_bbfpro_controls_create(mixer); + break; +diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c +index 93510aa0dc5ef..d1bf0a6d0bc9e 100644 +--- a/sound/usb/mixer_s1810c.c ++++ b/sound/usb/mixer_s1810c.c +@@ -322,6 +322,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + break; + ++ case USB_ID(0x194f, 0x0107): /* 1824 */ + case USB_ID(0x194f, 0x010d): /* 1824c */ + /* Set all output faders to unity gain */ + a = 0x65; +@@ -641,6 +642,7 @@ int snd_sc1810_init_mixer(struct usb_mixer_interface *mixer) + return ret; + + break; ++ case USB_ID(0x194f, 0x0107): /* Presonus Studio 1824 */ + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + ret = snd_s1810c_switch_init(mixer, &snd_s1824c_mono_sw); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-6.18/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..d91fb50f5d --- /dev/null +++ b/queue-6.18/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From 1d1806185c940ceaf882525c119bdfd08157bc7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 0765250f3a56d..ba302a5f35d8a 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-6.18/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-6.18/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..e4fc2c5225 --- /dev/null +++ b/queue-6.18/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From b8756627bf2f3e7101111ee347825244a500a02b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index 8655bc3d36347..e1e4f444a120b 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -218,8 +218,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -228,9 +229,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-6.18/arm64-tegra-fix-snps-blen-properties.patch b/queue-6.18/arm64-tegra-fix-snps-blen-properties.patch new file mode 100644 index 0000000000..150494e73f --- /dev/null +++ b/queue-6.18/arm64-tegra-fix-snps-blen-properties.patch @@ -0,0 +1,52 @@ +From 4c907cc5af4516a0d5d12f14ae144d805a6272f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 15:33:04 +0100 +Subject: arm64: tegra: Fix snps,blen properties + +From: Thierry Reding + +[ Upstream commit 51f10c527a63dc4a71bce4b40fc53eee78bbbd52 ] + +The snps,blen property of stmmac-axi-config nodes needs to have 7 +entries in total, with unsupported burst lengths listed as 0. + +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/nvidia/tegra234.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +index 5657045c53d90..0491e3473cc44 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +@@ -3618,7 +3618,7 @@ ethernet@6800000 { + snps,axi-config = <&mgbe0_axi_setup>; + + mgbe0_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3660,7 +3660,7 @@ ethernet@6900000 { + snps,axi-config = <&mgbe1_axi_setup>; + + mgbe1_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3702,7 +3702,7 @@ ethernet@6a00000 { + snps,axi-config = <&mgbe2_axi_setup>; + + mgbe2_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +-- +2.53.0 + diff --git a/queue-6.18/asoc-amd-acp-add-asus-hn7306ea-quirk-for-legacy-sdw-.patch b/queue-6.18/asoc-amd-acp-add-asus-hn7306ea-quirk-for-legacy-sdw-.patch new file mode 100644 index 0000000000..c897544a28 --- /dev/null +++ b/queue-6.18/asoc-amd-acp-add-asus-hn7306ea-quirk-for-legacy-sdw-.patch @@ -0,0 +1,45 @@ +From be33c410ca412bc10dbeb6c095d56fc52fc7f169 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 01:33:21 +0900 +Subject: ASoC: amd: acp: add ASUS HN7306EA quirk for legacy SDW machine + +From: Hasun Park + +[ Upstream commit 2594196f4e3bd70782e7cf1e22e3e398cdb74f78 ] + +Add a DMI quirk entry for ASUS HN7306EA in the ACP SoundWire legacy +machine driver. + +Set driver_data to ASOC_SDW_ACP_DMIC for this board so the +platform-specific DMIC quirk path is selected. + +Signed-off-by: Hasun Park +Link: https://patch.msgid.link/20260319163321.30326-1-hasunpark@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-sdw-legacy-mach.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +index 798c73d7e26de..84e6354cffb23 100644 +--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +@@ -119,6 +119,14 @@ static const struct dmi_system_id soc_sdw_quirk_table[] = { + }, + .driver_data = (void *)(ASOC_SDW_ACP_DMIC), + }, ++ { ++ .callback = soc_sdw_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HN7306EA"), ++ }, ++ .driver_data = (void *)(ASOC_SDW_ACP_DMIC), ++ }, + {} + }; + +-- +2.53.0 + diff --git a/queue-6.18/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch b/queue-6.18/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch new file mode 100644 index 0000000000..7d280b2161 --- /dev/null +++ b/queue-6.18/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch @@ -0,0 +1,47 @@ +From ac43fdfc92103e38207e6fc1e9ce3475abef5b87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:45:53 +0200 +Subject: ASoC: amd: yc: Add MSI Vector A16 HX A8WHG to quirk table + +From: Ihor Uzlov + +[ Upstream commit 72dcd84938f5026dc44d0e7e1e68d9d571c113a0 ] + +Add the MSI Vector A16 HX A8WHG (board MS-15MM) to the DMI quirk table +to enable DMIC support. This laptop uses an AMD Ryzen 9 7945HX (Dragon +Range) with the ACP6x audio coprocessor (rev 0x62) and a Realtek ALC274 +codec. The built-in digital microphone is connected via the ACP PDM +interface and requires this DMI entry to be activated. + +Tested on MSI Vector A16 HX A8WHG with kernel 6.8.0-107 (Ubuntu 24.04). +DMIC capture device appears as 'acp6x' and records audio correctly. + +Signed-off-by: Ihor Uzlov +Link: https://patch.msgid.link/20260410094553.24654-1-igor.uzlov@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index d9f145b634f35..0aa4b48ce14c2 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -500,6 +500,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +-- +2.53.0 + diff --git a/queue-6.18/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch b/queue-6.18/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch new file mode 100644 index 0000000000..860dbecf4d --- /dev/null +++ b/queue-6.18/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch @@ -0,0 +1,65 @@ +From 550081b6a8a02f6d7033cd321e109edb86cc2244 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:34:08 +0800 +Subject: ASoC: aw88395: Fix kernel panic caused by invalid GPIO error pointer + +From: wangdicheng + +[ Upstream commit 241ee17ecb6be210f7b231b2a81bfb68871950d0 ] + +In aw88395_i2c_probe(), if `devm_gpiod_get_optional()` fails, it returns +an ERR_PTR() error pointer. The current code only prints a message and +continues execution, leaving `aw88395->reset_gpio` as an invalid pointer. + +Later, in `aw88395_hw_reset()`, this invalid pointer is passed to +`gpiod_set_value_cansleep()`, which dereferences it and causes a kernel +panic. + +For optional GPIOs, `devm_gpiod_get_optional()` returns NULL if the GPIO +is not defined in the DT, which is safe. If it returns an ERR_PTR, it +means a real error occurred (e.g., -EPROBE_DEFER) and the probe must be +aborted. + +Also, since the GPIO is optional, remove the dev_err() log in +aw88395_hw_reset() when the GPIO is missing to match the optional +semantics. This also fixes a potential NULL pointer dereference as +aw_pa is not initialized when aw88395_hw_reset() is called. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428023408.46420-1-wangdich9700@163.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/aw88395/aw88395.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c +index fb563b4c69718..6c5c24941cae1 100644 +--- a/sound/soc/codecs/aw88395/aw88395.c ++++ b/sound/soc/codecs/aw88395/aw88395.c +@@ -456,8 +456,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); + gpiod_set_value_cansleep(aw88395->reset_gpio, 1); + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); +- } else { +- dev_err(aw88395->aw_pa->dev, "%s failed", __func__); + } + } + +@@ -522,9 +520,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) + i2c_set_clientdata(i2c, aw88395); + + aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(aw88395->reset_gpio)) +- dev_info(&i2c->dev, "reset gpio not defined\n"); +- ++ if (IS_ERR(aw88395->reset_gpio)) { ++ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), ++ "failed to get reset gpio\n"); ++ } + /* hardware reset */ + aw88395_hw_reset(aw88395); + +-- +2.53.0 + diff --git a/queue-6.18/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-6.18/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..98090434bf --- /dev/null +++ b/queue-6.18/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From 10f284c78b8e2bec5367dd9b520e6ba30179a733 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index d96e23ec43d4c..cf09b66eb2873 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -848,9 +848,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.18/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch b/queue-6.18/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch new file mode 100644 index 0000000000..c4b1b3402c --- /dev/null +++ b/queue-6.18/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch @@ -0,0 +1,88 @@ +From 13c3c9ac4b9c31e44088dd17b5cbc984a6f82139 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:32:21 +0530 +Subject: ASoC: codecs: wcd937x: fix AUX PA sequencing and mixer controls + +From: Ajay Kumar Nandam + +[ Upstream commit 74c876bfd71b1023029a483d7213015201f62b53 ] + +Enable AUX PA sequencing during AUX DAC DAPM events and keep the +AUX-specific RX supplies enabled while the path is active. + +Add the missing AUX-related mixer controls, including CLSH PA and +DSD left/right switches, so AUX playback can be routed from userspace. + +Signed-off-by: Ajay Kumar Nandam +Link: https://patch.msgid.link/20260420180221.785113-1-ajay.nandam@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd937x.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c +index ed0ff45a89649..03fff7ada137b 100644 +--- a/sound/soc/codecs/wcd937x.c ++++ b/sound/soc/codecs/wcd937x.c +@@ -546,6 +546,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), BIT(2)); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), BIT(4)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(2), BIT(2)); +@@ -562,6 +565,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), 0x00); + break; + } + +@@ -730,10 +736,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); ++ /* Enable AUX PA related RX supplies */ ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), BIT(6)); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), BIT(7)); + enable_irq(wcd937x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->aux_pdm_wd_int); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(2000, 2010); +@@ -2053,7 +2072,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), +- ++ SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-6.18/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..93c1f9d2d8 --- /dev/null +++ b/queue-6.18/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From adc62b090f9dc97d427689a2dd4b36eab5cd85ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index 1e9b1903fae81..dab3a7d917d38 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -289,6 +289,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-6.18/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..4152d7706f --- /dev/null +++ b/queue-6.18/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From c9974646bc2cbe9771f0193a3271140118ea2059 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index ca540a66f22ce..7f7ead9893fef 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -210,6 +210,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-6.18/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..c590b165db --- /dev/null +++ b/queue-6.18/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From ef638950913da0027219936618afa0401aa51372 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index 54c1894ee96ac..7eddac1d5fd52 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -78,6 +78,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -86,6 +88,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-6.18/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch b/queue-6.18/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch new file mode 100644 index 0000000000..60799d924f --- /dev/null +++ b/queue-6.18/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch @@ -0,0 +1,46 @@ +From 16af2a0bab06b5ca0d09c2a5fff243897998792e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 13:30:51 +0800 +Subject: ASoC: mxs-sgtl5000: disable MCLK on error paths of + mxs_sgtl5000_probe() + +From: Haoxiang Li + +[ Upstream commit c8ef13d692f19cdbbf195fb845421a5b71801704 ] + +Call mxs_saif_put_mclk() to disable MCLK on error +paths of mxs_sgtl5000_probe(). + +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260401053051.586290-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/mxs/mxs-sgtl5000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c +index 245f174116384..f1c0e612313dd 100644 +--- a/sound/soc/mxs/mxs-sgtl5000.c ++++ b/sound/soc/mxs/mxs-sgtl5000.c +@@ -157,13 +157,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); ++ mxs_saif_put_mclk(0); + return ret; + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) ++ if (ret) { ++ mxs_saif_put_mclk(0); + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/asoc-qcom-x1e80100-limit-speaker-volumes.patch b/queue-6.18/asoc-qcom-x1e80100-limit-speaker-volumes.patch new file mode 100644 index 0000000000..6ff956c5ee --- /dev/null +++ b/queue-6.18/asoc-qcom-x1e80100-limit-speaker-volumes.patch @@ -0,0 +1,75 @@ +From 0d0c3622d9bf39249a09294402631be5a24f1176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 15:30:59 +0200 +Subject: ASoC: qcom: x1e80100: limit speaker volumes + +From: Tobias Heider + +[ Upstream commit 0a5ee0e520eff98ee2b4568194562870877b050f ] + +Limit the digital gain and PA volumes to a combined -3 dB in the machine +driver to reduce the risk of speaker damage until we have active speaker +protection in place (or higher safe levels have been established). + +Based on commit c481016bb4f8 ("ASoC: qcom: sc8280xp: limit speaker +volumes") which addressed the same issue on the sc8280x SoC with some +minor changes as explained below. + +The Digital Volume behaves almost identical to sc8280x since both use +the same lpass-wsa-macro, but x1e80100 has two sets of controls prefixed +with WSA and WSA2. +For PA x1e80100 machines use wsa884x amplifiers which expose a linear +scale from -9 dB to 9 dB with a 1.5 dB step size giving us +0 dB = -9 dB + 6 * 1.5 dB. + +On x1e80100 there are two different speaker topologies we need to handle: + 2-Speakers: SpkrLeft, Spkr Right + 4-Speakers: WooferLeft, WooferRight, TweeterLeft, TweeterRight + +Signed-off-by: Tobias Heider +Tested-by: Srinivas Kandagatla +Reviewed-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260422-x1e80100-audio-limit-v2-1-333258b97697@canonical.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/x1e80100.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c +index 2e3599516aa2a..6b36b5051a91a 100644 +--- a/sound/soc/qcom/x1e80100.c ++++ b/sound/soc/qcom/x1e80100.c +@@ -28,10 +28,29 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) + { + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_card *card = rtd->card; + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; + + switch (cpu_dai->id) { ++ case WSA_CODEC_DMA_RX_0: ++ case WSA_CODEC_DMA_RX_1: ++ /* ++ * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume ++ * to reduce the risk of speaker damage until we have active ++ * speaker protection in place. ++ */ ++ snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "SpkrRight PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferRight PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterRight PA Volume", 6); ++ break; + case DISPLAY_PORT_RX_0: + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; +-- +2.53.0 + diff --git a/queue-6.18/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-6.18/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..1398d16c4c --- /dev/null +++ b/queue-6.18/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From 82bfd3de2d5967ba2eb99f0c9cd81ae5c4cc633b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index f50e771db24b0..7fdc81febc1fa 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1838,6 +1838,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + unsigned int pll_bit = 0; + int ret; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + ret = clk_set_rate(rt5640->mclk, freq); +-- +2.53.0 + diff --git a/queue-6.18/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-6.18/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..8a34f6b575 --- /dev/null +++ b/queue-6.18/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From c65f1b331e733ecd367d7e3b3e0f5eabe561fe3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index 43449d7c25843..80206c2e09462 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -487,7 +487,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -496,7 +496,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -583,7 +583,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { +@@ -608,7 +608,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -621,7 +621,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-6.18/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-6.18/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..830c661978 --- /dev/null +++ b/queue-6.18/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From 415550aa056caed0207d2490571656746903c3df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index 621a9d5f9377a..db43580217f47 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2530,6 +2530,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-6.18/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-6.18/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..cfe2377dba --- /dev/null +++ b/queue-6.18/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From 90df789d5beaec81b3976098857cec81503b3245 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 23be85418b3b1..e97a842005e98 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -3171,7 +3171,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-6.18/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch b/queue-6.18/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch new file mode 100644 index 0000000000..cfb05647ab --- /dev/null +++ b/queue-6.18/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch @@ -0,0 +1,215 @@ +From 71f55ee4d44000f2295be93d258712e9960d12de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:05:09 +0000 +Subject: blk-iocost: fix busy_level reset when no IOs complete + +From: Jialin Wang + +[ Upstream commit f91ffe89b2016d280995a9c28d73288b02d83615 ] + +When a disk is saturated, it is common for no IOs to complete within a +timer period. Currently, in this case, rq_wait_pct and missed_ppm are +calculated as 0, the iocost incorrectly interprets this as meeting QoS +targets and resets busy_level to 0. + +This reset prevents busy_level from reaching the threshold (4) needed +to reduce vrate. On certain cloud storage, such as Azure Premium SSD, +we observed that iocost may fail to reduce vrate for tens of seconds +during saturation, failing to mitigate noisy neighbor issues. + +Fix this by tracking the number of IO completions (nr_done) in a period. +If nr_done is 0 and there are lagging IOs, the saturation status is +unknown, so we keep busy_level unchanged. + +The issue is consistently reproducible on Azure Standard_D8as_v5 (Dasv5) +VMs with 512GB Premium SSD (P20) using the script below. It was not +observed on GCP n2d VMs (with 100G pd-ssd and 1.5T local-ssd), and no +regressions were found with this patch. In this script, cgA performs +large IOs with iodepth=128, while cgB performs small IOs with iodepth=1 +rate_iops=100 rw=randrw. With iocost enabled, we expect it to throttle +cgA, the submission latency (slat) of cgA should be significantly higher, +cgB can reach 200 IOPS and the completion latency (clat) should below. + + BLK_DEVID="8:0" + MODEL="rbps=173471131 rseqiops=3566 rrandiops=3566 wbps=173333269 wseqiops=3566 wrandiops=3566" + QOS="rpct=90 rlat=3500 wpct=90 wlat=3500 min=80 max=10000" + + echo "$BLK_DEVID ctrl=user model=linear $MODEL" > /sys/fs/cgroup/io.cost.model + echo "$BLK_DEVID enable=1 ctrl=user $QOS" > /sys/fs/cgroup/io.cost.qos + + CG_A="/sys/fs/cgroup/cgA" + CG_B="/sys/fs/cgroup/cgB" + + FILE_A="/path/to/sda/A.fio.testfile" + FILE_B="/path/to/sda/B.fio.testfile" + RESULT_DIR="./iocost_results_$(date +%Y%m%d_%H%M%S)" + + mkdir -p "$CG_A" "$CG_B" "$RESULT_DIR" + + get_result() { + local file=$1 + local label=$2 + + local results=$(jq -r ' + .jobs[0].mixed | + ( .iops | tonumber | round ) as $iops | + ( .bw_bytes / 1024 / 1024 ) as $bps | + ( .slat_ns.mean / 1000000 ) as $slat | + ( .clat_ns.mean / 1000000 ) as $avg | + ( .clat_ns.max / 1000000 ) as $max | + ( .clat_ns.percentile["90.000000"] / 1000000 ) as $p90 | + ( .clat_ns.percentile["99.000000"] / 1000000 ) as $p99 | + ( .clat_ns.percentile["99.900000"] / 1000000 ) as $p999 | + ( .clat_ns.percentile["99.990000"] / 1000000 ) as $p9999 | + "\($iops)|\($bps)|\($slat)|\($avg)|\($max)|\($p90)|\($p99)|\($p999)|\($p9999)" + ' "$file") + + IFS='|' read -r iops bps slat avg max p90 p99 p999 p9999 <<<"$results" + printf "%-8s %-6s %-7.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f\n" \ + "$label" "$iops" "$bps" "$slat" "$avg" "$max" "$p90" "$p99" "$p999" "$p9999" + } + + run_fio() { + local cg_path=$1 + local filename=$2 + local name=$3 + local bs=$4 + local qd=$5 + local out=$6 + shift 6 + local extra=$@ + + ( + pid=$(sh -c 'echo $PPID') + echo $pid >"${cg_path}/cgroup.procs" + fio --name="$name" --filename="$filename" --direct=1 --rw=randrw --rwmixread=50 \ + --ioengine=libaio --bs="$bs" --iodepth="$qd" --size=4G --runtime=10 \ + --time_based --group_reporting --unified_rw_reporting=mixed \ + --output-format=json --output="$out" $extra >/dev/null 2>&1 + ) & + } + + echo "Starting Test ..." + + for bs_b in "4k" "32k" "256k"; do + echo "Running iteration: BS=$bs_b" + out_a="${RESULT_DIR}/cgA_1m.json" + out_b="${RESULT_DIR}/cgB_${bs_b}.json" + + # cgA: Heavy background (BS 1MB, QD 128) + run_fio "$CG_A" "$FILE_A" "cgA" "1m" 128 "$out_a" + # cgB: Latency sensitive (Variable BS, QD 1, Read/Write IOPS limit 100) + run_fio "$CG_B" "$FILE_B" "cgB" "$bs_b" 1 "$out_b" "--rate_iops=100" + + wait + SUMMARY_DATA+="$(get_result "$out_a" "cgA-1m")"$'\n' + SUMMARY_DATA+="$(get_result "$out_b" "cgB-$bs_b")"$'\n\n' + done + + echo -e "\nFinal Results Summary:\n" + + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n" \ + "" "" "" "slat" "clat" "clat" "clat" "clat" "clat" "clat" + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n\n" \ + "CGROUP" "IOPS" "MB/s" "avg(ms)" "avg(ms)" "max(ms)" "P90(ms)" "P99" "P99.9" "P99.99" + echo "$SUMMARY_DATA" + + echo "Results saved in $RESULT_DIR" + +Before: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 166 166.37 3.44 748.95 1298.29 977.27 1233.13 1300.23 1300.23 + cgB-4k 5 0.02 0.02 181.74 761.32 742.39 759.17 759.17 759.17 + + cgA-1m 167 166.51 1.98 748.68 1549.41 809.50 1451.23 1551.89 1551.89 + cgB-32k 6 0.18 0.02 169.98 761.76 742.39 759.17 759.17 759.17 + + cgA-1m 166 165.55 2.89 750.89 1540.37 851.44 1451.23 1535.12 1535.12 + cgB-256k 5 1.30 0.02 191.35 759.51 750.78 759.17 759.17 759.17 + +After: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 162 162.48 6.14 749.69 850.02 826.28 834.67 843.06 851.44 + cgB-4k 199 0.78 0.01 1.95 42.12 2.57 7.50 34.87 42.21 + + cgA-1m 146 146.20 6.83 833.04 908.68 893.39 901.78 910.16 910.16 + cgB-32k 200 6.25 0.01 2.32 31.40 3.06 7.50 16.58 31.33 + + cgA-1m 110 110.46 9.04 1082.67 1197.91 1182.79 1199.57 1199.57 1199.57 + cgB-256k 200 49.98 0.02 3.69 22.20 4.88 9.11 20.05 22.15 + +Signed-off-by: Jialin Wang +Acked-by: Tejun Heo +Link: https://patch.msgid.link/20260331100509.182882-1-wjl.linux@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 5bfd70311359c..264ea3f12d9b8 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1596,7 +1596,8 @@ static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer) + return HRTIMER_NORESTART; + } + +-static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p) ++static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p, ++ u32 *nr_done) + { + u32 nr_met[2] = { }; + u32 nr_missed[2] = { }; +@@ -1633,6 +1634,8 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p + + *rq_wait_pct_p = div64_u64(rq_wait_ns * 100, + ioc->period_us * NSEC_PER_USEC); ++ ++ *nr_done = nr_met[READ] + nr_met[WRITE] + nr_missed[READ] + nr_missed[WRITE]; + } + + /* was iocg idle this period? */ +@@ -2250,12 +2253,12 @@ static void ioc_timer_fn(struct timer_list *timer) + u64 usage_us_sum = 0; + u32 ppm_rthr; + u32 ppm_wthr; +- u32 missed_ppm[2], rq_wait_pct; ++ u32 missed_ppm[2], rq_wait_pct, nr_done; + u64 period_vtime; + int prev_busy_level; + + /* how were the latencies during the period? */ +- ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct); ++ ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct, &nr_done); + + /* take care of active iocgs */ + spin_lock_irq(&ioc->lock); +@@ -2399,9 +2402,17 @@ static void ioc_timer_fn(struct timer_list *timer) + * and should increase vtime rate. + */ + prev_busy_level = ioc->busy_level; +- if (rq_wait_pct > RQ_WAIT_BUSY_PCT || +- missed_ppm[READ] > ppm_rthr || +- missed_ppm[WRITE] > ppm_wthr) { ++ if (!nr_done && nr_lagging) { ++ /* ++ * When there are lagging IOs but no completions, we don't ++ * know if the IO latency will meet the QoS targets. The ++ * disk might be saturated or not. We should not reset ++ * busy_level to 0 (which would prevent vrate from scaling ++ * up or down), but rather to keep it unchanged. ++ */ ++ } else if (rq_wait_pct > RQ_WAIT_BUSY_PCT || ++ missed_ppm[READ] > ppm_rthr || ++ missed_ppm[WRITE] > ppm_wthr) { + /* clearly missing QoS targets, slow down vrate */ + ioc->busy_level = max(ioc->busy_level, 0); + ioc->busy_level++; +-- +2.53.0 + diff --git a/queue-6.18/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch b/queue-6.18/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch new file mode 100644 index 0000000000..9a53e9b812 --- /dev/null +++ b/queue-6.18/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch @@ -0,0 +1,72 @@ +From 1b82b25e69cd4a4b6c5c84ee49d4901f56c602d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 01:09:29 -0400 +Subject: block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user() + +From: Sungwoo Kim + +[ Upstream commit 8582792cf23b3d94674d4d838f7cde9a28d0fcaf ] + +pin_user_pages_fast() can partially succeed and return the number of +pages that were actually pinned. However, the bio_integrity_map_user() +does not handle this partial pinning. This leads to a general protection +fault since bvec_from_pages() dereferences an unpinned page address, +which is 0. + +To fix this, add a check to verify that all requested memory is pinned. +If partial pinning occurs, unpin the memory and return -EFAULT. + +Kernel Oops: + +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI +KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] +CPU: 0 UID: 0 PID: 1061 Comm: nvme-passthroug Not tainted 7.0.0-11783-g90957f9314e8-dirty #16 PREEMPT(lazy) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 +RIP: 0010:bio_integrity_map_user.cold+0x1b0/0x9d6 + +Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") +Acked-by: Chao Shi +Acked-by: Weidong Zhu +Acked-by: Dave Tian +Signed-off-by: Sungwoo Kim +Tested-by: Shin'ichiro Kawasaki +Link: https://github.com/linux-blktests/blktests/pull/244 +Link: https://patch.msgid.link/20260512050929.541397-2-iam@sung-woo.kim +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index ab4a15437925e..46c59ed92bd1c 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -299,6 +299,24 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + if (unlikely(ret < 0)) + goto free_bvec; + ++ /* ++ * Handle partial pinning. This can happen when pin_user_pages_fast() ++ * returns fewer pages than requested. ++ */ ++ if (user_backed_iter(iter) && unlikely(ret != bytes)) { ++ if (ret > 0) { ++ int npinned = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ int i; ++ ++ for (i = 0; i < npinned; i++) ++ unpin_user_page(pages[i]); ++ } ++ if (pages != stack_pages) ++ kvfree(pages); ++ ret = -EFAULT; ++ goto free_bvec; ++ } ++ + nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, + &is_p2p); + if (pages != stack_pages) +-- +2.53.0 + diff --git a/queue-6.18/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch b/queue-6.18/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch new file mode 100644 index 0000000000..037bc39aa0 --- /dev/null +++ b/queue-6.18/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch @@ -0,0 +1,43 @@ +From af20bae41a877ddbcc2aaedf9b817797a4eabeef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 22:51:51 +0100 +Subject: block: don't overwrite bip_vcnt in bio_integrity_copy_user() + +From: David Carlier + +[ Upstream commit 637ad3a56a3b889527d1dacea6fea2a8bd648140 ] + +bio_integrity_add_page() already sets bip_vcnt to 1 for the bounce +segment. Overwriting it with nr_vecs breaks bip_vcnt <= bip_max_vcnt +on WRITE (bip_max_vcnt is 1), so the gap-merge checks in block/blk.h +read past the bip_vec[] flex array. On READ the read is in bounds +but lands on a saved user bvec instead of the bounce. + +The line was added for split propagation, but bio_integrity_clone() +doesn't copy bip_vcnt and BIP_CLONE_FLAGS excludes BIP_COPY_USER. + +Fixes: 3991657ae707 ("block: set bip_vcnt correctly") +Signed-off-by: David Carlier +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511215151.346228-1-devnexen@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 12d887349c260..ab4a15437925e 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -205,7 +205,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + } + + bip->bip_flags |= BIP_COPY_USER; +- bip->bip_vcnt = nr_vecs; + return 0; + free_bip: + bio_integrity_free(bio); +-- +2.53.0 + diff --git a/queue-6.18/block-recompute-nr_integrity_segments-in-blk_insert_.patch b/queue-6.18/block-recompute-nr_integrity_segments-in-blk_insert_.patch new file mode 100644 index 0000000000..5c6c267657 --- /dev/null +++ b/queue-6.18/block-recompute-nr_integrity_segments-in-blk_insert_.patch @@ -0,0 +1,82 @@ +From ab13998d1fc049ba77c57f8254907660a3a44832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 15:22:30 -0600 +Subject: block: recompute nr_integrity_segments in blk_insert_cloned_request + +From: Casey Chen + +[ Upstream commit 2c6e6a18a37b905cb584eb0dda3ae482162a81ca ] + +blk_insert_cloned_request() already recomputes nr_phys_segments +against the bottom queue, because "the queue settings related to +segment counting may differ from the original queue." The exact same +reasoning applies to integrity segments: a stacked driver's underlying +queue can have tighter virt_boundary_mask, seg_boundary_mask, or +max_segment_size than the top queue, in which case +blk_rq_count_integrity_sg() against the bottom queue produces a +different count than the cached rq->nr_integrity_segments inherited +from the source request by blk_rq_prep_clone(). + +When the cached count is lower than the bottom queue's actual count, +blk_rq_map_integrity_sg() trips + + BUG_ON(segments > rq->nr_integrity_segments); + +on dispatch. The same families of stacked setups that motivated the +existing nr_phys_segments recompute -- dm-multipath fanning out to +nvme-rdma in particular -- can produce this. + +Mirror the nr_phys_segments handling: when the request carries +integrity, recompute nr_integrity_segments against the bottom queue +and reject the request if it exceeds the bottom queue's +max_integrity_segments. blk_rq_count_integrity_sg() and +queue_max_integrity_segments() are both already available via +, which blk-mq.c includes. + +This closes a latent gap in the stacking contract and brings the +integrity-segment accounting in line with the existing +phys-segment accounting. + +Fixes: 76c313f658d2 ("blk-integrity: improved sg segment mapping") +Signed-off-by: Casey Chen +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511212230.27511-1-cachen@purestorage.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-mq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 4ebb92014eae1..ab05c5c9e6ae2 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3285,6 +3285,25 @@ blk_status_t blk_insert_cloned_request(struct request *rq) + return BLK_STS_IOERR; + } + ++ /* ++ * Integrity segment counting depends on the same queue limits ++ * (virt_boundary_mask, seg_boundary_mask, max_segment_size) that ++ * vary across stacked queues, so recompute against the bottom ++ * queue just like nr_phys_segments above. ++ */ ++ if (blk_integrity_rq(rq) && rq->bio) { ++ unsigned short max_int_segs = queue_max_integrity_segments(q); ++ ++ rq->nr_integrity_segments = ++ blk_rq_count_integrity_sg(rq->q, rq->bio); ++ if (rq->nr_integrity_segments > max_int_segs) { ++ printk(KERN_ERR "%s: over max integrity segments limit. (%u > %u)\n", ++ __func__, rq->nr_integrity_segments, ++ max_int_segs); ++ return BLK_STS_IOERR; ++ } ++ } ++ + if (q->disk && should_fail_request(q->disk->part0, blk_rq_bytes(rq))) + return BLK_STS_IOERR; + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-6.18/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..15ebedaf08 --- /dev/null +++ b/queue-6.18/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From 0fa2d4dc76085d6e874f54f1bfa95e31beae581d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 3a3a56ddbb06d..93368ef56ddc5 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -507,6 +507,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btmtk-add-mt7902-mcu-support.patch b/queue-6.18/bluetooth-btmtk-add-mt7902-mcu-support.patch new file mode 100644 index 0000000000..20cdca6909 --- /dev/null +++ b/queue-6.18/bluetooth-btmtk-add-mt7902-mcu-support.patch @@ -0,0 +1,47 @@ +From 53122478cfef3a9bdf10f15d6c73a62cf8b28af6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:19 -0600 +Subject: Bluetooth: btmtk: add MT7902 MCU support + +From: Sean Wang + +[ Upstream commit aab25984e55972e53f3e58821cb85a7101876056 ] + +Add MT7902 device ID and firmware filename to enable MCU firmware +loading. + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 1 + + drivers/bluetooth/btmtk.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index ad0c7c21109e3..b08e34e962352 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -1343,6 +1343,7 @@ int btmtk_usb_setup(struct hci_dev *hdev) + case 0x7922: + case 0x7925: + case 0x7961: ++ case 0x7902: + btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id, + fw_version, fw_flavor); + +diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h +index 5df7c32966247..b4506186b2f70 100644 +--- a/drivers/bluetooth/btmtk.h ++++ b/drivers/bluetooth/btmtk.h +@@ -5,6 +5,7 @@ + #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" + #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" + #define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin" ++#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin" + #define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" + #define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch b/queue-6.18/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch new file mode 100644 index 0000000000..6b09b3bfaa --- /dev/null +++ b/queue-6.18/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch @@ -0,0 +1,40 @@ +From 65f3f5f4cb7a799512b96eebbb83763f7bc63975 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:25:08 +0800 +Subject: Bluetooth: btmtk: improve mt79xx firmware setup retry flow + +From: Chris Lu + +[ Upstream commit 54f1f020e9f4a087779cc4d96a7c86f47d0c6797 ] + +If retries are exhausted, driver should not do futher operation. +During mt79xx firmware download process, if the retry count reaches0, +driver will return an -EIO error and release the firmware resources. + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index cf05746e9db5a..ad0c7c21109e3 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -205,6 +205,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, + } + } + ++ /* If retry exhausted goto err_release_fw */ ++ if (retry == 0) { ++ err = -EIO; ++ goto err_release_fw; ++ } ++ + fw_ptr += section_offset; + wmt_params.op = BTMTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch b/queue-6.18/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch new file mode 100644 index 0000000000..185e4f12fd --- /dev/null +++ b/queue-6.18/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch @@ -0,0 +1,56 @@ +From 0b30dd0345f1ec541b9e30753ac17e3eaeff5be6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 20:32:09 +0100 +Subject: Bluetooth: btusb: Add Lite-On 04ca:3807 for MediaTek MT7921 + +From: Dylan Eray + +[ Upstream commit 67377cd38b89ce782ccdb83bda3f65a2def843cd ] + +Add USB device ID (04ca:3807) for a Lite-On Wireless_Device containing +a MediaTek MT7921 (MT7920) Bluetooth chipset found in Acer laptops. + +Without this entry, btusb binds via the generic USB class-based wildcard +match but never sets the BTUSB_MEDIATEK flag. This means btmtk never +triggers firmware loading, and the driver sends a raw HCI Reset that +the uninitialized chip cannot respond to, resulting in: + + Bluetooth: hci0: Opcode 0x0c03 failed: -110 + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below: + +T: Bus=03 Lev=01 Prnt=01 Port=09 Cnt=01 Dev#=5 Spd=480 MxCh=0 +P: Vendor=04ca ProdID=3807 Rev=1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C: #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) + +Reviewed-by: Paul Menzel +Signed-off-by: Dylan Eray +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 139d5af971db3..43ee00a3dd2d4 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -705,6 +705,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x04ca, 0x3807), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch b/queue-6.18/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch new file mode 100644 index 0000000000..e9594bdfb7 --- /dev/null +++ b/queue-6.18/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch @@ -0,0 +1,79 @@ +From 5e0648ce0fca4b6cb906655c325639491cecd823 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:20 -0600 +Subject: Bluetooth: btusb: Add new VID/PID 13d3/3579 for MT7902 + +From: Sean Wang + +[ Upstream commit 51c4173b89fe7399bad1381016096cc154588660 ] + +Add VID 13d3 & PID 3579 for MediaTek MT7902 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=04 Dev#= 7 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=13d3 ProdID=3579 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 43ee00a3dd2d4..0de2c109d8451 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -669,7 +669,9 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +- ++ /* MediaTek MT7902 Bluetooth devices */ ++ { USB_DEVICE(0x13d3, 0x3579), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + /* MediaTek MT7922 Bluetooth devices */ + { USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch b/queue-6.18/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch new file mode 100644 index 0000000000..b08ffb6bc9 --- /dev/null +++ b/queue-6.18/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch @@ -0,0 +1,46 @@ +From 243adc483f26a5014b69ee5d7cfcee4ab8ff39f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:53:01 +0900 +Subject: Bluetooth: btusb: MediaTek MT7922: Add VID 0489 & PID e11d + +From: Kamiyama Chiaki + +[ Upstream commit 5e17010bfc7e6820a5004f1e06d08db886e3927e ] + +Add VID 0489 & PID e11d for MediaTek MT7922 USB Bluetooth chip. +Found in Dynabook GA/ZY (W6GAZY5RCL). + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e11d Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 + +Reviewed-by: Paul Menzel +Signed-off-by: Kamiyama Chiaki +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 0de2c109d8451..5ff57b4197bb1 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -697,6 +697,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe11d), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe152), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch b/queue-6.18/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch new file mode 100644 index 0000000000..5b3c21de81 --- /dev/null +++ b/queue-6.18/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch @@ -0,0 +1,77 @@ +From de44d34f1dab192999ec68ddd6bb7845a92bfdff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:13:56 +0800 +Subject: Bluetooth: btusb: MT7922: Add VID/PID 0489/e174 + +From: Chris Lu + +[ Upstream commit 1f2ac009d3e06380400618e777c858e582872efa ] + +Add VID 0489 & PID e174 for MediaTek MT7922 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e174 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 40f0c3b4eee6c..139d5af971db3 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -701,6 +701,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe174), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch b/queue-6.18/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch new file mode 100644 index 0000000000..67891c5a5a --- /dev/null +++ b/queue-6.18/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch @@ -0,0 +1,68 @@ +From 9d8398b07c815e8d96db03626745b1459b9b0c95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:47:03 +0200 +Subject: Bluetooth: hci_ll: Enable BROKEN_ENHANCED_SETUP_SYNC_CONN for WL183x + +From: Stefano Radaelli + +[ Upstream commit 1c0bc11cd445ba8235ac8ec87d5999b6769ed8b9 ] + +TI WL183x controllers advertise support for the HCI Enhanced Setup +Synchronous Connection command, but SCO setup fails when the enhanced +path is used. The only working configuration is to fall back to the +legacy HCI Setup Synchronous Connection (0x0028). + +This matches the scenario described in commit 05abad857277 +("Bluetooth: HCI: Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk"). + +Enable HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN automatically for +devices compatible with: + - ti,wl1831-st + - ti,wl1835-st + - ti,wl1837-st + +Signed-off-by: Stefano Radaelli +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ll.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c +index c4584f4085766..72c932e10a1a1 100644 +--- a/drivers/bluetooth/hci_ll.c ++++ b/drivers/bluetooth/hci_ll.c +@@ -68,6 +68,7 @@ struct ll_device { + struct gpio_desc *enable_gpio; + struct clk *ext_clk; + bdaddr_t bdaddr; ++ bool broken_enhanced_setup; + }; + + struct ll_struct { +@@ -658,6 +659,10 @@ static int ll_setup(struct hci_uart *hu) + hci_set_quirk(hu->hdev, HCI_QUIRK_INVALID_BDADDR); + } + ++ if (lldev->broken_enhanced_setup) ++ hci_set_quirk(hu->hdev, ++ HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN); ++ + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; +@@ -712,6 +717,11 @@ static int hci_ti_probe(struct serdev_device *serdev) + of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); + hci_uart_set_speeds(hu, 115200, max_speed); + ++ if (of_device_is_compatible(serdev->dev.of_node, "ti,wl1831-st") || ++ of_device_is_compatible(serdev->dev.of_node, "ti,wl1835-st") || ++ of_device_is_compatible(serdev->dev.of_node, "ti,wl1837-st")) ++ lldev->broken_enhanced_setup = true; ++ + /* optional BD address from nvram */ + bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address"); + if (IS_ERR(bdaddr_cell)) { +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch b/queue-6.18/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch new file mode 100644 index 0000000000..5f5788e0bb --- /dev/null +++ b/queue-6.18/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch @@ -0,0 +1,43 @@ +From 8a7b86b338d11bacfacc795c7f8f631d6b7f04f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:16 +0800 +Subject: Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is + not defined + +From: Shuai Zhang + +[ Upstream commit 7b75867803a8712bdf7683c31d71d3d5e28ce821 ] + +On platforms using an M.2 slot with both UART and USB support, bt_en is +pulled high by hardware. In this case, software-based power control +should be disabled. The current platforms are Lemans-EVK and Monaco-EVK. + +Add QCA_WCN7850 to the existing condition so that power_ctrl_enabled is +cleared when bt_en is not software-controlled (or absent), aligning its +behavior with WCN6750 and WCN6855 + +Signed-off-by: Shuai Zhang +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index c0cc04995fc2f..56663f6717311 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2467,7 +2467,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + if (!qcadev->bt_en && + (data->soc_type == QCA_WCN6750 || +- data->soc_type == QCA_WCN6855)) ++ data->soc_type == QCA_WCN6855 || ++ data->soc_type == QCA_WCN7850)) + power_ctrl_enabled = false; + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch b/queue-6.18/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch new file mode 100644 index 0000000000..d1132a6084 --- /dev/null +++ b/queue-6.18/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch @@ -0,0 +1,72 @@ +From 649acfecf3bd82626c157f4ea1c3f41ac5be1021 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:54:43 +0800 +Subject: Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling + +From: Shuai Zhang + +[ Upstream commit c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f ] + +When a Bluetooth controller encounters a coredump, it triggers the +Subsystem Restart (SSR) mechanism. The controller first reports the +coredump data and, once the upload is complete, sends a hw_error +event. The host relies on this event to proceed with subsequent +recovery actions. + +If the host has not finished processing the coredump data when the +hw_error event is received, it waits until either the processing is +complete or the 8-second timeout expires before handling the event. + +The current implementation clears QCA_MEMDUMP_COLLECTION using +clear_bit(), which does not wake up waiters sleeping in +wait_on_bit_timeout(). As a result, the waiting thread may remain +blocked until the timeout expires even if the coredump collection +has already completed. + +Fix this by clearing QCA_MEMDUMP_COLLECTION with +clear_and_wake_up_bit(), which also wakes up the waiting thread and +allows the hw_error handling to proceed immediately. + +Test case: +- Trigger a controller coredump using: + hcitool cmd 0x3f 0c 26 +- Tested on QCA6390. +- Capture HCI logs using btmon. +- Verify that the delay between receiving the hw_error event and + initiating the power-off sequence is reduced compared to the + timeout-based behavior. + +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Paul Menzel +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 56663f6717311..76340685df350 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -1103,7 +1103,7 @@ static void qca_controller_memdump(struct work_struct *work) + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; +@@ -1181,7 +1181,7 @@ static void qca_controller_memdump(struct work_struct *work) + kfree(qca->qca_memdump); + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } + + mutex_unlock(&qca->hci_memdump_lock); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-6.18/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..7f0a619817 --- /dev/null +++ b/queue-6.18/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From 4bf2df1b021913144b34ec2a5805931ea6cabfc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index bcb13ce531099..6c39f361b2396 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6711,6 +6711,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); +-- +2.53.0 + diff --git a/queue-6.18/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-6.18/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..c723c0c89c --- /dev/null +++ b/queue-6.18/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From a1c7279c2e0427d84f78862c4437341e35160587 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 931a4ddd8530c..25fd06bb86e84 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -2049,12 +2049,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-6.18/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch b/queue-6.18/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch new file mode 100644 index 0000000000..60a3881a92 --- /dev/null +++ b/queue-6.18/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch @@ -0,0 +1,40 @@ +From 313d7ccebf4b434333a2432f94ef9b113df67dec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 14:08:00 +0800 +Subject: bpf: propagate kvmemdup_bpfptr errors from bpf_prog_verify_signature + +From: Weixie Cui + +[ Upstream commit ad2f7ed0ee91d63792cbe52f2b38325918ae3daa ] + +kvmemdup_bpfptr() returns -EFAULT when the user pointer cannot be +copied, and -ENOMEM on allocation failure. The error path always +returned -ENOMEM, misreporting bad addresses as out-of-memory. + +Return PTR_ERR(sig) so user space gets the correct errno. + +Signed-off-by: Weixie Cui +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/tencent_C9C5B2B28413D6303D505CD02BFEA4708C07@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index ff268fd2ff8b5..2465d2a0714c1 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -2843,7 +2843,7 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr + sig = kvmemdup_bpfptr(usig, attr->signature_size); + if (IS_ERR(sig)) { + bpf_key_put(key); +- return -ENOMEM; ++ return PTR_ERR(sig); + } + + bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0, +-- +2.53.0 + diff --git a/queue-6.18/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch b/queue-6.18/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch new file mode 100644 index 0000000000..b8d277ac67 --- /dev/null +++ b/queue-6.18/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch @@ -0,0 +1,52 @@ +From 6e41ec8025acd390c95a5eddefc8d46a44c16679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:15 +0200 +Subject: bpf, sockmap: Annotate af_unix sock:: Sk_state data-races + +From: Michal Luczaj + +[ Upstream commit a25566084e391348385a72dd507e0cc0c268dd5d ] + +sock_map_sk_state_allowed() and sock_map_redirect_allowed() read af_unix +socket sk_state locklessly. + +Use READ_ONCE(). Note that for sock_map_redirect_allowed() change affects +not only af_unix, but all non-TCP sockets (UDP, af_vsock). + +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-1-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/core/sock_map.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock_map.c b/net/core/sock_map.c +index 5947b38e4f8b6..d4f15b846ad46 100644 +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -530,7 +530,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return sk->sk_state != TCP_LISTEN; + else +- return sk->sk_state == TCP_ESTABLISHED; ++ return READ_ONCE(sk->sk_state) == TCP_ESTABLISHED; + } + + static bool sock_map_sk_is_suitable(const struct sock *sk) +@@ -543,7 +543,7 @@ static bool sock_map_sk_state_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); + if (sk_is_stream_unix(sk)) +- return (1 << sk->sk_state) & TCPF_ESTABLISHED; ++ return (1 << READ_ONCE(sk->sk_state)) & TCPF_ESTABLISHED; + if (sk_is_vsock(sk) && + (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) + return (1 << sk->sk_state) & TCPF_ESTABLISHED; +-- +2.53.0 + diff --git a/queue-6.18/btrfs-apply-first-key-check-for-readahead-when-possi.patch b/queue-6.18/btrfs-apply-first-key-check-for-readahead-when-possi.patch new file mode 100644 index 0000000000..203386a41e --- /dev/null +++ b/queue-6.18/btrfs-apply-first-key-check-for-readahead-when-possi.patch @@ -0,0 +1,129 @@ +From a96fec955c87cd0f64dea2bae0fc33e7a5eb0f21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 20:31:05 +0930 +Subject: btrfs: apply first key check for readahead when possible + +From: Qu Wenruo + +[ Upstream commit a86a283430e1a44907b142c4f53e1f3ad24e87ae ] + +Currently for tree block readahead we never pass a +btrfs_tree_parent_check with @has_first_key set. + +Without @has_first_key set, btrfs will skip the following extra +checks: + +- Header generation check + This is a minor one. + +- Empty leaf/node checks + This is more serious, for certain trees like the csum tree, they are + allowed to be empty, thus an empty leaf can pass the tree checker. + But if there is a parent node for such an empty leaf, it indicates + corruption. + + Without @has_first_key set, we can no longer detect such a problem. + + In fact there is already a fuzzed image report that a corrupted csum + leaf which has zero nritems but still has a parent node can trigger + a BUG_ON() during csum deletion. + +However there are only two call sites of btrfs_readahead_tree_block(): + +- Inside relocate_tree_blocks() + At this call site we are trying to grab the first key of the tree + block, thus we are not able to pass a @first_key parameter. + +- Inside btrfs_readahead_node_child() + This is the more common call site, where we have the parent node and + want to readahead the child tree blocks. + + In this case we can easily grab the node key and pass it for checks. + +Add a new parameter @first_key to btrfs_readahead_tree_block() and pass +the node key to it inside btrfs_readahead_node_child(). + +This should plug the gap in empty leaf detection during readahead. + +Link: https://lore.kernel.org/linux-btrfs/20260409071255.3358044-1-gality369@gmail.com/ +Reviewed-by: David Sterba +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 14 ++++++++++++-- + fs/btrfs/extent_io.h | 3 ++- + fs/btrfs/relocation.c | 2 +- + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 4b2bd3cc3ed33..9a0a4eb88bf71 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -4564,7 +4564,8 @@ int try_release_extent_buffer(struct folio *folio) + * to read the block we will not block on anything. + */ + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level) ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key) + { + struct btrfs_tree_parent_check check = { + .level = level, +@@ -4573,6 +4574,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb; + int ret; + ++ if (first_key) { ++ memcpy(&check.first_key, first_key, sizeof(struct btrfs_key)); ++ check.has_first_key = true; ++ } ++ + eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); + if (IS_ERR(eb)) + return; +@@ -4600,9 +4606,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + */ + void btrfs_readahead_node_child(struct extent_buffer *node, int slot) + { ++ struct btrfs_key node_key; ++ ++ btrfs_node_key_to_cpu(node, &node_key, slot); + btrfs_readahead_tree_block(node->fs_info, + btrfs_node_blockptr(node, slot), + btrfs_header_owner(node), + btrfs_node_ptr_generation(node, slot), +- btrfs_header_level(node) - 1); ++ btrfs_header_level(node) - 1, ++ &node_key); + } +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 73571d5d3d5ad..77b26d19165a4 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -264,7 +264,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb) + } + + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level); ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key); + void btrfs_readahead_node_child(struct extent_buffer *node, int slot); + + /* Note: this can be used in for loops without caching the value in a variable. */ +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 0765e06d00b80..fe3dab9e44f74 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2617,7 +2617,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, + if (!block->key_ready) + btrfs_readahead_tree_block(fs_info, block->bytenr, + block->owner, 0, +- block->level); ++ block->level, NULL); + } + + /* Get first keys */ +-- +2.53.0 + diff --git a/queue-6.18/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-6.18/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..de7a3d37c7 --- /dev/null +++ b/queue-6.18/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 39e1b7494ca312fb78f0845ac8676f74e1944226 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index b3ff2e1da89ba..ef124400d22b7 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -473,10 +473,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + +-- +2.53.0 + diff --git a/queue-6.18/btrfs-check-return-value-of-btrfs_partially_delete_r.patch b/queue-6.18/btrfs-check-return-value-of-btrfs_partially_delete_r.patch new file mode 100644 index 0000000000..dde11c2e17 --- /dev/null +++ b/queue-6.18/btrfs-check-return-value-of-btrfs_partially_delete_r.patch @@ -0,0 +1,73 @@ +From 42e412f7258045dd6394c357f53a91eaf6c7a419 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:37 +0800 +Subject: btrfs: check return value of btrfs_partially_delete_raid_extent() + +From: robbieko + +[ Upstream commit a8d58a7c0200904ff24ca7f0d7c147017e25aa99 ] + +btrfs_partially_delete_raid_extent() returns an error code (e.g. +-ENOMEM from kzalloc(), or errors from btrfs_del_item/btrfs_insert_item()), +but all three call sites in btrfs_delete_raid_extent() discard the +return value, silently losing errors and potentially leaving the stripe +tree in an inconsistent state. + +Fix by capturing the return value into ret at all three call sites and +breaking out of the loop on error where appropriate. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index 9d32d13b037c8..ab8e743396ef8 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -217,8 +217,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + /* The "left" item. */ + path->slots[0]--; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); +- btrfs_partially_delete_raid_extent(trans, path, &key, +- diff_start, 0); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ diff_start, 0); + break; + } + +@@ -234,8 +235,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + if (found_start < start) { + u64 diff_start = start - found_start; + +- btrfs_partially_delete_raid_extent(trans, path, &key, +- diff_start, 0); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ diff_start, 0); ++ if (ret) ++ break; + + start += (key.offset - diff_start); + length -= (key.offset - diff_start); +@@ -258,9 +262,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + if (found_end > end) { + u64 diff_end = found_end - end; + +- btrfs_partially_delete_raid_extent(trans, path, &key, +- key.offset - length, +- length); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ key.offset - length, ++ length); + ASSERT(key.offset - diff_end == length); + break; + } +-- +2.53.0 + diff --git a/queue-6.18/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch b/queue-6.18/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch new file mode 100644 index 0000000000..1eea56f436 --- /dev/null +++ b/queue-6.18/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch @@ -0,0 +1,47 @@ +From 81360209b728e7fed9ae7f95161168754caeac50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:32 +0800 +Subject: btrfs: copy devid in btrfs_partially_delete_raid_extent() + +From: robbieko + +[ Upstream commit 513f8a52eed880ea525dbb139b2127bd9bb793f1 ] + +When btrfs_partially_delete_raid_extent() rebuilds a truncated/shifted +stripe extent into newitem, the loop copies the physical address for +each stride but forgets to copy the devid. The resulting item written +back to the stripe tree has zeroed-out devids, corrupting the stripe +mapping. + +Fix this by reading the devid with btrfs_raid_stride_devid() and +writing it into the new item with btrfs_set_stack_raid_stride_devid() +before copying the physical address. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index fb1fa9ff676f5..9d32d13b037c8 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans, + + for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { + struct btrfs_raid_stride *stride = &extent->strides[i]; ++ u64 devid; + u64 phys; + ++ devid = btrfs_raid_stride_devid(leaf, stride); ++ btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid); + phys = btrfs_raid_stride_physical(leaf, stride) + frontpad; + btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys); + } +-- +2.53.0 + diff --git a/queue-6.18/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-6.18/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..9efe1c2279 --- /dev/null +++ b/queue-6.18/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From 2d1ef7224cf6a29f54547525745f1205558becfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index fc378d2038a2d..80aadc4f8178b 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -535,6 +535,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + blocksize, BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch b/queue-6.18/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch new file mode 100644 index 0000000000..560ab51b14 --- /dev/null +++ b/queue-6.18/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch @@ -0,0 +1,66 @@ +From 778e2619abe04a33e49239c77191d22494560db2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:33 +0800 +Subject: btrfs: fix raid stripe search missing entries at leaf boundaries + +From: robbieko + +[ Upstream commit 2aef5cb1dcf9b3e1be3895a6477dc065e618aab8 ] + +In btrfs_delete_raid_extent(), the search key uses offset=0. When the +target stripe entry is the first item on a leaf, btrfs_search_slot() +may land on the previous leaf and decrementing the slot from nritems +still points to the wrong entry, causing the stripe extent to be +silently missed. + +Fix this by searching with offset=(u64)-1 instead. Since no real stripe +entry has this offset, btrfs_search_slot() always returns 1 with the +slot pointing past the last matching objectid entry. Then unconditionally +decrement the slot with a proper slots[0]==0 early-exit check to handle +the case where no matching entry exists. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index f78cc320773c7..460f46eb9a498 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -99,14 +99,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + while (1) { + key.objectid = start; + key.type = BTRFS_RAID_STRIPE_KEY; +- key.offset = 0; ++ key.offset = (u64)-1; + + ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); + if (ret < 0) + break; + +- if (path->slots[0] == btrfs_header_nritems(path->nodes[0])) +- path->slots[0]--; ++ /* ++ * Search with offset=(u64)-1 ensures we land on the correct ++ * leaf even when the target entry is the first item on a leaf. ++ * Since no real entry has offset=(u64)-1, ret is always 1 and ++ * slot points past the last entry with objectid==start (or ++ * past the end of the leaf if that entry is the last item). ++ * Back up one slot to find the actual entry. ++ */ ++ if (path->slots[0] == 0) { ++ /* No entry with objectid <= start exists. */ ++ ret = 0; ++ break; ++ } ++ path->slots[0]--; + + leaf = path->nodes[0]; + slot = path->slots[0]; +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch b/queue-6.18/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch new file mode 100644 index 0000000000..43b3103022 --- /dev/null +++ b/queue-6.18/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch @@ -0,0 +1,61 @@ +From ec8c79abcb2ee8d7a16032f449dc8ee7fe7fa9e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 09:06:44 -0700 +Subject: btrfs: fix silent IO error loss in encoded writes and zoned split + +From: Michal Grzedzicki + +[ Upstream commit 3cd181cc46d36aa7bd4af85f14639d86a25beaec ] + +can_finish_ordered_extent() and btrfs_finish_ordered_zoned() set +BTRFS_ORDERED_IOERR via bare set_bit(). Later, +btrfs_mark_ordered_extent_error() in btrfs_finish_one_ordered() uses +test_and_set_bit(), finds it already set, and skips +mapping_set_error(). The error is never recorded on the inode's +address_space, making it invisible to fsync. For encoded writes this +causes btrfs receive to silently produce files with zero-filled holes. + +Fix: replace bare set_bit(BTRFS_ORDERED_IOERR) with +btrfs_mark_ordered_extent_error() which pairs test_and_set_bit() with +mapping_set_error(), guaranteeing the error is recorded exactly once. + +Reviewed-by: Qu Wenruo +Reviewed-by: Johannes Thumshirn +Reviewed-by: Mark Harmstone +Signed-off-by: Michal Grzedzicki +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ordered-data.c | 2 +- + fs/btrfs/zoned.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c +index 8a8aa6ed405bd..8f48935ec80ba 100644 +--- a/fs/btrfs/ordered-data.c ++++ b/fs/btrfs/ordered-data.c +@@ -385,7 +385,7 @@ static bool can_finish_ordered_extent(struct btrfs_ordered_extent *ordered, + } + + if (!uptodate) +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + + if (ordered->bytes_left) + return false; +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index 16818dbf48a46..40b9b0e043753 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -2113,7 +2113,7 @@ void btrfs_finish_ordered_zoned(struct btrfs_ordered_extent *ordered) + continue; + } + if (!btrfs_zoned_split_ordered(ordered, logical, len)) { +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + btrfs_err(fs_info, "failed to split ordered extent"); + goto out; + } +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch b/queue-6.18/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch new file mode 100644 index 0000000000..db3581fcb8 --- /dev/null +++ b/queue-6.18/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch @@ -0,0 +1,43 @@ +From a4c7ddaa1626c3429c186a0a2311104030bd5d6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:34 +0800 +Subject: btrfs: fix wrong min_objectid in btrfs_previous_item() call + +From: robbieko + +[ Upstream commit 1871ae78ffa5ce7c0458e9ba5867958c1753e425 ] + +When found_start > start and slot == 0, btrfs_previous_item() is called +with min_objectid=start to find the previous stripe extent. However, the +previous stripe extent we are looking for has objectid < start (it starts +before our deletion range), so passing start as min_objectid prevents +finding it. + +Fix by passing 0 as min_objectid to allow finding any preceding stripe +extent regardless of its objectid. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index cc6f6095cc9fd..f78cc320773c7 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -127,7 +127,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + */ + if (found_start > start) { + if (slot == 0) { +- ret = btrfs_previous_item(stripe_root, path, start, ++ ret = btrfs_previous_item(stripe_root, path, 0, + BTRFS_RAID_STRIPE_KEY); + if (ret) { + if (ret > 0) +-- +2.53.0 + diff --git a/queue-6.18/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch b/queue-6.18/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch new file mode 100644 index 0000000000..4ae0431da0 --- /dev/null +++ b/queue-6.18/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch @@ -0,0 +1,60 @@ +From 241b6ad8d4bc6e05a203090d5e47faf3e9923711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:36 +0800 +Subject: btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale + leaf pointer + +From: robbieko + +[ Upstream commit fe0cdfd7118d8b40a21bfac221bb4982c5e10e10 ] + +In the 'punch a hole' case of btrfs_delete_raid_extent(), +btrfs_duplicate_item() can return -EAGAIN when the leaf needs to be +split and the path becomes invalid. The old code treats any error as +fatal and breaks out of the loop. + +Additionally, btrfs_duplicate_item() may trigger setup_leaf_for_split() +which can reallocate the leaf node. The code continues using the old +leaf pointer, leading to use-after-free or stale data access. + +Fix both issues by: + +- Handling -EAGAIN specifically: release the path and retry the loop. +- Refreshing leaf = path->nodes[0] after successful duplication. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index ab8e743396ef8..011e005b61c71 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -198,9 +198,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + + /* The "right" item. */ + ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); ++ if (ret == -EAGAIN) { ++ btrfs_release_path(path); ++ continue; ++ } + if (ret) + break; + ++ /* ++ * btrfs_duplicate_item() may have triggered a leaf ++ * split via setup_leaf_for_split(), so we must refresh ++ * our leaf pointer from the path. ++ */ ++ leaf = path->nodes[0]; + item_size = btrfs_item_size(leaf, path->slots[0]); + extent = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_stripe_extent); +-- +2.53.0 + diff --git a/queue-6.18/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-6.18/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..c2ab812fd8 --- /dev/null +++ b/queue-6.18/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From 8d29482d24964205b02bc39d424fb90573e44e9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index d86541073d42d..9cd546c084765 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -266,7 +266,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -415,7 +419,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans, + + nr++; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1523,7 +1531,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/btrfs-replace-assert-with-proper-error-handling-in-s.patch b/queue-6.18/btrfs-replace-assert-with-proper-error-handling-in-s.patch new file mode 100644 index 0000000000..d81de48501 --- /dev/null +++ b/queue-6.18/btrfs-replace-assert-with-proper-error-handling-in-s.patch @@ -0,0 +1,46 @@ +From 82052f7a03421112789c342fc8af87173f7d47c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:35 +0800 +Subject: btrfs: replace ASSERT with proper error handling in stripe lookup + fallback + +From: robbieko + +[ Upstream commit 653361585d251fbca0e19ac58b04ba95dd01e378 ] + +After falling back to the previous item in btrfs_delete_raid_extent(), +the code uses ASSERT(found_start <= start) to verify the found extent +actually precedes our target range. If the B-tree state is unexpected +(e.g. no overlapping extent exists), this triggers a kernel BUG/panic +in debug builds, or silently continues with wrong data otherwise. + +Replace the ASSERT with a proper bounds check that returns -ENOENT if +the found extent does not actually overlap with the start position. + +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index 460f46eb9a498..fb1fa9ff676f5 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -155,7 +155,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + btrfs_item_key_to_cpu(leaf, &key, slot); + found_start = key.objectid; + found_end = found_start + key.offset; +- ASSERT(found_start <= start); ++ if (found_start > start || found_end <= start) { ++ ret = -ENOENT; ++ break; ++ } + } + + if (key.type != BTRFS_RAID_STRIPE_KEY) +-- +2.53.0 + diff --git a/queue-6.18/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-6.18/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..2a93539a12 --- /dev/null +++ b/queue-6.18/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 84a84ec71876b22b1cf94bc56857424a6515a5ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index a277c8cc91661..e044af6fa1315 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3231,7 +3231,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-6.18/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch b/queue-6.18/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch new file mode 100644 index 0000000000..80c683886a --- /dev/null +++ b/queue-6.18/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch @@ -0,0 +1,75 @@ +From 24df84996a1b5fc9e9f6348920ba27104190be75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:58:56 +0100 +Subject: btrfs: tracepoints: fix sleep while in atomic context in + btrfs_sync_file() + +From: Filipe Manana + +[ Upstream commit c73370c677646e86fc4b1780fb07027bdf847375 ] + +The trace event btrfs_sync_file() is called in an atomic context (all trace +events are) and its call to dput(), which is needed due to the call to +dget_parent(), can sleep, triggering a kernel splat. + +This can be reproduced by enabling the trace event and running btrfs/056 +from fstests for example. The splat shown in dmesg is the following: + + [53.919] BUG: sleeping function called from invalid context at fs/dcache.c:970 + [53.947] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 32773, name: xfs_io + [53.988] preempt_count: 2, expected: 0 + [53.967] RCU nest depth: 0, expected: 0 + [53.943] Preemption disabled at: + [53.944] [<0000000000000000>] 0x0 + [54.078] CPU: 0 UID: 0 PID: 32773 Comm: xfs_io Tainted: G W 7.1.0-rc1-btrfs-next-232+ #1 PREEMPT(full) + [54.070] Tainted: [W]=WARN + [54.071] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [54.072] Call Trace: + [54.074] + [54.076] dump_stack_lvl+0x56/0x80 + [54.079] __might_resched.cold+0xd6/0x10f + [54.072] dput.part.0+0x24/0x110 + [54.078] trace_event_raw_event_btrfs_sync_file+0x75/0x140 [btrfs] + [54.089] btrfs_sync_file+0x1ed/0x530 [btrfs] + [54.087] ? __handle_mm_fault+0x8ae/0xed0 + [54.089] btrfs_do_write_iter+0x172/0x210 [btrfs] + [54.091] vfs_write+0x21f/0x450 + [54.094] __x64_sys_pwrite64+0x8d/0xc0 + [54.096] ? do_user_addr_fault+0x20c/0x670 + [54.099] do_syscall_64+0x60/0xf20 + [54.092] ? clear_bhb_loop+0x60/0xb0 + [54.094] entry_SYSCALL_64_after_hwframe+0x76/0x7e + +So stop using dget_parent() and dput() and access the parent dentry +directly as dentry->d_parent. This is also what ext4 is doing in +its equivalent trace event ext4_sync_file_enter(). + +Fixes: a85b46db143f ("btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file()") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + include/trace/events/btrfs.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index 0864700f76e0a..fa090a455037a 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -771,10 +771,8 @@ TRACE_EVENT(btrfs_sync_file, + TP_fast_assign( + struct dentry *dentry = file_dentry(file); + struct inode *inode = file_inode(file); +- struct dentry *parent = dget_parent(dentry); +- struct inode *parent_inode = d_inode(parent); ++ struct inode *parent_inode = d_inode(dentry->d_parent); + +- dput(parent); + TP_fast_assign_fsid(btrfs_sb(inode->i_sb)); + __entry->ino = btrfs_ino(BTRFS_I(inode)); + __entry->parent = btrfs_ino(BTRFS_I(parent_inode)); +-- +2.53.0 + diff --git a/queue-6.18/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-6.18/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..c7b664d198 --- /dev/null +++ b/queue-6.18/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From 18f7f2376d9dbba43a322fce769b12bd178164a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 655eed981078b..01871b4edafde 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3617,7 +3617,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.18/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch b/queue-6.18/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch new file mode 100644 index 0000000000..0fe9f82287 --- /dev/null +++ b/queue-6.18/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch @@ -0,0 +1,57 @@ +From 5d94fb173dfd8b46e5c76577eab982156c02e8d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:16:17 +0530 +Subject: bus: mhi: host: pci_generic: Add Qualcomm SDX35 modem + +From: Krishna Chaitanya Chundru + +[ Upstream commit 6a7084102bb9659f699005c420eb59eade6d3b4f ] + +Add support for sdx35 modem. Similar to SDX75, SDX35 can take longer to +transition to ready during power up, so use modem_qcom_v2_mhiv_config +configurations. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Qualcomm Device 011a + +Signed-off-by: Krishna Chaitanya Chundru +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260123-mhi_sdx35-v1-1-79440abf0c92@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index b929c7d6c49aa..8fb0ec666de07 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -407,6 +407,16 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { + .sideband_wake = false, + }; + ++static const struct mhi_pci_dev_info mhi_qcom_sdx35_info = { ++ .name = "qcom-sdx35m", ++ .config = &modem_qcom_v2_mhiv_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .mru_default = 32768, ++ .sideband_wake = false, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { + .name = "qcom-sdx24", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -898,6 +908,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), ++ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), +-- +2.53.0 + diff --git a/queue-6.18/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch b/queue-6.18/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch new file mode 100644 index 0000000000..904de5a4c1 --- /dev/null +++ b/queue-6.18/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch @@ -0,0 +1,56 @@ +From ccef7381862a2fff9e8b6c93eeb05011584b40ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:28:37 +0100 +Subject: bus: mhi: host: pci_generic: Add Telit FE912C04 modem support + +From: Daniele Palmas + +[ Upstream commit ac12b852b4ead4a586299c8f68cdcbcaf1bf6cbc ] + +Add SDX35 based modem Telit FE912C04, reusing FN920C04 configuration. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Device 1c5d:2045 + +Signed-off-by: Daniele Palmas +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260323122837.3406521-1-dnlplm@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index 8fb0ec666de07..a2fee2b699350 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -881,6 +881,16 @@ static const struct mhi_pci_dev_info mhi_telit_fe990b40_info = { + .edl_trigger = true, + }; + ++static const struct mhi_pci_dev_info mhi_telit_fe912c04_info = { ++ .name = "telit-fe912c04", ++ .config = &modem_telit_fn920c04_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++ .mru_default = 32768, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = { + .name = "netprisma-lcur57", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -908,6 +918,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ /* Telit FE912C04 (sdx35) */ ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2045), ++ .driver_data = (kernel_ulong_t) &mhi_telit_fe912c04_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-6.18/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..1df1ab34e3 --- /dev/null +++ b/queue-6.18/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From 6dc25b7adb3ad1264021a40218472ddc400fc509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index d0a5847f91114..b82ecbf0ad264 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -1117,6 +1117,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-6.18/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..350e81b899 --- /dev/null +++ b/queue-6.18/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From d9f11ebf083bfe4ac519fc0a9ac0a03f32b8d074 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index 723a6eb677540..ceb82723fa8cd 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -343,13 +343,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-6.18/coda_flag_children-fix-a-uaf.patch b/queue-6.18/coda_flag_children-fix-a-uaf.patch new file mode 100644 index 0000000000..f41995fb68 --- /dev/null +++ b/queue-6.18/coda_flag_children-fix-a-uaf.patch @@ -0,0 +1,44 @@ +From fad29da3ca7801f3bbbfa149509bc8a2ac3ccb36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:33:37 -0500 +Subject: coda_flag_children(): fix a UAF + +From: Al Viro + +[ Upstream commit e252ed8988578f01da5a4f5aa4c2269f96f03951 ] + +if de goes negative right under us, there's nothing to prevent inode +getting freed just as we call coda_flag_inode(). We are not holding +->d_lock, so it's not impossible. Not going to be reproducible on +bare hardware unless it's a realtime config, but it could happen on KVM. + +Trivial to fix - just hold rcu_read_lock() over that loop. + +Signed-off-by: Al Viro +Signed-off-by: Sasha Levin +--- + fs/coda/cache.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/coda/cache.c b/fs/coda/cache.c +index 970f0022ec528..2451312963004 100644 +--- a/fs/coda/cache.c ++++ b/fs/coda/cache.c +@@ -93,12 +93,14 @@ static void coda_flag_children(struct dentry *parent, int flag) + struct dentry *de; + + spin_lock(&parent->d_lock); ++ rcu_read_lock(); + hlist_for_each_entry(de, &parent->d_children, d_sib) { + struct inode *inode = d_inode_rcu(de); + /* don't know what to do with negative dentries */ + if (inode) + coda_flag_inode(inode, flag); + } ++ rcu_read_unlock(); + spin_unlock(&parent->d_lock); + } + +-- +2.53.0 + diff --git a/queue-6.18/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-6.18/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..e10e8a0466 --- /dev/null +++ b/queue-6.18/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From bb7b216e13d011052b55e534d3f76c7fadc440b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index d1d88debbd71e..34a90330d4d7e 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -2820,6 +2820,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-6.18/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch b/queue-6.18/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch new file mode 100644 index 0000000000..b504c81b1f --- /dev/null +++ b/queue-6.18/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch @@ -0,0 +1,102 @@ +From 9b41dd736976a91f0dac277b892b23ee516dd6d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 15:06:32 +0800 +Subject: cxl/pci: Hold memdev lock in cxl_event_trace_record() + +From: Li Ming + +[ Upstream commit dc372e5f429ced834d81ff12a945397dc43585a8 ] + +cxl_event_config() invokes cxl_mem_get_event_record() to get remain +event logs from CXL device during cxl_pci_probe(). If CXL memdev probing +failed before that, it is possible to access an invalid endpoint. So +adding a cxlmd->driver binding status checking inside +cxl_dpa_to_region() to ensure the corresponding endpoint is valid. + +Besides, cxl_event_trace_record() needs to hold memdev lock to invoke +cxl_dpa_to_region() to ensure the memdev probing completed. It is +possible that cxl_event_trace_record() is invoked during the CXL memdev +probing, especially user or cxl_acpi triggers CXL memdev re-probing. + +Suggested-by: Dan Williams +Reviewed-by: Dan Williams +Reviewed-by: Dave Jiang +Signed-off-by: Li Ming +Link: https://patch.msgid.link/20260314-fix_access_endpoint_without_drv_check-v2-3-4c09edf2e1db@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/mbox.c | 5 +++-- + drivers/cxl/core/region.c | 8 +++++--- + drivers/cxl/cxlmem.h | 2 +- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c +index fa6dd0c94656f..7b923408b6c5f 100644 +--- a/drivers/cxl/core/mbox.c ++++ b/drivers/cxl/core/mbox.c +@@ -886,7 +886,7 @@ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) + } + EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, "CXL"); + +-void cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++void cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt) +@@ -913,6 +913,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + * translations. Take topology mutation locks and lookup + * { HPA, REGION } from { DPA, MEMDEV } in the event record. + */ ++ guard(device)(&cxlmd->dev); + guard(rwsem_read)(&cxl_rwsem.region); + guard(rwsem_read)(&cxl_rwsem.dpa); + +@@ -961,7 +962,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + } + EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, "CXL"); + +-static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++static void __cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + struct cxl_event_record_raw *record) + { +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index 41b64d871c5a1..7b9b7db31c483 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -2893,13 +2893,15 @@ static int __cxl_dpa_to_region(struct device *dev, void *arg) + struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) + { + struct cxl_dpa_to_region_context ctx; +- struct cxl_port *port; ++ struct cxl_port *port = cxlmd->endpoint; ++ ++ if (!cxlmd->dev.driver) ++ return NULL; + + ctx = (struct cxl_dpa_to_region_context) { + .dpa = dpa, + }; +- port = cxlmd->endpoint; +- if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) ++ if (cxl_num_decoders_committed(port)) + device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); + + return ctx.cxlr; +diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h +index c12ab4fc95123..3c8b226a919bd 100644 +--- a/drivers/cxl/cxlmem.h ++++ b/drivers/cxl/cxlmem.h +@@ -856,7 +856,7 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, + void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, + unsigned long *cmds); + void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status); +-void cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++void cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt); +-- +2.53.0 + diff --git a/queue-6.18/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch b/queue-6.18/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch new file mode 100644 index 0000000000..bde7eabec9 --- /dev/null +++ b/queue-6.18/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch @@ -0,0 +1,137 @@ +From 74445003d71f2d8701a7c05334e03e7b9f55cd1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:28:13 -0700 +Subject: cxl/region: Fix use-after-free from auto assembly failure + +From: Dan Williams + +[ Upstream commit 87805c32e6ad7b5ce2d9f7f47e76081857a4a335 ] + +The following crash signature results from region destruction while an +endpoint decoder is staged, but not fully attached. + +[ dj: Moved bus_find_device( to next line. ] + +Signed-off-by: Dan Williams +Reviewed-by: Ira Weiny +Reviewed-by: Alison Schofield +Reviewed-by: Dave Jiang +Link: https://patch.msgid.link/20260327052821.440749-2-dan.j.williams@intel.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/region.c | 54 ++++++++++++++++++++++++++++++++++++++- + drivers/cxl/cxl.h | 6 +++-- + 2 files changed, 57 insertions(+), 3 deletions(-) + +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index 7b9b7db31c483..0eb804aa45e45 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -1025,6 +1025,14 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr, + + if (!cxld->region) { + cxld->region = cxlr; ++ ++ /* ++ * Now that cxld->region is set the intermediate staging state ++ * can be cleared. ++ */ ++ if (cxld == &cxled->cxld && ++ cxled->state == CXL_DECODER_STATE_AUTO_STAGED) ++ cxled->state = CXL_DECODER_STATE_AUTO; + get_device(&cxlr->dev); + } + +@@ -1753,6 +1761,7 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr, + pos = p->nr_targets; + p->targets[pos] = cxled; + cxled->pos = pos; ++ cxled->state = CXL_DECODER_STATE_AUTO_STAGED; + p->nr_targets++; + + return 0; +@@ -2101,6 +2110,47 @@ static int cxl_region_attach(struct cxl_region *cxlr, + return 0; + } + ++static int cxl_region_by_target(struct device *dev, const void *data) ++{ ++ const struct cxl_endpoint_decoder *cxled = data; ++ struct cxl_region_params *p; ++ struct cxl_region *cxlr; ++ ++ if (!is_cxl_region(dev)) ++ return 0; ++ ++ cxlr = to_cxl_region(dev); ++ p = &cxlr->params; ++ return p->targets[cxled->pos] == cxled; ++} ++ ++/* ++ * When an auto-region fails to assemble the decoder may be listed as a target, ++ * but not fully attached. ++ */ ++static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled) ++{ ++ struct cxl_region_params *p; ++ struct cxl_region *cxlr; ++ int pos = cxled->pos; ++ ++ if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED) ++ return; ++ ++ struct device *dev __free(put_device) = ++ bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target); ++ if (!dev) ++ return; ++ ++ cxlr = to_cxl_region(dev); ++ p = &cxlr->params; ++ ++ p->nr_targets--; ++ cxled->state = CXL_DECODER_STATE_AUTO; ++ cxled->pos = -1; ++ p->targets[pos] = NULL; ++} ++ + static struct cxl_region * + __cxl_decoder_detach(struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled, int pos, +@@ -2124,8 +2174,10 @@ __cxl_decoder_detach(struct cxl_region *cxlr, + cxled = p->targets[pos]; + } else { + cxlr = cxled->cxld.region; +- if (!cxlr) ++ if (!cxlr) { ++ cxl_cancel_auto_attach(cxled); + return NULL; ++ } + p = &cxlr->params; + } + +diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h +index 3a794278cc7fe..48ca1ca7de4c5 100644 +--- a/drivers/cxl/cxl.h ++++ b/drivers/cxl/cxl.h +@@ -378,12 +378,14 @@ struct cxl_decoder { + }; + + /* +- * Track whether this decoder is reserved for region autodiscovery, or +- * free for userspace provisioning. ++ * Track whether this decoder is free for userspace provisioning, reserved for ++ * region autodiscovery, whether it is started connecting (awaiting other ++ * peers), or has completed auto assembly. + */ + enum cxl_decoder_state { + CXL_DECODER_STATE_MANUAL, + CXL_DECODER_STATE_AUTO, ++ CXL_DECODER_STATE_AUTO_STAGED, + }; + + /** +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-6.18/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..f16d3fe137 --- /dev/null +++ b/queue-6.18/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From 9e30abe5c15f0478944cdf5e91554aa117e1d32d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index db77ba58f64ac..acb335cee4d36 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1816,3 +1816,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 2f107e7c67d0a..91f8706b41fdd 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -141,6 +141,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index bb0b484d4d687..1444915e0b7a1 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2961,6 +2961,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2977,6 +2980,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3542,7 +3559,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.18/dm-integrity-fix-mismatched-queue-limits.patch b/queue-6.18/dm-integrity-fix-mismatched-queue-limits.patch new file mode 100644 index 0000000000..bf2a443895 --- /dev/null +++ b/queue-6.18/dm-integrity-fix-mismatched-queue-limits.patch @@ -0,0 +1,48 @@ +From e3b72b4647960bd1334d24df6f96c4eedbaa8800 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:36:06 -0700 +Subject: dm-integrity: fix mismatched queue limits + +From: Keith Busch + +[ Upstream commit 6ebf3b6c6f16fda0568aa4207c6cd398f983c354 ] + +A user can integritysetup a device with a backing device using a 4k +logical block size, but request the dm device use 1k or 2k. This +mismatch creates an inconsistency such that the dm device would report +limits for IO that it can't actually execute. Fix this by using the +backing device's limits if they are larger. + +Signed-off-by: Keith Busch +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-integrity.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index a9c0157bf42fe..a9972439228dc 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -4046,9 +4046,15 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim + struct dm_integrity_c *ic = ti->private; + + if (ic->sectors_per_block > 1) { +- limits->logical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->physical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->io_min = ic->sectors_per_block << SECTOR_SHIFT; ++ limits->logical_block_size = ++ max(limits->logical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->physical_block_size = ++ max(limits->physical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->io_min = ++ max(limits->io_min, ++ ic->sectors_per_block << SECTOR_SHIFT); + limits->dma_alignment = limits->logical_block_size - 1; + limits->discard_granularity = ic->sectors_per_block << SECTOR_SHIFT; + } +-- +2.53.0 + diff --git a/queue-6.18/dm-vdo-indexer-validate-saved-zone-count.patch b/queue-6.18/dm-vdo-indexer-validate-saved-zone-count.patch new file mode 100644 index 0000000000..85fc8d25f9 --- /dev/null +++ b/queue-6.18/dm-vdo-indexer-validate-saved-zone-count.patch @@ -0,0 +1,36 @@ +From bf594c6d60328ff6f5f8bcd310549ac3be1cdfb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:54 -0500 +Subject: dm vdo indexer: validate saved zone count + +From: Matthew Sakai + +[ Upstream commit 9e809bb1defe9be7fed2e21552c6b03b2694394d ] + +Verify that the loaded zone count is in the valid range +before using it as a loop iterator. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/indexer/index-layout.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/md/dm-vdo/indexer/index-layout.c b/drivers/md/dm-vdo/indexer/index-layout.c +index 61edf2b72427d..37144249f7ba6 100644 +--- a/drivers/md/dm-vdo/indexer/index-layout.c ++++ b/drivers/md/dm-vdo/indexer/index-layout.c +@@ -1445,6 +1445,9 @@ static int __must_check reconstruct_index_save(struct index_save_layout *isl, + u64 last_block = next_block + isl->index_save.block_count; + + isl->zone_count = table->header.region_count - 3; ++ if (isl->zone_count > MAX_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); + + last_region = &table->regions[table->header.region_count - 1]; + if (last_region->kind == RL_KIND_EMPTY) { +-- +2.53.0 + diff --git a/queue-6.18/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch b/queue-6.18/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch new file mode 100644 index 0000000000..87592886c9 --- /dev/null +++ b/queue-6.18/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch @@ -0,0 +1,37 @@ +From c58764a2fd9003b1aad2e4dabc9faca91fba2585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:55 -0500 +Subject: dm vdo slab-depot: validate old zone count on load + +From: Matthew Sakai + +[ Upstream commit b3929b2cc2a6003b8e301e6540c651e60d24dcb4 ] + +Verify the old zone count has a valid value before using +it to compute slab summary entry offsets. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/slab-depot.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c +index f3d80ff7bef55..92b32af1ba4e9 100644 +--- a/drivers/md/dm-vdo/slab-depot.c ++++ b/drivers/md/dm-vdo/slab-depot.c +@@ -4252,6 +4252,10 @@ int vdo_decode_slab_depot(struct slab_depot_state_2_0 state, struct vdo *vdo, + } + slab_size_shift = ilog2(slab_size); + ++ if (state.zone_count > MAX_VDO_PHYSICAL_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); ++ + result = vdo_allocate_extended(struct slab_depot, + vdo->thread_config.physical_zone_count, + struct block_allocator, __func__, &depot); +-- +2.53.0 + diff --git a/queue-6.18/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch b/queue-6.18/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch new file mode 100644 index 0000000000..b5863eb936 --- /dev/null +++ b/queue-6.18/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch @@ -0,0 +1,40 @@ +From 9a7688dcc64fe17becae28bbe92e57fd9a6dd9cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:48:39 +0100 +Subject: drivers/virt: pkvm: Add Kconfig dependency on DMA_RESTRICTED_POOL + +From: Will Deacon + +[ Upstream commit 61135967fa76d37883d90ccccc5a1cb73e90b94d ] + +pKVM guests practically rely on CONFIG_DMA_RESTRICTED_POOL=y in order +to establish shared memory regions with the host for virtio buffers. + +Make CONFIG_ARM_PKVM_GUEST depend on CONFIG_DMA_RESTRICTED_POOL to avoid +the inevitable segmentation faults experience if you have the former but +not the latter. + +Reported-by: Marc Zyngier +Signed-off-by: Will Deacon +Link: https://patch.msgid.link/20260330144841.26181-39-will@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Sasha Levin +--- + drivers/virt/coco/pkvm-guest/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/virt/coco/pkvm-guest/Kconfig b/drivers/virt/coco/pkvm-guest/Kconfig +index d2f344f1f98f7..928b8e1668ccc 100644 +--- a/drivers/virt/coco/pkvm-guest/Kconfig ++++ b/drivers/virt/coco/pkvm-guest/Kconfig +@@ -1,6 +1,6 @@ + config ARM_PKVM_GUEST + bool "Arm pKVM protected guest driver" +- depends on ARM64 ++ depends on ARM64 && DMA_RESTRICTED_POOL + help + Protected guests running under the pKVM hypervisor on arm64 + are isolated from the host and must issue hypercalls to enable +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch b/queue-6.18/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch new file mode 100644 index 0000000000..3660e812de --- /dev/null +++ b/queue-6.18/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch @@ -0,0 +1,113 @@ +From ff3b990e53ea5212a2f663238225921e9b8c1204 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:25:25 -0400 +Subject: drm/amd/display: Avoid turning off the PHY when OTG is running for + DVI + +From: Nicholas Kazlauskas + +[ Upstream commit ee212b0208a18831d2b537865da56708c17af90d ] + +[Why] +The OTG's virtual pixel clock source for DVI comes from the PHY. + +If the signal type is DVI then the OTG can become stuck on pre DCN401 +ASIC when DPMS off occurs because the OTG remains running but the +PHY transmitter is disabled. + +[How] +There exists logic to keep track of the OTG running refcount on the +link to determine if the link needs to go to PLL_EN instead of TX_EN +but the logic only checks for HDMI TMDS on older ASIC. + +DVI is still a TMDS signal type so the constraint should also apply. + +Replace the checks for dc_is_hdmi_tmds_signal with dc_is_tmds_signal to +cover both HDMI and DVI for the symclk refcount workaround. + +Reviewed-by: Dillon Varone +Reviewed-by: Charlene Liu +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 4 ++-- + drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 4 ++-- + drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 2 +- + drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 2 +- + 4 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +index 8f86177de48dc..71dffa17d49f7 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +@@ -1547,7 +1547,7 @@ static enum dc_status dce110_enable_stream_timing( + return DC_ERROR_UNEXPECTED; + } + +- if (dc_is_hdmi_tmds_signal(stream->signal)) { ++ if (dc_is_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; +@@ -2340,7 +2340,7 @@ static void dce110_reset_hw_ctx_wrap( + BREAK_TO_DEBUGGER(); + } + pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); +- if (dc_is_hdmi_tmds_signal(pipe_ctx_old->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx_old->stream->signal)) + pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; + pipe_ctx_old->plane_res.mi->funcs->free_mem_input( + pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +index a4025a09a38a3..9184b38a809ff 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +@@ -908,7 +908,7 @@ enum dc_status dcn20_enable_stream_timing( + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + +- if (dc_is_hdmi_tmds_signal(stream->signal)) { ++ if (dc_is_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; +@@ -2868,7 +2868,7 @@ void dcn20_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +index e9bd43a72ce58..c1748492bf17d 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +@@ -551,7 +551,7 @@ static void dcn31_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + + if (pipe_ctx->top_pipe == NULL) { +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index a9fd566cf4e8d..3197cd2de9c3a 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1893,7 +1893,7 @@ void dcn401_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-6.18/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..e46c319189 --- /dev/null +++ b/queue-6.18/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From fa54b930051958f91158f8f88c5e9a88830c522b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index c800c603bf708..a5860c127107c 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1936,7 +1936,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch b/queue-6.18/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch new file mode 100644 index 0000000000..f7757ff1d7 --- /dev/null +++ b/queue-6.18/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch @@ -0,0 +1,64 @@ +From 21133cdc50367d80f0fcb0bbd2537038e2cada1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 17:08:01 -0500 +Subject: drm/amd/display: Exit IPS w/ DC helper for all dc_set_power_state + cases + +From: Ovidiu Bunea + +[ Upstream commit f44c094449669c7d9ac403cc73ce23e255f0828b ] + +[why & how] +On D3 path during dc_set_power_state, we may be in idle_allowed=true, +at which point we will exit idle via dc_wake_and_execute_dmub_cmd_list +which doesn't update dc->idle_optimizations_allowed to false. This +would cause any future attempts to allow idle optimizations via the DC +helper to get skipped because the value is stale and not reflective of +the actual HW state. + +Move dc_exit_ips_for_hw_access() to the top of the function. +Additionally ensure that dc_power_down_on_boot thread holds the DC +lock and only runs if there are 0 streams. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ovidiu Bunea +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 5f2d5638c8191..0bcde44e7ed82 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -5431,6 +5431,9 @@ void dc_power_down_on_boot(struct dc *dc) + { + if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW && + dc->hwss.power_down_on_boot) { ++ if (dc->current_state->stream_count > 0) ++ return; ++ + if (dc->caps.ips_support) + dc_exit_ips_for_hw_access(dc); + dc->hwss.power_down_on_boot(dc); +@@ -5442,12 +5445,12 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state) + if (!dc->current_state) + return; + ++ dc_exit_ips_for_hw_access(dc); ++ + switch (power_state) { + case DC_ACPI_CM_POWER_STATE_D0: + dc_state_construct(dc, dc->current_state); + +- dc_exit_ips_for_hw_access(dc); +- + dc_z10_restore(dc); + + dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state); +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch b/queue-6.18/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch new file mode 100644 index 0000000000..deffc9286a --- /dev/null +++ b/queue-6.18/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch @@ -0,0 +1,61 @@ +From 671d71e86f30b45bd2c8f2c1d5af77c8e2726d99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:57:19 -0500 +Subject: drm/amd/display: Fix cursor pos at overlay plane edges on DCN4 + +From: Ivan Lipski + +[ Upstream commit d8f6c978fd3d12ae129879dd1c514cec2e8cf2f8 ] + +[Why&How] +On DCN4, when cursor straddles the left/top edge of an overlay plane, the +recout-relative position becomes negative. These negative values wrap +to large positive numbers when cast to uint32_t, causing the cursor on the +the overlay plane to disappear. + +Fix by adding hotspot adjustment and position clamping after the +recout-relative calculation, matching the existing ODM/MPC slice +boundary handling. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index 914c30a42ecfa..b802f3ed53fc9 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1208,6 +1208,25 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) + x_pos = pos_cpy.x - param.recout.x; + y_pos = pos_cpy.y - param.recout.y; + ++ /** ++ * If the cursor position is negative after recout adjustment, we need ++ * to shift the hotspot to compensate and clamp position to 0. This ++ * handles the case where cursor straddles the left/top edge of an ++ * overlay plane - the cursor is partially visible and needs correct ++ * hotspot adjustment to render the visible portion. ++ */ ++ if (x_pos < 0) { ++ pos_cpy.x_hotspot -= x_pos; ++ if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) ++ adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); ++ x_pos = 0; ++ } ++ ++ if (y_pos < 0) { ++ pos_cpy.y_hotspot -= y_pos; ++ y_pos = 0; ++ } ++ + recout_x_pos = x_pos - pos_cpy.x_hotspot; + recout_y_pos = y_pos - pos_cpy.y_hotspot; + +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-fix-dcn401_optimize_bandwidth.patch b/queue-6.18/drm-amd-display-fix-dcn401_optimize_bandwidth.patch new file mode 100644 index 0000000000..2d8fda7a7e --- /dev/null +++ b/queue-6.18/drm-amd-display-fix-dcn401_optimize_bandwidth.patch @@ -0,0 +1,49 @@ +From 19d853a95ec91628c90fd0cbd786b14e534cff59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:53:44 -0500 +Subject: drm/amd/display: Fix dcn401_optimize_bandwidth + +From: Charlene Liu + +[ Upstream commit 002f32db0d4292f117994c330928d2374887b28e ] + +[Why&How] +We should check for != zstate disallow and programming extend blank from a +different struct. + +Reviewed-by: Leo Chen +Reviewed-by: Dmytro Laktyushkin +Signed-off-by: Charlene Liu +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index b802f3ed53fc9..a9fd566cf4e8d 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1486,7 +1486,7 @@ void dcn401_optimize_bandwidth( + dc->clk_mgr, + context, + true); +- if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { ++ if (context->bw_ctx.bw.dcn.clk.zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW) { + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + +@@ -1494,7 +1494,7 @@ void dcn401_optimize_bandwidth( + && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max + && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) + pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, +- pipe_ctx->dlg_regs.min_dst_y_next_start); ++ pipe_ctx->hubp_regs.dlg_regs.min_dst_y_next_start); + } + } + } +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch b/queue-6.18/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch new file mode 100644 index 0000000000..d0652f0230 --- /dev/null +++ b/queue-6.18/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch @@ -0,0 +1,93 @@ +From d7c308512538f35e588c66b0086c4f0e6853d743 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:28:12 -0400 +Subject: drm/amd/display: Fix HostVMMinPageSize unit mismatch in DML2.1 + +From: Nicholas Kazlauskas + +[ Upstream commit 5721b5b9c9c792233d7817239bd81925fb3ad9d1 ] + +[Why] +This was found back on DML2 but was missed when creating DML2.1. + +The bottom layer calculation (CalculateHostVMDynamicLevels) expects +a value in bytes, not KB, but we pass in the value in KB (eg. 4). + +This causes an extra page table level to be required in the prefetch +bytes which can be significant overhead - preventing some modes +from being supported that should otherwise be. + +[How] +Correct the units by multiplying the input and override values by 1024. + +Reviewed-by: Austin Zheng +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Roman Li +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +index bf62d42b3f78b..2106fd859a8a3 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +@@ -7361,7 +7361,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter + s->tdlut_bytes_per_group, + s->HostVMInefficiencyFactor, + s->HostVMInefficiencyFactorPrefetch, +- mode_lib->soc.hostvm_min_page_size_kbytes, ++ mode_lib->soc.hostvm_min_page_size_kbytes * 1024, + mode_lib->soc.qos_parameters.qos_type, + !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), + mode_lib->soc.max_outstanding_reqs, +@@ -7457,7 +7457,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter + CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; + CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; + CalculatePrefetchSchedule_params->VStartup = s->MaximumVStartup[k]; +- CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; + CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; + CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; +@@ -8928,7 +8928,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthY; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthC; +- CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; + +@@ -10715,7 +10715,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->mp.SwathWidthY; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->mp.SwathWidthC; +- CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; + +@@ -10931,7 +10931,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + s->tdlut_bytes_per_group, + s->HostVMInefficiencyFactor, + s->HostVMInefficiencyFactorPrefetch, +- mode_lib->soc.hostvm_min_page_size_kbytes, ++ mode_lib->soc.hostvm_min_page_size_kbytes * 1024, + mode_lib->soc.qos_parameters.qos_type, + !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), + mode_lib->soc.max_outstanding_reqs, +@@ -11224,7 +11224,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; + CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; + CalculatePrefetchSchedule_params->VStartup = s->MaxVStartupLines[k]; +- CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; + CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; + CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-merge-pipes-for-validate.patch b/queue-6.18/drm-amd-display-merge-pipes-for-validate.patch new file mode 100644 index 0000000000..a7a22e2136 --- /dev/null +++ b/queue-6.18/drm-amd-display-merge-pipes-for-validate.patch @@ -0,0 +1,43 @@ +From 18b14311659e28b1056d28c23e8262eb779fe399 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:48:11 -0500 +Subject: drm/amd/display: Merge pipes for validate + +From: Harry Wentland + +[ Upstream commit 606f6b171326152ef08d0ef0ad49f52034edca07 ] + +Validation expects to operate on non-split pipes. This is +seen in dcn20_fast_validate_bw, which merges pipes for +validation. We weren't doing that in the non-fast path +which lead to validation failures when operating with +4-to-1 MPC and a writeback connector. + +Co-developed by Claude Sonnet 4.5 + +Assisted-by: Claude:claude-sonnet-4.5 +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Harry Wentland +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +index ff63f59ff928a..559039686946d 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +@@ -1642,6 +1642,8 @@ noinline bool dcn30_internal_validate_bw( + if (!pipes) + return false; + ++ dcn20_merge_pipes_for_validate(dc, context); ++ + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch b/queue-6.18/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch new file mode 100644 index 0000000000..e120f4953f --- /dev/null +++ b/queue-6.18/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch @@ -0,0 +1,102 @@ +From bee1cc8721397a727c1b57e0fea71031a4ba0fae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:34:56 -0400 +Subject: drm/amd/display: Pass min page size from SOC BB to dml2_1 plane + config + +From: Nicholas Kazlauskas + +[ Upstream commit 07ac59230d5fd603d56af2363dae80d3e973e4bc ] + +[Why] +Like dml2_0 this isn't guaranteed to be constant for every ASIC. + +This can cause corruption or underflow for linear surfaces due to a +wrong PTE_ROW_HEIGHT_LINEAR value if not correctly specified. + +[How] +Like dml2_0 pass in the SOC bb into the plane configuration population +functions. + +Set both GPUVM and HostVM page sizes in the overrides. + +Reviewed-by: Dillon Varone +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Roman Li +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../dc/dml2/dml21/dml21_translation_helper.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c +index bf5e7f4e04167..a64c0407ad515 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c +@@ -381,7 +381,9 @@ static void populate_dml21_dummy_surface_cfg(struct dml2_surface_cfg *surface, c + surface->tiling = dml2_sw_64kb_2d; + } + +-static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, const struct dc_stream_state *stream) ++static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, ++ const struct dc_stream_state *stream, ++ const struct dml2_soc_bb *soc_bb) + { + unsigned int width, height; + +@@ -425,7 +427,8 @@ static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, + plane->pixel_format = dml2_444_32; + + plane->dynamic_meta_data.enable = false; +- plane->overrides.gpuvm_min_page_size_kbytes = 256; ++ plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; ++ plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; + } + + static void populate_dml21_surface_config_from_plane_state( +@@ -495,7 +498,7 @@ static const struct scaler_data *get_scaler_data_for_plane( + + static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dml_ctx, + struct dml2_plane_parameters *plane, const struct dc_plane_state *plane_state, +- const struct dc_state *context, unsigned int stream_index) ++ const struct dc_state *context, unsigned int stream_index, const struct dml2_soc_bb *soc_bb) + { + const struct scaler_data *scaler_data = get_scaler_data_for_plane(dml_ctx, plane_state, context); + struct dc_stream_state *stream = context->streams[stream_index]; +@@ -631,7 +634,8 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm + plane->composition.rotation_angle = (enum dml2_rotation_angle) plane_state->rotation; + plane->stream_index = stream_index; + +- plane->overrides.gpuvm_min_page_size_kbytes = 256; ++ plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; ++ plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; + + plane->immediate_flip = plane_state->flip_immediate; + +@@ -765,7 +769,9 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s + if (context->stream_status[stream_index].plane_count == 0) { + disp_cfg_plane_location = dml_dispcfg->num_planes++; + populate_dml21_dummy_surface_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->streams[stream_index]); +- populate_dml21_dummy_plane_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->streams[stream_index]); ++ populate_dml21_dummy_plane_cfg( ++ &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], ++ context->streams[stream_index], &dml_ctx->v21.dml_init.soc_bb); + dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; + } else { + for (plane_index = 0; plane_index < context->stream_status[stream_index].plane_count; plane_index++) { +@@ -777,7 +783,10 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s + ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location < __DML2_WRAPPER_MAX_STREAMS_PLANES__); + + populate_dml21_surface_config_from_plane_state(in_dc, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->stream_status[stream_index].plane_states[plane_index]); +- populate_dml21_plane_config_from_plane_state(dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->stream_status[stream_index].plane_states[plane_index], context, stream_index); ++ populate_dml21_plane_config_from_plane_state( ++ dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], ++ context->stream_status[stream_index].plane_states[plane_index], ++ context, stream_index, &dml_ctx->v21.dml_init.soc_bb); + dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; + + if (dml21_wrapper_get_plane_id(context, context->streams[stream_index]->stream_id, context->stream_status[stream_index].plane_states[plane_index], &dml_ctx->v21.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[disp_cfg_plane_location])) +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-remove-duplicate-format-modifier.patch b/queue-6.18/drm-amd-display-remove-duplicate-format-modifier.patch new file mode 100644 index 0000000000..5f6c27c523 --- /dev/null +++ b/queue-6.18/drm-amd-display-remove-duplicate-format-modifier.patch @@ -0,0 +1,60 @@ +From 55c2f80717c96dc640c32d1161c663d135b600eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:08:15 -0500 +Subject: drm/amd/display: remove duplicate format modifier + +From: Erik Kurzinger + +[ Upstream commit 6736c8ff9d63e847a3b694aeaeb78d4e8ad42464 ] + +amdgpu_dm_plane_get_plane_modifiers always adds DRM_FORMAT_MOD_LINEAR to +the list of modifiers. However, with gfx12, +amdgpu_dm_plane_add_gfx12_modifiers also adds that modifier to the list. +So we end up with two copies. Most apps just ignore this but some +(Weston) don't like it. + +As a fix, we change amdgpu_dm_plane_add_gfx12_modifiers to not add +DRM_FORMAT_MOD_LINEAR to the list, matching the behavior of analogous +functions for other chips. + +Signed-off-by: Erik Kurzinger +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 2ecebf9a00fa4..a767d2b42f47a 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -703,21 +703,21 @@ static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, + uint8_t max_comp_block[] = {2, 1, 0}; + uint64_t max_comp_block_mod[ARRAY_SIZE(max_comp_block)] = {0}; + uint8_t i = 0, j = 0; +- uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b, DRM_FORMAT_MOD_LINEAR}; ++ /* Note, linear (no DCC) gets added to the modifier list for all chips by the caller. */ ++ uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b}; + + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + max_comp_block_mod[i] = AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, max_comp_block[i]); + + /* With DCC: Best choice should be kept first. Hence, add all 256k modifiers of different + * max compressed blocks first and then move on to the next smaller sized layouts. +- * Do not add the linear modifier here, and hence the condition of size-1 for the loop + */ +- for (j = 0; j < ARRAY_SIZE(gfx12_modifiers) - 1; j++) ++ for (j = 0; j < ARRAY_SIZE(gfx12_modifiers); j++) + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, + ver | dcc | max_comp_block_mod[i] | gfx12_modifiers[j]); + +- /* Without DCC. Add all modifiers including linear at the end */ ++ /* Without DCC. */ + for (i = 0; i < ARRAY_SIZE(gfx12_modifiers); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, gfx12_modifiers[i]); + +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch b/queue-6.18/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch new file mode 100644 index 0000000000..cd0a9e3404 --- /dev/null +++ b/queue-6.18/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch @@ -0,0 +1,63 @@ +From c91239d99ebad90f15d111f2519739beb0da2413 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:45:47 -0400 +Subject: drm/amd/display: Remove invalid DPSTREAMCLK mask usage + +From: Roman Li + +[ Upstream commit 8de2559ec172b04301d6e53c4f30388e40fad08c ] + +[Why] +The invalid register field access causes ASSERT(mask != 0) to fire +in set_reg_field_values() during display enable. + +WARNING: at drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:100 +set_reg_field_values.isra.0+0xcf/0xf0 [amdgpu] +Call Trace: + +generic_reg_update_ex+0x66/0x1d0 [amdgpu] +dccg401_set_dpstreamclk+0xed/0x350 [amdgpu] +dcn401_enable_stream+0x165/0x370 [amdgpu] +link_set_dpms_on+0x6e9/0xe90 [amdgpu] +dce110_apply_single_controller_ctx_to_hw+0x343/0x530 [amdgpu] +dce110_apply_ctx_to_hw+0x1f6/0x2d0 [amdgpu] +dc_commit_state_no_check+0x49a/0xe20 [amdgpu] +dc_commit_streams+0x354/0x570 [amdgpu] +amdgpu_dm_atomic_commit_tail+0x6f8/0x3fc0 [amdgpu] + +DCN4.x hardware does not have DPSTREAMCLK_GATE_DISABLE and +DPSTREAMCLK_ROOT_GATE_DISABLE fields in DCCG_GATE_DISABLE_CNTL3. +These global fields only exist in DCN3.1.x hardware. + +[How] +Remove the call that tries to update non-existent fields in CNTL3. +DCN4.x uses per-instance fields in CNTL5 instead, +which are already correctly programmed in the switch cases above. + +Reviewed-by: Dillon Varone +Signed-off-by: Roman Li +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +index 0b8ed9b94d3c5..3a2eca9e45e23 100644 +--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c ++++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +@@ -525,10 +525,6 @@ static void dccg401_enable_dpstreamclk(struct dccg *dccg, int otg_inst, int dp_h + BREAK_TO_DEBUGGER(); + return; + } +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) +- REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3, +- DPSTREAMCLK_GATE_DISABLE, 1, +- DPSTREAMCLK_ROOT_GATE_DISABLE, 1); + } + + void dccg401_disable_dpstreamclk(struct dccg *dccg, int dp_hpo_inst) +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch b/queue-6.18/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch new file mode 100644 index 0000000000..25025bff2a --- /dev/null +++ b/queue-6.18/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch @@ -0,0 +1,162 @@ +From c3ef8a650b4278561a13e3e6f7a27edd74fd1509 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 10:21:15 -0500 +Subject: drm/amdgpu: Check for multiplication overflow in checkpoint stack + size + +From: David Francis + +[ Upstream commit 421c0f19043337a553e802b2dfe4b56d538ef4d6 ] + +get_checkpoint_info() in kfd_mqd_manager_v9.c finds 32-bit value +ctl_stack_size by multiplying two 32-bit values. This can overflow to a +lower value, which could result in copying outside the bounds of +a buffer in checkpoint_mqd() in the same file. + +Put in a check for the overflow, and fail with -EINVAL if detected. + +v2: use check_mul_overflow() + +Signed-off-by: David Francis +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 7 +++++-- + drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 3 ++- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 7 +++++-- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 3 ++- + drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 8 +++++++- + 6 files changed, 22 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 51a47a91e21e5..df6faa9da0a6e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2717,7 +2717,7 @@ static int get_wave_state(struct device_queue_manager *dqm, + ctl_stack, ctl_stack_used_size, save_area_used_size); + } + +-static void get_queue_checkpoint_info(struct device_queue_manager *dqm, ++static int get_queue_checkpoint_info(struct device_queue_manager *dqm, + const struct queue *q, + u32 *mqd_size, + u32 *ctl_stack_size) +@@ -2725,6 +2725,7 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm, + struct mqd_manager *mqd_mgr; + enum KFD_MQD_TYPE mqd_type = + get_mqd_type_from_queue_type(q->properties.type); ++ int ret = 0; + + dqm_lock(dqm); + mqd_mgr = dqm->mqd_mgrs[mqd_type]; +@@ -2732,9 +2733,11 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm, + *ctl_stack_size = 0; + + if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info) +- mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size); ++ ret = mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size); + + dqm_unlock(dqm); ++ ++ return ret; + } + + static int checkpoint_mqd(struct device_queue_manager *dqm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +index 74a61b5b2f0b4..6888467029045 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +@@ -192,7 +192,7 @@ struct device_queue_manager_ops { + + int (*reset_queues)(struct device_queue_manager *dqm, + uint16_t pasid); +- void (*get_queue_checkpoint_info)(struct device_queue_manager *dqm, ++ int (*get_queue_checkpoint_info)(struct device_queue_manager *dqm, + const struct queue *q, u32 *mqd_size, + u32 *ctl_stack_size); + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +index 17cc1f25c8d08..f9739cfb09263 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +@@ -102,7 +102,8 @@ struct mqd_manager { + u32 *ctl_stack_used_size, + u32 *save_area_used_size); + +- void (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, uint32_t *ctl_stack_size); ++ int (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, ++ uint32_t *ctl_stack_size); + + void (*checkpoint_mqd)(struct mqd_manager *mm, + void *mqd, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +index f2dee320fada4..37c34d5de0bb4 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +@@ -369,11 +369,14 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, + return 0; + } + +-static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) ++static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) + { + struct v9_mqd *m = get_mqd(mqd); + +- *ctl_stack_size = m->cp_hqd_cntl_stack_size * NUM_XCC(mm->dev->xcc_mask); ++ if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size)) ++ return -EINVAL; ++ ++ return 0; + } + + static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +index c1fafc5025158..f60ed6a75c30c 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +@@ -274,10 +274,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, + return 0; + } + +-static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) ++static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) + { + /* Control stack is stored in user mode */ + *ctl_stack_size = 0; ++ return 0; + } + + static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index 7bf712032c52c..5e5d30bd11178 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -1083,6 +1083,7 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm, + uint32_t *ctl_stack_size) + { + struct process_queue_node *pqn; ++ int ret; + + pqn = get_queue_by_qid(pqm, qid); + if (!pqn) { +@@ -1095,9 +1096,14 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm, + return -EOPNOTSUPP; + } + +- pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm, ++ ret = pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm, + pqn->q, mqd_size, + ctl_stack_size); ++ if (ret) { ++ pr_debug("amdkfd: Overflow while computing stack size for queue %d\n", qid); ++ return ret; ++ } ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch b/queue-6.18/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch new file mode 100644 index 0000000000..26ed8a7bc0 --- /dev/null +++ b/queue-6.18/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch @@ -0,0 +1,36 @@ +From 966fd889bded7064b2753c221665dec2919041ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Feb 2026 20:11:03 +0800 +Subject: drm/amdgpu: clear related counter after RAS eeprom reset + +From: Tao Zhou + +[ Upstream commit 3d77ca68eb0b48f88cc891d1b98f109b68e2ffcf ] + +Make eeprom data and its counter consistent. + +Signed-off-by: Tao Zhou +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +index dafa46a9656ca..7d7c65d5e13af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -488,6 +488,9 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) + control->bad_channel_bitmap = 0; + amdgpu_dpm_send_hbm_bad_channel_flag(adev, control->bad_channel_bitmap); + con->update_channel_flag = false; ++ /* there is no record on eeprom now, clear the counter */ ++ if (con->eh_data) ++ con->eh_data->count_saved = 0; + + amdgpu_ras_debugfs_set_ret_size(control); + +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch b/queue-6.18/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch new file mode 100644 index 0000000000..4a2da7de85 --- /dev/null +++ b/queue-6.18/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch @@ -0,0 +1,133 @@ +From ab917201fb4a7a655715a9cf0c75983a5f5aa133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:00:04 +0800 +Subject: drm/amdgpu: drop userq fence driver refs out of fence process() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Prike Liang + +[ Upstream commit dd88d42d9ca0dd7a4ed327dd33f6ead76cedf726 ] + +amdgpu_userq_wait_ioctl() takes extra references on waited-on fence +drivers and stores them in waitq->fence_drv_xa. When a new userq fence is +created, those references are transferred into userq_fence->fence_drv_array +so they can be released when the fence completes. + +However, those inherited references are currently only dropped from +amdgpu_userq_fence_driver_process(). If a fence never reaches that path, +such as it is already signaled when created, so we need to explicitly release +those fences in that case. + +v2: use a list(list_cut_before) for managing the signal userq driver fences.(Christian) + Link: https://patchwork.freedesktop.org/patch/718078/?series=164763&rev=2 +v3: Doesn't cache the userq first unsignaled fence and use the cut before list + head directly.(Christian) + +Cc: Alex Deucher +Signed-off-by: Prike Liang +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 47 +++++++++++++------ + 1 file changed, 33 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +index 29aa3e709a5ce..bfbe6e746864d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +@@ -151,13 +151,22 @@ amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) + amdgpu_userq_fence_driver_put(userq->fence_drv); + } + ++static void ++amdgpu_userq_fence_put_fence_drv_array(struct amdgpu_userq_fence *userq_fence) ++{ ++ unsigned long i; ++ for (i = 0; i < userq_fence->fence_drv_array_count; i++) ++ amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); ++ userq_fence->fence_drv_array_count = 0; ++} ++ + void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv) + { + struct amdgpu_userq_fence *userq_fence, *tmp; ++ LIST_HEAD(to_be_signaled); + struct dma_fence *fence; + unsigned long flags; + u64 rptr; +- int i; + + if (!fence_drv) + return; +@@ -165,21 +174,26 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d + spin_lock_irqsave(&fence_drv->fence_list_lock, flags); + rptr = amdgpu_userq_fence_read(fence_drv); + +- list_for_each_entry_safe(userq_fence, tmp, &fence_drv->fences, link) { +- fence = &userq_fence->base; +- +- if (rptr < fence->seqno) ++ list_for_each_entry(userq_fence, &fence_drv->fences, link) { ++ if (rptr < userq_fence->base.seqno) + break; ++ } + +- dma_fence_signal(fence); +- +- for (i = 0; i < userq_fence->fence_drv_array_count; i++) +- amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); ++ list_cut_before(&to_be_signaled, &fence_drv->fences, ++ &userq_fence->link); ++ spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + +- list_del(&userq_fence->link); ++ list_for_each_entry_safe(userq_fence, tmp, &to_be_signaled, link) { ++ fence = &userq_fence->base; ++ list_del_init(&userq_fence->link); ++ dma_fence_signal(fence); ++ /* Drop fence_drv_array outside fence_list_lock ++ * to avoid the recursion lock. ++ */ ++ amdgpu_userq_fence_put_fence_drv_array(userq_fence); + dma_fence_put(fence); + } +- spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); ++ + } + + void amdgpu_userq_fence_driver_destroy(struct kref *ref) +@@ -242,6 +256,7 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, + struct amdgpu_userq_fence_driver *fence_drv; + struct dma_fence *fence; + unsigned long flags; ++ bool signaled = false; + + fence_drv = userq->fence_drv; + if (!fence_drv) +@@ -289,13 +304,17 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, + + /* Check if hardware has already processed the job */ + spin_lock_irqsave(&fence_drv->fence_list_lock, flags); +- if (!dma_fence_is_signaled(fence)) ++ if (!dma_fence_is_signaled(fence)) { + list_add_tail(&userq_fence->link, &fence_drv->fences); +- else ++ } else { ++ signaled = true; + dma_fence_put(fence); +- ++ } + spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + ++ if (signaled) ++ amdgpu_userq_fence_put_fence_drv_array(userq_fence); ++ + *f = fence; + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-amdgpu_userq_evict.patch b/queue-6.18/drm-amdgpu-fix-amdgpu_userq_evict.patch new file mode 100644 index 0000000000..66063fcbf5 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-amdgpu_userq_evict.patch @@ -0,0 +1,47 @@ +From 10d82ccce1e9d96dbd8b5b43fa8b11a3744f9e1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:27:25 +0100 +Subject: drm/amdgpu: fix amdgpu_userq_evict +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 98dc529a27c57e184ab47453993ba9cfcfcec0ca ] + +Canceling the resume worker synchonized can deadlock because it can in +turn wait for the eviction worker through the userq_mutex. + +Signed-off-by: Christian König +Reviewed-by: Alex Deucher +Reviewed-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index 7e3175f82a20d..6293d5331df52 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -965,13 +965,8 @@ amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, + /* Signal current eviction fence */ + amdgpu_eviction_fence_signal(evf_mgr, ev_fence); + +- if (evf_mgr->fd_closing) { +- cancel_delayed_work_sync(&uq_mgr->resume_work); +- return; +- } +- +- /* Schedule a resume work */ +- schedule_delayed_work(&uq_mgr->resume_work, 0); ++ if (!evf_mgr->fd_closing) ++ schedule_delayed_work(&uq_mgr->resume_work, 0); + } + + int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-cper-ring-header-parsing.patch b/queue-6.18/drm-amdgpu-fix-cper-ring-header-parsing.patch new file mode 100644 index 0000000000..b75834eee1 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-cper-ring-header-parsing.patch @@ -0,0 +1,107 @@ +From 0da301c99fcbfc5269ef96b00e0608c0b897d72d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 17:10:21 +0800 +Subject: drm/amdgpu: fix CPER ring header parsing + +From: Xiang Liu + +[ Upstream commit b8939bd764c9c8bf6488dc0d71d9c718c25d8cfc ] + +amdgpu_cper_ring_get_ent_sz() parses CPER headers directly from the +circular ring buffer to determine the current entry size. When the ring +is full and the write pointer lands near the end of the buffer, the +header can wrap across the ring boundary. + +The existing code treats the 4-byte CPER signature as a C string and +uses strcmp() on in-ring binary data, then reads record_length through a +direct struct pointer cast. Both assumptions are unsafe for wrapped +entries and can read past the end of the ring mapping. + +Fix the parser by comparing the signature as raw bytes and by copying +the header into a local buffer before reading record_length, handling +wraparound explicitly in both cases. This avoids out-of-bounds reads in +amdgpu_cper_ring_get_ent_sz() when the CPER ring is full or the current +entry starts at the tail of the ring. + +Signed-off-by: Xiang Liu +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c | 36 ++++++++++++++++++------ + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +index 425a3e5643608..c5fe670b847c3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +@@ -31,6 +31,8 @@ static const guid_t BOOT = BOOT_TYPE; + static const guid_t CRASHDUMP = AMD_CRASHDUMP; + static const guid_t RUNTIME = AMD_GPU_NONSTANDARD_ERROR; + ++#define CPER_SIGNATURE_SZ (sizeof(((struct cper_hdr *)0)->signature)) ++ + static void __inc_entry_length(struct cper_hdr *hdr, uint32_t size) + { + hdr->record_length += size; +@@ -424,23 +426,40 @@ int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev, + + static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos) + { +- struct cper_hdr *chdr; ++ char signature[CPER_SIGNATURE_SZ]; ++ ++ if ((pos << 2) >= ring->ring_size) ++ return false; + +- chdr = (struct cper_hdr *)&(ring->ring[pos]); +- return strcmp(chdr->signature, "CPER") ? false : true; ++ if ((pos << 2) + CPER_SIGNATURE_SZ <= ring->ring_size) { ++ memcpy(signature, &ring->ring[pos], CPER_SIGNATURE_SZ); ++ } else { ++ u32 chunk = ring->ring_size - (pos << 2); ++ ++ memcpy(signature, &ring->ring[pos], chunk); ++ memcpy(signature + chunk, ring->ring, CPER_SIGNATURE_SZ - chunk); ++ } ++ ++ return !memcmp(signature, "CPER", CPER_SIGNATURE_SZ); + } + + static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) + { +- struct cper_hdr *chdr; ++ struct cper_hdr chdr; + u64 p; + u32 chunk, rec_len = 0; + +- chdr = (struct cper_hdr *)&(ring->ring[pos]); + chunk = ring->ring_size - (pos << 2); + +- if (!strcmp(chdr->signature, "CPER")) { +- rec_len = chdr->record_length; ++ if (amdgpu_cper_is_hdr(ring, pos)) { ++ if (chunk >= sizeof(chdr)) { ++ memcpy(&chdr, &ring->ring[pos], sizeof(chdr)); ++ } else { ++ memcpy(&chdr, &ring->ring[pos], chunk); ++ memcpy((u8 *)&chdr + chunk, ring->ring, sizeof(chdr) - chunk); ++ } ++ ++ rec_len = chdr.record_length; + goto calc; + } + +@@ -449,8 +468,7 @@ static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) + goto calc; + + for (p = pos + 1; p <= ring->buf_mask; p++) { +- chdr = (struct cper_hdr *)&(ring->ring[p]); +- if (!strcmp(chdr->signature, "CPER")) { ++ if (amdgpu_cper_is_hdr(ring, p)) { + rec_len = (p - pos) << 2; + goto calc; + } +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch b/queue-6.18/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch new file mode 100644 index 0000000000..ee16f96b13 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch @@ -0,0 +1,36 @@ +From 5e01f8b80f6fb9c8895369176a5ad03f8f4e4382 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 09:33:17 +0800 +Subject: drm/amdgpu: fix DF NULL pointer issue for soc24 + +From: Likun Gao + +[ Upstream commit 50808826a64b4957b7088c789e539dd0a75a1560 ] + +If DF function not initialized, NULL pointer issue +will happen on soc24. + +Signed-off-by: Likun Gao +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/soc24.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c +index 972b449ab89fa..cc6684f265384 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc24.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc24.c +@@ -489,7 +489,7 @@ static int soc24_common_hw_init(struct amdgpu_ip_block *ip_block) + if (adev->nbio.funcs->remap_hdp_registers) + adev->nbio.funcs->remap_hdp_registers(adev); + +- if (adev->df.funcs->hw_init) ++ if (adev->df.funcs && adev->df.funcs->hw_init) + adev->df.funcs->hw_init(adev); + + /* enable the doorbell aperture */ +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch b/queue-6.18/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch new file mode 100644 index 0000000000..888f17f4d3 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch @@ -0,0 +1,46 @@ +From 1ed9cab6034c31fd0c11926144b78ff6c6a3931e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 18:53:40 +0800 +Subject: drm/amdgpu: fix shift-out-of-bounds when updating umc active mask + +From: Hawking Zhang + +[ Upstream commit 1394a4926f4bcff0dc6ac6deea5beeb2844297f0 ] + +UMC node_inst_num can exceed 32, causing +(1 << node_inst_num) to shift a 32-bit int +out of bounds + +Signed-off-by: Hawking Zhang +Reviewed-by: Likun Gao +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index 54a045a0bda96..91a89bd28e378 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -715,7 +715,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + struct harvest_table *harvest_info; + u16 offset; + int i; +- uint32_t umc_harvest_config = 0; ++ u64 umc_harvest_config = 0; + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset); +@@ -771,7 +771,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + } + } + +- adev->umc.active_mask = ((1 << adev->umc.node_inst_num) - 1) & ++ adev->umc.active_mask = ((1ULL << adev->umc.node_inst_num) - 1ULL) & + ~umc_harvest_config; + } + +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch b/queue-6.18/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch new file mode 100644 index 0000000000..154be2ba94 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch @@ -0,0 +1,166 @@ +From 26126566ade1e42af0ae80573f6d0633cd880ef7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 17:30:57 +0100 +Subject: drm/amdgpu: fix some more bug in amdgpu_gem_va_ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 68bd4f6b8310f309eb63b41e15088690c9cec0a9 ] + +Some illegal combination of input flags were not checked and we need to +take the PDEs into account when returning the fence as well. + +Signed-off-by: Christian König +Acked-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 76 +++++++++++-------------- + 1 file changed, 34 insertions(+), 42 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index 1631a0431ea8e..31f2fb3c07072 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -723,11 +724,10 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + struct dma_fence *fence; + int r = 0; + +- /* Always start from the VM's existing last update fence. */ +- fence = dma_fence_get(vm->last_update); +- ++ /* If the VM is not ready return only a stub. */ + if (!amdgpu_vm_ready(vm)) +- return fence; ++ return dma_fence_get_stub(); ++ + + /* + * First clean up any freed mappings in the VM. +@@ -736,7 +736,7 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + * schedules GPU work. If nothing needs clearing, @fence can remain as + * the original vm->last_update. + */ +- r = amdgpu_vm_clear_freed(adev, vm, &fence); ++ r = amdgpu_vm_clear_freed(adev, vm, &vm->last_update); + if (r) + goto error; + +@@ -753,47 +753,34 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + if (r) + goto error; + +- /* +- * Decide which fence best represents the last update: +- * +- * MAP/REPLACE: +- * - For always-valid mappings, use vm->last_update. +- * - Otherwise, export bo_va->last_pt_update. +- * +- * UNMAP/CLEAR: +- * Keep the fence returned by amdgpu_vm_clear_freed(). If no work was +- * needed, it can remain as vm->last_pt_update. +- * +- * The VM and BO update fences are always initialized to a valid value. +- * vm->last_update and bo_va->last_pt_update always start as valid fences. +- * and are never expected to be NULL. +- */ +- switch (operation) { +- case AMDGPU_VA_OP_MAP: +- case AMDGPU_VA_OP_REPLACE: ++ if ((operation == AMDGPU_VA_OP_MAP || ++ operation == AMDGPU_VA_OP_REPLACE) && ++ !amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) { ++ + /* +- * For MAP/REPLACE, return the page table update fence for the +- * mapping we just modified. bo_va is expected to be valid here. ++ * For MAP/REPLACE of non per-VM BOs we need to sync to both the ++ * bo_va->last_pt_update and vm->last_update or otherwise we ++ * potentially miss the PDE updates. + */ +- dma_fence_put(fence); +- +- if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) +- fence = dma_fence_get(vm->last_update); +- else +- fence = dma_fence_get(bo_va->last_pt_update); +- break; +- case AMDGPU_VA_OP_UNMAP: +- case AMDGPU_VA_OP_CLEAR: +- default: +- /* keep @fence as returned by amdgpu_vm_clear_freed() */ +- break; ++ fence = dma_fence_unwrap_merge(vm->last_update, ++ bo_va->last_pt_update); ++ if (!fence) { ++ /* As fallback in OOM situations */ ++ dma_fence_wait(vm->last_update, false); ++ dma_fence_wait(bo_va->last_pt_update, false); ++ fence = dma_fence_get_stub(); ++ } ++ } else { ++ fence = dma_fence_get(vm->last_update); + } + ++ return fence; ++ + error: + if (r && r != -ERESTARTSYS) + DRM_ERROR("Couldn't update BO_VA (%d)\n", r); + +- return fence; ++ return dma_fence_get(vm->last_update); + } + + int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, +@@ -814,7 +801,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + struct amdgpu_bo_va *bo_va; + struct drm_syncobj *timeline_syncobj = NULL; + struct dma_fence_chain *timeline_chain = NULL; +- struct dma_fence *fence; + struct drm_exec exec; + uint64_t vm_size; + int r = 0; +@@ -866,6 +852,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + return -EINVAL; + } + ++ if (args->flags & AMDGPU_VM_DELAY_UPDATE && ++ args->vm_timeline_syncobj_out) ++ return -EINVAL; ++ + if ((args->operation != AMDGPU_VA_OP_CLEAR) && + !(args->flags & AMDGPU_VM_PAGE_PRT)) { + gobj = drm_gem_object_lookup(filp, args->handle); +@@ -955,11 +945,13 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + * that represents the last relevant update for this mapping. This + * fence can then be exported to the user-visible VM timeline. + */ +- if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !adev->debug_vm) { ++ if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && ++ (!adev->debug_vm || timeline_syncobj)) { ++ struct dma_fence *fence; ++ + fence = amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, + args->operation); +- +- if (timeline_syncobj && fence) { ++ if (timeline_syncobj) { + if (!args->vm_timeline_point) { + /* Replace the existing fence when no point is given. */ + drm_syncobj_replace_fence(timeline_syncobj, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch b/queue-6.18/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch new file mode 100644 index 0000000000..411b16d325 --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch @@ -0,0 +1,56 @@ +From dbd13eaf978c998bb3c57fc3167e0b501e674014 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:47:11 +0800 +Subject: drm/amdgpu: fix syncobj leak for amdgpu_gem_va_ioctl() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Prike Liang + +[ Upstream commit a0f0b6d31a53a7607ed44f7623faafc628333258 ] + +It requires freeing the syncobj and chain +alloction resource. + +Signed-off-by: Prike Liang +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index 31f2fb3c07072..878bbf7f336fa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -107,6 +107,7 @@ amdgpu_gem_update_timeline_node(struct drm_file *filp, + *chain = dma_fence_chain_alloc(); + if (!*chain) { + drm_syncobj_put(*syncobj); ++ *syncobj = NULL; + return -ENOMEM; + } + +@@ -962,6 +963,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + timeline_chain, + fence, + args->vm_timeline_point); ++ timeline_chain = NULL; + } + } + dma_fence_put(fence); +@@ -969,6 +971,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + } + + error: ++ dma_fence_chain_free(timeline_chain); ++ if (timeline_syncobj) ++ drm_syncobj_put(timeline_syncobj); + drm_exec_fini(&exec); + error_put_gobj: + drm_gem_object_put(gobj); +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch b/queue-6.18/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch new file mode 100644 index 0000000000..c00f36bc58 --- /dev/null +++ b/queue-6.18/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch @@ -0,0 +1,95 @@ +From 9e67dd0ba3b238d2ba881007ace45aec907fa656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:28:59 +0800 +Subject: drm/amdgpu: guard atom_context in devcoredump VBIOS dump + +From: Jesse Zhang + +[ Upstream commit 557fa5a453c9ccb49a22f30a7ad0545573d434b7 ] + +During GPU reset coredump generation, amdgpu_devcoredump_fw_info() unconditionally +dereferences adev->mode_info.atom_context to print VBIOS fields. On reset/teardown +paths this pointer can be NULL, causing a kernel page fault from the deferred +coredump workqueue. + +Fix by checking ctx before printing VBIOS fields: + +if ctx is valid, print full VBIOS information as before; +This prevents NULL-dereference crashes while preserving coredump output. + +Observed page fault log: +[ 667.933329] RIP: 0010:amdgpu_devcoredump_format+0x780/0xc00 [amdgpu] +[ 667.941517] amdgpu 0002:01:00.0: Dumping IP State +[ 667.949660] Code: 8d 57 74 48 c7 c6 01 65 9f c2 48 8d 7d 98 e8 97 96 7a ff 49 8d 97 b4 00 00 00 48 c7 c6 18 65 9f c2 48 8d 7d 98 e8 80 96 7a ff <41> 8b 97 f4 00 00 00 48 c7 c6 2f 65 9f c2 48 8d 7d 98 e8 69 96 7a +[ 667.949666] RSP: 0018:ffffc9002302bd50 EFLAGS: 00010246 +[ 667.949673] RAX: 0000000000000000 RBX: ffff888110600000 RCX: 0000000000000000 +[ 667.949676] RDX: 000000000000a9b5 RSI: 0000000000000405 RDI: 000000000000a999 +[ 667.949680] RBP: ffffc9002302be00 R08: ffffffffc09c3084 R09: ffffffffc09c3085 +[ 667.949684] R10: 0000000000000000 R11: 0000000000000004 R12: 00000000000048e0 +[ 667.993908] amdgpu 0002:01:00.0: Dumping IP State Completed +[ 667.994229] R13: 0000000000000025 R14: 000000000000000c R15: 0000000000000000 +[ 667.994233] FS: 0000000000000000(0000) GS:ffff88c44c2c9000(0000) knlGS:0000000000000000 +[ 668.000076] amdgpu 0002:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.008025] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 668.008030] CR2: 00000000000000f4 CR3: 000000011195f001 CR4: 0000000000770ef0 +[ 668.008035] PKRU: 55555554 +[ 668.008040] Call Trace: +[ 668.008045] +[ 668.016010] amdgpu 0002:01:00.0: [drm] Check your /sys/class/drm/card16/device/devcoredump/data +[ 668.023967] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 668.023988] ? __pfx___drm_printfn_coredump+0x10/0x10 [drm] +[ 668.031950] amdgpu 0003:01:00.0: Dumping IP State +[ 668.038159] ? __pfx___drm_puts_coredump+0x10/0x10 [drm] +[ 668.083017] amdgpu 0003:01:00.0: Dumping IP State Completed +[ 668.083824] amdgpu_devcoredump_deferred_work+0x26/0xc0 [amdgpu] +[ 668.086163] amdgpu 0003:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.095863] process_scheduled_works+0xa6/0x420 +[ 668.095880] worker_thread+0x12a/0x270 +[ 668.101223] amdgpu 0003:01:00.0: [drm] Check your /sys/class/drm/card24/device/devcoredump/data +[ 668.107441] kthread+0x10d/0x230 +[ 668.107451] ? __pfx_worker_thread+0x10/0x10 +[ 668.107458] ? __pfx_kthread+0x10/0x10 +[ 668.112709] amdgpu 0000:01:00.0: ring vcn_unified_1 timeout, signaled seq=9, emitted seq=10 +[ 668.118630] ret_from_fork+0x17c/0x1f0 +[ 668.118640] ? __pfx_kthread+0x10/0x10 +[ 668.118647] ret_from_fork_asm+0x1a/0x30 + +Reviewed-by: Lijo Lazar +Suggested-by: Lijo Lazar +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +index 8a026bc9ea44f..f2000e281a5e0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +@@ -187,12 +187,16 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev, + drm_printf(p, "VPE feature version: %u, fw version: 0x%08x\n", + adev->vpe.feature_version, adev->vpe.fw_version); + +- drm_printf(p, "\nVBIOS Information\n"); +- drm_printf(p, "vbios name : %s\n", ctx->name); +- drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); +- drm_printf(p, "vbios version : %d\n", ctx->version); +- drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); +- drm_printf(p, "vbios date : %s\n", ctx->date); ++ if (adev->bios) { ++ drm_printf(p, "\nVBIOS Information\n"); ++ drm_printf(p, "vbios name : %s\n", ctx->name); ++ drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); ++ drm_printf(p, "vbios version : %d\n", ctx->version); ++ drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); ++ drm_printf(p, "vbios date : %s\n", ctx->date); ++ }else { ++ drm_printf(p, "\nVBIOS Information: NA\n"); ++ } + } + + static ssize_t +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch b/queue-6.18/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch new file mode 100644 index 0000000000..19686dc0c6 --- /dev/null +++ b/queue-6.18/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch @@ -0,0 +1,64 @@ +From c8df74d009008f771639fd40d2f1b1c5967611a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 12:41:22 +0530 +Subject: drm/amdgpu/userq: fix dma_fence refcount underflow in userq path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 7a14a4e9b3fda05b907d0445a3be9e7c0e887f4e ] + +An extra dma_fence_put() can drop the last reference to a fence while it is +still attached to a dma_resv object. This frees the fence prematurely via +dma_fence_release() while other users still hold the pointer. + +Later accesses through dma_resv iteration may then operate on the freed +fence object, leading to refcount underflow warnings and potential hangs +when walking reservation fences. + +Fix this by correcting the fence lifetime so the dma_resv object retains a +valid reference until it is done with the fence.i + +[ 31.133803] refcount_t: underflow; use-after-free. +[ 31.133805] WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x58/0x90, CPU#18: kworker/u96:1/188 + +Signed-off-by: Sunil Khatri +Reviewed-by: Tvrtko Ursulin +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +index 73e1827816a0c..29aa3e709a5ce 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +@@ -940,12 +940,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, + * be good for now + */ + r = dma_fence_wait(fences[i], true); +- if (r) { +- dma_fence_put(fences[i]); ++ if (r) + goto free_fences; +- } + +- dma_fence_put(fences[i]); + continue; + } + +@@ -967,7 +964,6 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, + fence_info[cnt].va = fence_drv->va; + fence_info[cnt].value = fences[i]->seqno; + +- dma_fence_put(fences[i]); + /* Increment the actual userq fence count */ + cnt++; + } +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-6.18/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..893f38b553 --- /dev/null +++ b/queue-6.18/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 5775ed9420956a113107a132d52789ed6b7f04c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 2f6a96af7fb12..be19c7c2f2724 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1744,6 +1744,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch b/queue-6.18/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch new file mode 100644 index 0000000000..5fab684a9e --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch @@ -0,0 +1,64 @@ +From ac3dcaea2ca9f94810cc1e2a4e9632d60c324761 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:16:16 +0800 +Subject: drm/amdgpu/vcn4.0.3: gate per-queue reset by PSP SOS program version + +From: Jesse Zhang + +[ Upstream commit 16df395a55c635649dd3cf41d61bd685d3fd7a98 ] + +Add a PSP SOS firmware compatibility check before enabling VCN per-queue +reset on vcn_v4_0_3. + +Per review, program check is sufficient: when PSP SOS program is 0x01, +require fw version >= 0x0036015f; otherwise allow per-queue reset. + +Reviewed-by: Lijo Lazar +Suggested-by: Lijo Lazar +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index 88d1139e931e2..a691628a3e827 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -134,6 +134,21 @@ static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) + return 0; + } + ++static bool vcn_v4_0_3_is_psp_fw_reset_supported(struct amdgpu_device *adev) ++{ ++ uint32_t fw_ver = adev->psp.sos.fw_version; ++ uint32_t pgm = (fw_ver >> 8) & 0xFF; ++ ++ /* ++ * FWDEV-159155: PSP SOS FW must be >= 0x0036015f for program 0x01 ++ * before enabling VCN per-queue reset. ++ */ ++ if (pgm == 1) ++ return fw_ver >= 0x0036015f; ++ ++ return true; ++} ++ + static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; +@@ -141,7 +156,9 @@ static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + +- if (amdgpu_dpm_reset_vcn_is_supported(adev) && !amdgpu_sriov_vf(adev)) ++ if (amdgpu_dpm_reset_vcn_is_supported(adev) && ++ vcn_v4_0_3_is_psp_fw_reset_supported(adev) && ++ !amdgpu_sriov_vf(adev)) + adev->vcn.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch b/queue-6.18/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch new file mode 100644 index 0000000000..6fd558b397 --- /dev/null +++ b/queue-6.18/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch @@ -0,0 +1,68 @@ +From bb398162d6d4a6ba74d35cd5d55f907d728df32f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:57:53 +0100 +Subject: drm/bridge: waveshare-dsi: Register and attach our DSI device at + probe + +From: Marek Vasut + +[ Upstream commit b8eb97ead862de7a321dd55a901542a372f8f1cd ] + +In order to avoid any probe ordering issue, the best practice is to move +the secondary MIPI-DSI device registration and attachment to the +MIPI-DSI host at probe time. + +Besides solving the probe ordering problems, this makes the bridge work +with R-Car DU. The R-Car DU will attempt to locate the DSI host bridge in +its own rcar_du_probe()->rcar_du_modeset_init()->rcar_du_encoder_init() +by calling of_drm_find_bridge() which calls of_drm_find_and_get_bridge() +and iterates over bridge_list to locate the DSI host bridge. + +However, unless the WS driver calls mipi_dsi_attach() in probe(), the +DSI host bridge .attach callback rcar_mipi_dsi_host_attach() is not +called and the DSI host bridge is not added into bridge_list. Therefore +the of_drm_find_and_get_bridge() called from du_probe() will never find +the DSI host bridge and probe will indefinitelly fail with -EPROBE_DEFER. + +The circular dependency here is, that if rcar_du_encoder_init() would +manage to find the DSI host bridge, it would call the WS driver .attach +callback ws_bridge_bridge_attach(), but this is too late and can never +happen. This change avoids the circular dependency. + +Reviewed-by: Luca Ceresoli +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260206125801.78705-1-marek.vasut+renesas@mailbox.org +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/waveshare-dsi.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c +index 43f4e7412d722..9254446f54958 100644 +--- a/drivers/gpu/drm/bridge/waveshare-dsi.c ++++ b/drivers/gpu/drm/bridge/waveshare-dsi.c +@@ -80,11 +80,6 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) + { + struct ws_bridge *ws = bridge_to_ws_bridge(bridge); +- int ret; +- +- ret = ws_bridge_attach_dsi(ws); +- if (ret) +- return ret; + + return drm_bridge_attach(encoder, ws->next_bridge, + &ws->bridge, flags); +@@ -179,7 +174,7 @@ static int ws_bridge_probe(struct i2c_client *i2c) + ws->bridge.of_node = dev->of_node; + devm_drm_bridge_add(dev, &ws->bridge); + +- return 0; ++ return ws_bridge_attach_dsi(ws); + } + + static const struct of_device_id ws_bridge_of_ids[] = { +-- +2.53.0 + diff --git a/queue-6.18/drm-gem-dma-set-vm_dontdump-for-mmap.patch b/queue-6.18/drm-gem-dma-set-vm_dontdump-for-mmap.patch new file mode 100644 index 0000000000..0725258764 --- /dev/null +++ b/queue-6.18/drm-gem-dma-set-vm_dontdump-for-mmap.patch @@ -0,0 +1,49 @@ +From 76c7e91111e01a6c2ed78c2ae7cceac466c49f34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 12:00:32 +0800 +Subject: drm/gem-dma: set VM_DONTDUMP for mmap + +From: Chen-Yu Tsai + +[ Upstream commit e3eb0e70815cc02ea15298818e37d8b0a0930ab1 ] + +When the mmap function was converted from a file op to a GEM object +function in commit f5ca8eb6f9bd ("drm/cma-helper: Implement mmap as GEM +CMA object functions") some VM flags were not lifted from drm_gem_mmap(): + + - VM_IO + - VM_DONTEXPAND + - VM_DONTDUMP + +VM_DONTEXPAND was added back in commit 59f39bfa6553 ("drm/cma-helper: +Set VM_DONTEXPAND for mmap"). VM_IO doesn't make sense since these are +memory buffers, while "IO tells people not to look at these pages +(accesses can have side effects)". + +Add back VM_DONTDUMP. This matches the behavior of most other GEM +implementations. + +Reviewed-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260317040034.617585-1-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gem_dma_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c +index 4f0320df858f8..475ed7f3a1469 100644 +--- a/drivers/gpu/drm/drm_gem_dma_helper.c ++++ b/drivers/gpu/drm/drm_gem_dma_helper.c +@@ -530,7 +530,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct * + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); +- vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); ++ vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP); + + if (dma_obj->map_noncoherent) { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); +-- +2.53.0 + diff --git a/queue-6.18/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch b/queue-6.18/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch new file mode 100644 index 0000000000..a465942234 --- /dev/null +++ b/queue-6.18/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch @@ -0,0 +1,150 @@ +From d2ba8fca56b0a9218210d5689a5d4f5fe9bc0a84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 16:33:34 +0900 +Subject: drm: gpu: msm: forbid mem reclaim from reset + +From: Sergey Senozhatsky + +[ Upstream commit 4625fe5bbdaccd45be274c30ff0a42e30d4e38cf ] + +We sometimes get into a situtation where GPU hangcheck fails to +recover GPU: + +[..] +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): hangcheck detected gpu lockup rb 0! +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): completed fence: 7840161 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): submitted fence: 7840162 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): hangcheck detected gpu lockup rb 0! +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): completed fence: 7840162 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): submitted fence: 7840163 +[..] + +The problem is that msm_job worker is blocked on gpu->lock + +INFO: task ring0:155 blocked for more than 122 seconds. +Not tainted 6.6.99-08727-gaac38b365d2c #1 +task:ring0 state:D stack:0 pid:155 ppid:2 flags:0x00000008 +Call trace: +__switch_to+0x108/0x208 +schedule+0x544/0x11f0 +schedule_preempt_disabled+0x30/0x50 +__mutex_lock_common+0x410/0x850 +__mutex_lock_slowpath+0x28/0x40 +mutex_lock+0x5c/0x90 +msm_job_run+0x9c/0x140 +drm_sched_main+0x514/0x938 +kthread+0x114/0x138 +ret_from_fork+0x10/0x20 + +which is owned by recover worker, which is waiting for DMA fences +from a memory reclaim path, under the very same gpu->lock + +INFO: task ring0:155 is blocked on a mutex likely owned by task gpu-worker:154. +task:gpu-worker state:D stack:0 pid:154 ppid:2 flags:0x00000008 +Call trace: +__switch_to+0x108/0x208 +schedule+0x544/0x11f0 +schedule_timeout+0x1f8/0x770 +dma_fence_default_wait+0x108/0x218 +dma_fence_wait_timeout+0x6c/0x1c0 +dma_resv_wait_timeout+0xe4/0x118 +active_purge+0x34/0x98 +drm_gem_lru_scan+0x1d0/0x388 +msm_gem_shrinker_scan+0x1cc/0x2e8 +shrink_slab+0x228/0x478 +shrink_node+0x380/0x730 +try_to_free_pages+0x204/0x510 +__alloc_pages_direct_reclaim+0x90/0x158 +__alloc_pages_slowpath+0x1d4/0x4a0 +__alloc_pages+0x9f0/0xc88 +vm_area_alloc_pages+0x17c/0x260 +__vmalloc_node_range+0x1c0/0x420 +kvmalloc_node+0xe8/0x108 +msm_gpu_crashstate_capture+0x1e4/0x280 +recover_worker+0x1c0/0x638 +kthread_worker_fn+0x150/0x2d8 +kthread+0x114/0x138 + +So no one can make any further progress. + +Forbid recover/fault worker to enter memory reclaim (under +gpu->lock) to address this deadlock scenario. + +Cc: Tomasz Figa +Signed-off-by: Sergey Senozhatsky +Reviewed-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/700978/ +Message-ID: <20260127073341.2862078-1-senozhatsky@chromium.org> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gpu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c +index a4377ee84c723..13e64ed20336d 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + /* + * Power Management: +@@ -470,6 +471,7 @@ static void recover_worker(struct kthread_work *work) + struct msm_gem_submit *submit; + struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); + char *comm = NULL, *cmd = NULL; ++ unsigned int noreclaim_flag; + struct task_struct *task; + int i; + +@@ -507,6 +509,8 @@ static void recover_worker(struct kthread_work *work) + msm_gem_vm_unusable(submit->vm); + } + ++ noreclaim_flag = memalloc_noreclaim_save(); ++ + get_comm_cmdline(submit, &comm, &cmd); + + if (comm && cmd) { +@@ -525,6 +529,8 @@ static void recover_worker(struct kthread_work *work) + pm_runtime_get_sync(&gpu->pdev->dev); + msm_gpu_crashstate_capture(gpu, submit, NULL, comm, cmd); + ++ memalloc_noreclaim_restore(noreclaim_flag); ++ + kfree(cmd); + kfree(comm); + +@@ -587,6 +593,7 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + struct msm_gem_submit *submit; + struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); + char *comm = NULL, *cmd = NULL; ++ unsigned int noreclaim_flag; + + mutex_lock(&gpu->lock); + +@@ -594,6 +601,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + if (submit && submit->fault_dumped) + goto resume_smmu; + ++ noreclaim_flag = memalloc_noreclaim_save(); ++ + if (submit) { + get_comm_cmdline(submit, &comm, &cmd); + +@@ -609,6 +618,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + msm_gpu_crashstate_capture(gpu, submit, fault_info, comm, cmd); + pm_runtime_put_sync(&gpu->pdev->dev); + ++ memalloc_noreclaim_restore(noreclaim_flag); ++ + kfree(cmd); + kfree(comm); + +-- +2.53.0 + diff --git a/queue-6.18/drm-imx-parallel-display-add-drm_display_helper-for-.patch b/queue-6.18/drm-imx-parallel-display-add-drm_display_helper-for-.patch new file mode 100644 index 0000000000..4a9a570457 --- /dev/null +++ b/queue-6.18/drm-imx-parallel-display-add-drm_display_helper-for-.patch @@ -0,0 +1,45 @@ +From 348dac5f1ca0710dbfd79cee59ae46dbc1572dc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:26:07 +0100 +Subject: drm/imx: parallel-display: add DRM_DISPLAY_HELPER for + DRM_IMX_PARALLEL_DISPLAY + +From: Martin Kepplinger-Novakovic + +[ Upstream commit 02df94d98ff837074788ce921edf67707dbad404 ] + +When I build for an old imx53 platform I see the same as the test robot +saw before: + +arm-buildroot-linux-gnueabihf-ld: drivers/gpu/drm/imx/ipuv3/parallel-display.o: in function `imx_pd_bind': +parallel-display.c:(.text+0xb8): undefined reference to `drm_bridge_connector_init' + +Selecting DRM_DISPLAY_HELPER for DRM_IMX_PARALLEL_DISPLAY fixes the build. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202512241721.jZgcwRfr-lkp@intel.com/ + +Signed-off-by: Martin Kepplinger-Novakovic +Reviewed-by: Philipp Zabel +Signed-off-by: Philipp Zabel +Link: https://patch.msgid.link/20260121102607.4087362-1-martin.kepplinger-novakovic@ginzinger.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/ipuv3/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig +index acaf250890019..b2240998df4f1 100644 +--- a/drivers/gpu/drm/imx/ipuv3/Kconfig ++++ b/drivers/gpu/drm/imx/ipuv3/Kconfig +@@ -15,6 +15,7 @@ config DRM_IMX_PARALLEL_DISPLAY + depends on DRM_IMX + select DRM_BRIDGE + select DRM_BRIDGE_CONNECTOR ++ select DRM_DISPLAY_HELPER + select DRM_IMX_LEGACY_BRIDGE + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS +-- +2.53.0 + diff --git a/queue-6.18/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-6.18/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..7b644f09a1 --- /dev/null +++ b/queue-6.18/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From 2cc8164fc71731c0808f412f3a2eb92c9be87ecc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index acee2227275b7..b7f7f8b6f5141 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -672,6 +672,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -724,6 +739,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -769,30 +786,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch b/queue-6.18/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch new file mode 100644 index 0000000000..2f2e552964 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch @@ -0,0 +1,60 @@ +From 6a3ae0a189d1ea2008510539df4dea15b34b05ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:17:00 +0100 +Subject: drm/msm/dpu: fix vblank IRQ registration before atomic_mode_set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit 961c900628fef77ad07b4bc4c868e47b9a1269c7 ] + +dpu_encoder_toggle_vblank_for_crtc() can call control_vblank_irq() +at any time in response to a userspace vblank request, independently +of the atomic commit sequence. If this happens before the encoder's +first atomic_mode_set(), irq[INTR_IDX_RDPTR] is still zero. + +Passing irq_idx=0 to dpu_core_irq_register_callback() is treated as +invalid, and DPU_IRQ_REG(0) and DPU_IRQ_BIT(0) produce misleading +values of 134217727 and 31 respectively due to unsigned wraparound +in the (irq_idx - 1) macros, resulting in the confusing error: + + [dpu error]invalid IRQ=[134217727, 31] + +Since irq[INTR_IDX_RDPTR] will be properly populated by +atomic_mode_set() and registered by irq_enable() as part of the +normal modeset sequence, silently skip the vblank IRQ registration +when the index has not yet been initialized. This matches the +existing pattern of the master encoder check above it. + +Signed-off-by: Cédric Bellegarde +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/712752/ +Link: https://lore.kernel.org/r/20260318171700.394945-1-cedric.bellegarde@adishatz.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 93db1484f6069..45079ee59cf67 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -257,6 +257,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + ++ /* IRQ not yet initialized */ ++ if (!phys_enc->irq[INTR_IDX_RDPTR]) { ++ ret = -EINVAL; ++ goto end; ++ } ++ + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.18/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch b/queue-6.18/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch new file mode 100644 index 0000000000..f29e61c8c8 --- /dev/null +++ b/queue-6.18/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch @@ -0,0 +1,46 @@ +From 209b7f8d370dd8f7b4da5a1558c5a58ed5d6a1b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 11:29:04 +0800 +Subject: drm/panel-edp: Add AUO B116XAT04.1 (HW: 1A) + +From: Terry Hsiao + +[ Upstream commit 2cb217301e0df17f7107a1b0941b28d4053eae8b ] + +Add support for the AUO - B116XAT04.1 (HW: 1A) panel. +This panel is used on MT8186 Chromebooks + +The raw EDID: +00 ff ff ff ff ff ff 00 06 af ba 89 00 00 00 00 +0c 23 01 04 95 1a 0e 78 02 9e a5 96 59 58 96 28 +1b 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 ce 1d 56 ea 50 00 1a 30 30 20 +46 00 00 90 10 00 00 18 df 13 56 ea 50 00 1a 30 +30 20 46 00 00 90 10 00 00 18 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 +00 10 48 ff 0f 3c 7d 0c 0a 2a 7d 20 20 20 00 21 + +Signed-off-by: Terry Hsiao +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260122032904.3933-1-terry_hsiao@compal.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index d1e68c464e308..d6d76d001e1af 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1914,6 +1914,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), ++ EDP_PANEL_ENTRY('A', 'U', 'O', 0x89ba, &delay_200_500_e50, "B116XAT04.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8bba, &delay_200_500_e50, "B140UAN08.5"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xa199, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"), +-- +2.53.0 + diff --git a/queue-6.18/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch b/queue-6.18/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch new file mode 100644 index 0000000000..28a9e9cf91 --- /dev/null +++ b/queue-6.18/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch @@ -0,0 +1,56 @@ +From 46db3d17b946e238ccfff0cb16bbe1ec0789ad2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 11:04:56 +0800 +Subject: drm/panel-edp: Add CMN N116BCL-EAK (C2) + +From: Cong Yang + +[ Upstream commit 3d65e4c276b32c03450261d114e495fda03c8e97 ] + +Add support for the CMN N116BCL-EAK (C2) panel, pleace the EDID here for +subsequent reference. + +edid-decode (hex): + +00 ff ff ff ff ff ff 00 0d ae 7a 11 00 00 00 00 +08 22 01 04 95 1a 0e 78 03 46 a5 9c 5b 53 8b 24 +1d 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 e6 1e 56 e2 50 00 3c 30 30 20 +a6 00 00 90 10 00 00 1a 00 00 00 fd 00 28 3c 32 +32 08 01 0a 20 20 20 20 20 20 00 00 00 fe 00 43 +4d 4e 0a 20 20 20 20 20 20 20 20 20 00 00 00 fe +00 4e 31 31 36 42 43 4c 2d 45 41 4b 0a 20 01 80 + +70 20 79 02 00 25 01 09 fc 34 01 fc 34 01 28 3c +80 81 00 10 72 1a 00 00 03 01 28 3c 00 00 00 00 +00 00 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 90 + +Signed-off-by: Cong Yang +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260130030456.2080748-1-yangcong5@huaqin.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index d6d76d001e1af..2607288f2d7ed 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -2010,6 +2010,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), ++ EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x124c, &delay_200_500_e80_d50, "N122JCA-ENK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), +-- +2.53.0 + diff --git a/queue-6.18/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch b/queue-6.18/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch new file mode 100644 index 0000000000..143f4bccf5 --- /dev/null +++ b/queue-6.18/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch @@ -0,0 +1,44 @@ +From 6a1fda93fc82c7686b8302ccca85bd0b5d29c5ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:49:25 +0800 +Subject: drm/prime: Limit scatter list size with dedicated DMA device + +From: Chen-Yu Tsai + +[ Upstream commit 864279920b2b2c1dd491eba0d0c64764c0c03d9f ] + +If a dedicated DMA device is specified for the DRM device, then the +scatter list size limit should pertain to the DMA device. + +Use the dedicated DMA device, if given, to limit the scatter list size. +This only applies to drivers that have called drm_dev_set_dma_dev() and +are using drm_prime_pages_to_sg() either directly or through the SHMEM +helpers. At the time of this writing, the former case only includes the +Rockchip DRM driver, while the latter case includes the gud, udl, and +the tiny appletbdrm and gm12u320 drivers. + +Reviewed-by: Thomas Zimmermann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260311094929.3393338-2-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_prime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 43a10b4af43ac..0638bf4429c01 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -858,7 +858,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, + return ERR_PTR(-ENOMEM); + + if (dev) +- max_segment = dma_max_mapping_size(dev->dev); ++ max_segment = dma_max_mapping_size(drm_dev_dma_dev(dev)); + if (max_segment == 0) + max_segment = UINT_MAX; + err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, +-- +2.53.0 + diff --git a/queue-6.18/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch b/queue-6.18/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch new file mode 100644 index 0000000000..563028a3b7 --- /dev/null +++ b/queue-6.18/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch @@ -0,0 +1,98 @@ +From ae943bed46609e53024a762aec08755998dfacdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:18:55 +0100 +Subject: drm/ttm: Avoid invoking the OOM killer when reading back swapped + content +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +[ Upstream commit c6135f67aa37a4a744869f726d706bda091e6dfa ] + +In situations where the system is very short on RAM, the shmem +readback from swap-space may invoke the OOM killer. + +However, since this might be a recoverable situation where the caller +is indicating this by setting +struct ttm_operation_ctx::gfp_retry_mayfail to true, adjust the gfp +value used by the allocation accordingly. + +Signed-off-by: Thomas Hellström +Reviewed-by: Maarten Lankhorst +Acked-by: Christian König +Link: https://patch.msgid.link/20260317141856.237876-3-thomas.hellstrom@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/ttm/ttm_backup.c | 6 ++++-- + drivers/gpu/drm/ttm/ttm_pool.c | 5 ++++- + include/drm/ttm/ttm_backup.h | 2 +- + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c +index 32530c75f0385..229f5e7bb408f 100644 +--- a/drivers/gpu/drm/ttm/ttm_backup.c ++++ b/drivers/gpu/drm/ttm/ttm_backup.c +@@ -44,18 +44,20 @@ void ttm_backup_drop(struct file *backup, pgoff_t handle) + * @dst: The struct page to copy into. + * @handle: The handle returned when the page was backed up. + * @intr: Try to perform waits interruptible or at least killable. ++ * @additional_gfp: GFP mask to add to the default GFP mask if any. + * + * Return: 0 on success, Negative error code on failure, notably + * -EINTR if @intr was set to true and a signal is pending. + */ + int ttm_backup_copy_page(struct file *backup, struct page *dst, +- pgoff_t handle, bool intr) ++ pgoff_t handle, bool intr, gfp_t additional_gfp) + { + struct address_space *mapping = backup->f_mapping; + struct folio *from_folio; + pgoff_t idx = ttm_backup_handle_to_shmem_idx(handle); + +- from_folio = shmem_read_folio(mapping, idx); ++ from_folio = shmem_read_folio_gfp(mapping, idx, mapping_gfp_mask(mapping) ++ | additional_gfp); + if (IS_ERR(from_folio)) + return PTR_ERR(from_folio); + +diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c +index baf27c70a4193..ad2ff9181eab2 100644 +--- a/drivers/gpu/drm/ttm/ttm_pool.c ++++ b/drivers/gpu/drm/ttm/ttm_pool.c +@@ -521,6 +521,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, + p = first_page[i]; + if (ttm_backup_page_ptr_is_handle(p)) { + unsigned long handle = ttm_backup_page_ptr_to_handle(p); ++ gfp_t additional_gfp = ctx->gfp_retry_mayfail ? ++ __GFP_RETRY_MAYFAIL | __GFP_NOWARN : 0; + + if (IS_ENABLED(CONFIG_FAULT_INJECTION) && ctx->interruptible && + should_fail(&backup_fault_inject, 1)) { +@@ -534,7 +536,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, + } + + ret = ttm_backup_copy_page(backup, restore->alloced_page + i, +- handle, ctx->interruptible); ++ handle, ctx->interruptible, ++ additional_gfp); + if (ret) + break; + +diff --git a/include/drm/ttm/ttm_backup.h b/include/drm/ttm/ttm_backup.h +index c33cba111171f..29b9c855af779 100644 +--- a/include/drm/ttm/ttm_backup.h ++++ b/include/drm/ttm/ttm_backup.h +@@ -56,7 +56,7 @@ ttm_backup_page_ptr_to_handle(const struct page *page) + void ttm_backup_drop(struct file *backup, pgoff_t handle); + + int ttm_backup_copy_page(struct file *backup, struct page *dst, +- pgoff_t handle, bool intr); ++ pgoff_t handle, bool intr, gfp_t additional_gfp); + + s64 + ttm_backup_backup_page(struct file *backup, struct page *page, +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch b/queue-6.18/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch new file mode 100644 index 0000000000..0f85504477 --- /dev/null +++ b/queue-6.18/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch @@ -0,0 +1,135 @@ +From 8d85b654437242926209b05dd8c40c20ce872672 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:23:15 +0530 +Subject: drm/xe/guc: Add Wa_14025883347 for GuC DMA failure on reset + +From: Sk Anirban + +[ Upstream commit c57db41b8d2cd410e7219729f446aa17965485ad ] + +Prevent GuC firmware DMA failures during GuC-only reset by disabling +idle flow and verifying SRAM handling completion. Without this, reset +can be issued while SRAM handler is copying WOPCM to SRAM, +causing GuC HW to get stuck. + +v2: Modify error message (Badal) + Rename reg bit name (Daniele) + Update WA skip condition (Daniele) + Update SRAM handling logic (Daniele) +v3: Reorder WA call (Badal) + Wait for GuC ready status (Daniele) +v4: Update reg name (Badal) + Add comment (Daniele) + Add extended graphics version (Daniele) + Modify rules + +Signed-off-by: Sk Anirban +Reviewed-by: Badal Nilawar +Acked-by: Matt Roper +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260202105313.3338094-4-sk.anirban@intel.com +Signed-off-by: Matt Roper +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/regs/xe_guc_regs.h | 8 ++++++ + drivers/gpu/drm/xe/xe_guc.c | 38 +++++++++++++++++++++++++++ + drivers/gpu/drm/xe/xe_wa_oob.rules | 3 +++ + 3 files changed, 49 insertions(+) + +diff --git a/drivers/gpu/drm/xe/regs/xe_guc_regs.h b/drivers/gpu/drm/xe/regs/xe_guc_regs.h +index 87984713dd126..5faac8316b66c 100644 +--- a/drivers/gpu/drm/xe/regs/xe_guc_regs.h ++++ b/drivers/gpu/drm/xe/regs/xe_guc_regs.h +@@ -40,6 +40,9 @@ + #define GS_BOOTROM_JUMP_PASSED REG_FIELD_PREP(GS_BOOTROM_MASK, 0x76) + #define GS_MIA_IN_RESET REG_BIT(0) + ++#define BOOT_HASH_CHK XE_REG(0xc010) ++#define GUC_BOOT_UKERNEL_VALID REG_BIT(31) ++ + #define GUC_HEADER_INFO XE_REG(0xc014) + + #define GUC_WOPCM_SIZE XE_REG(0xc050) +@@ -83,7 +86,12 @@ + #define GUC_WOPCM_OFFSET_MASK REG_GENMASK(31, GUC_WOPCM_OFFSET_SHIFT) + #define HUC_LOADING_AGENT_GUC REG_BIT(1) + #define GUC_WOPCM_OFFSET_VALID REG_BIT(0) ++ ++#define GUC_SRAM_STATUS XE_REG(0xc398) ++#define GUC_SRAM_HANDLING_MASK REG_GENMASK(8, 7) ++ + #define GUC_MAX_IDLE_COUNT XE_REG(0xc3e4) ++#define GUC_IDLE_FLOW_DISABLE REG_BIT(31) + #define GUC_PMTIMESTAMP_LO XE_REG(0xc3e8) + #define GUC_PMTIMESTAMP_HI XE_REG(0xc3ec) + +diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c +index ae0c88da422b2..091da0f258aaa 100644 +--- a/drivers/gpu/drm/xe/xe_guc.c ++++ b/drivers/gpu/drm/xe/xe_guc.c +@@ -882,6 +882,41 @@ int xe_guc_post_load_init(struct xe_guc *guc) + return xe_guc_submit_enable(guc); + } + ++/* ++ * Wa_14025883347: Prevent GuC firmware DMA failures during GuC-only reset by ensuring ++ * SRAM save/restore operations are complete before reset. ++ */ ++static void guc_prevent_fw_dma_failure_on_reset(struct xe_guc *guc) ++{ ++ struct xe_gt *gt = guc_to_gt(guc); ++ u32 boot_hash_chk, guc_status, sram_status; ++ int ret; ++ ++ guc_status = xe_mmio_read32(>->mmio, GUC_STATUS); ++ if (guc_status & GS_MIA_IN_RESET) ++ return; ++ ++ boot_hash_chk = xe_mmio_read32(>->mmio, BOOT_HASH_CHK); ++ if (!(boot_hash_chk & GUC_BOOT_UKERNEL_VALID)) ++ return; ++ ++ /* Disable idle flow during reset (GuC reset re-enables it automatically) */ ++ xe_mmio_rmw32(>->mmio, GUC_MAX_IDLE_COUNT, 0, GUC_IDLE_FLOW_DISABLE); ++ ++ ret = xe_mmio_wait32(>->mmio, GUC_STATUS, GS_UKERNEL_MASK, ++ FIELD_PREP(GS_UKERNEL_MASK, XE_GUC_LOAD_STATUS_READY), ++ 100000, &guc_status, false); ++ if (ret) ++ xe_gt_warn(gt, "GuC not ready after disabling idle flow (GUC_STATUS: 0x%x)\n", ++ guc_status); ++ ++ ret = xe_mmio_wait32(>->mmio, GUC_SRAM_STATUS, GUC_SRAM_HANDLING_MASK, ++ 0, 5000, &sram_status, false); ++ if (ret) ++ xe_gt_warn(gt, "SRAM handling not complete (GUC_SRAM_STATUS: 0x%x)\n", ++ sram_status); ++} ++ + int xe_guc_reset(struct xe_guc *guc) + { + struct xe_gt *gt = guc_to_gt(guc); +@@ -894,6 +929,9 @@ int xe_guc_reset(struct xe_guc *guc) + if (IS_SRIOV_VF(gt_to_xe(gt))) + return xe_gt_sriov_vf_bootstrap(gt); + ++ if (XE_GT_WA(gt, 14025883347)) ++ guc_prevent_fw_dma_failure_on_reset(guc); ++ + xe_mmio_write32(mmio, GDRST, GRDOM_GUC); + + ret = xe_mmio_wait32(mmio, GDRST, GRDOM_GUC, 0, 5000, &gdrst, false); +diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules +index 1d32fa1c3b2d7..6660f109ff7af 100644 +--- a/drivers/gpu/drm/xe/xe_wa_oob.rules ++++ b/drivers/gpu/drm/xe/xe_wa_oob.rules +@@ -82,3 +82,6 @@ + 15015404425_disable PLATFORM(PANTHERLAKE), MEDIA_STEP(B0, FOREVER) + 16026007364 MEDIA_VERSION(3000) + 14020316580 MEDIA_VERSION(1301) ++ ++14025883347 MEDIA_VERSION_RANGE(1301, 3503) ++ GRAPHICS_VERSION_RANGE(2004, 3005) +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-6.18/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..6a5aac8c25 --- /dev/null +++ b/queue-6.18/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 202ee358c311f05a4544f493a2810e096179248a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index 4bc7454a5d3ac..7e77310da626f 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - enum: +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch b/queue-6.18/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch new file mode 100644 index 0000000000..aaf3146b80 --- /dev/null +++ b/queue-6.18/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch @@ -0,0 +1,37 @@ +From 59353d4b54b6d86391fe27a6967ada11af7df895 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:42 +0100 +Subject: dt-bindings: rtc: microcrystal,rv3028: Allow to specify vdd-supply + +From: Frieder Schrempf + +[ Upstream commit 10663044bee592ba049a2aa37f4431fbdf93b739 ] + +In case the VDD supply voltage regulator of the RTC needs to be +specified explicitly, allow to set vdd-supply. + +Signed-off-by: Frieder Schrempf +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20260309085749.25747-2-frieder@fris.de +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +index cda8ad7c12037..2ea3b40419530 100644 +--- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml ++++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +@@ -32,6 +32,8 @@ properties: + - 9000 + - 15000 + ++ vdd-supply: true ++ + required: + - compatible + - reg +-- +2.53.0 + diff --git a/queue-6.18/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-6.18/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..da8378c1c5 --- /dev/null +++ b/queue-6.18/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From 692fa5514fc48200c92d10d3a94e118c9638fe00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 16ea14dd2c62e..3757e918500a5 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -523,6 +523,7 @@ static int ecryptfs_get_tree(struct fs_context *fc) + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-6.18/enic-add-v2-sr-iov-vf-device-id.patch b/queue-6.18/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..5d831de878 --- /dev/null +++ b/queue-6.18/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,53 @@ +From 0e262ba40c4ca67d8d3af2b3e38934d7094090d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index 6bc8dfdb3d4be..2bd781a1d522b 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,12 +66,14 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + /* Supported devices */ + static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -307,7 +309,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-6.18/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch b/queue-6.18/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch new file mode 100644 index 0000000000..251a6bbf45 --- /dev/null +++ b/queue-6.18/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch @@ -0,0 +1,53 @@ +From eced64161311b60fefddd67725ea439029e974c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:02:49 +0800 +Subject: erofs: ensure all folios are managed in + erofs_try_to_free_all_cached_folios() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhan Xusheng + +[ Upstream commit 5de6951fedb29700ace53b283ccb951c8f712d12 ] + +folio_trylock() in erofs_try_to_free_all_cached_folios() may +successfully acquire the folio lock, but the subsequent check +for erofs_folio_is_managed() can skip unlocking when the folio +is not managed by EROFS. + +As Gao Xiang pointed out, this condition should not happen in +practice because compressed_bvecs[] only holds valid cached folios +at this point — any non-managed folio would have already been +detached by z_erofs_cache_release_folio() under folio lock. + +Fix this by adding DBG_BUGON() to catch unexpected folios +and ensure folio_unlock() is always called. + +Suggested-by: Gao Xiang +Signed-off-by: Zhan Xusheng +Reviewed-by: Gao Xiang +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index 71f01f0a07435..42b92761497ce 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -604,8 +604,7 @@ static int erofs_try_to_free_all_cached_folios(struct erofs_sb_info *sbi, + if (!folio_trylock(folio)) + return -EBUSY; + +- if (!erofs_folio_is_managed(sbi, folio)) +- continue; ++ DBG_BUGON(!erofs_folio_is_managed(sbi, folio)); + pcl->compressed_bvecs[i].page = NULL; + folio_detach_private(folio); + folio_unlock(folio); +-- +2.53.0 + diff --git a/queue-6.18/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-6.18/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..206414915d --- /dev/null +++ b/queue-6.18/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From ba73ab923e292ba3637a892a0771d36aed93fcd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-6.18/exfat-fix-bitwise-operation-having-different-size.patch b/queue-6.18/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..a0a854c5b2 --- /dev/null +++ b/queue-6.18/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 12f28010448219b9c43a14238e0bc8231c1df5f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 7229146fe2bf6..6bce84da2ed03 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -248,7 +248,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-6.18/exfat-fix-incorrect-directory-checksum-after-rename-.patch b/queue-6.18/exfat-fix-incorrect-directory-checksum-after-rename-.patch new file mode 100644 index 0000000000..f832b06ab1 --- /dev/null +++ b/queue-6.18/exfat-fix-incorrect-directory-checksum-after-rename-.patch @@ -0,0 +1,44 @@ +From e6e58b977d3937ebd8d559a0c63ffa8356817cea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:33 +0800 +Subject: exfat: fix incorrect directory checksum after rename to shorter name + +From: Chi Zhiling + +[ Upstream commit ff37797badd831797b8a27830fe5046d7e23fdc3 ] + +When renaming a file in-place to a shorter name, exfat_remove_entries +marks excess entries as DELETED, but es->num_entries is not updated +accordingly. As a result, exfat_update_dir_chksum iterates over the +deleted entries and computes an incorrect checksum. + +This does not lead to persistent corruption because mark_inode_dirty() +is called afterward, and __exfat_write_inode later recomputes the +checksum using the correct num_entries value. + +Fix by setting es->num_entries = num_entries in exfat_init_ext_entry. + +Signed-off-by: Chi Zhiling +Reviewed-by: Sungjong Seo +Reviewed-by: Yuezhang Mo +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 6bce84da2ed03..357df1e56457b 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -488,6 +488,7 @@ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries, + unsigned short *uniname = p_uniname->name; + struct exfat_dentry *ep; + ++ es->num_entries = num_entries; + ep = exfat_get_dentry_cached(es, ES_IDX_FILE); + ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); + +-- +2.53.0 + diff --git a/queue-6.18/exfat-fix-s_maxbytes.patch b/queue-6.18/exfat-fix-s_maxbytes.patch new file mode 100644 index 0000000000..be41dfd7e9 --- /dev/null +++ b/queue-6.18/exfat-fix-s_maxbytes.patch @@ -0,0 +1,80 @@ +From 5d20cf5e26c5130e1b1c349d2d74a633bc1980d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 06:41:37 +0900 +Subject: exfat: fix s_maxbytes + +From: David Timber + +[ Upstream commit 4129a3a2751cba8511cee5d13145223662a8e019 ] + +With fallocate support, xfstest unit generic/213 fails with + + QA output created by 213 + We should get: fallocate: No space left on device + Strangely, xfs_io sometimes says "Success" when something went wrong + -fallocate: No space left on device + +fallocate: File too large + +because sb->s_maxbytes is set to the volume size. + +To be in line with other non-extent-based filesystems, set to max volume +size possible with the cluster size of the volume. + +Signed-off-by: David Timber +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/exfat_raw.h | 1 + + fs/exfat/file.c | 1 + + fs/exfat/super.c | 11 ++++++++--- + 3 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h +index 4082fa7b8c142..ec70cd35bba0c 100644 +--- a/fs/exfat/exfat_raw.h ++++ b/fs/exfat/exfat_raw.h +@@ -25,6 +25,7 @@ + #define EXFAT_FIRST_CLUSTER 2 + #define EXFAT_DATA_CLUSTER_COUNT(sbi) \ + ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) ++#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) + + /* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ + #define ALLOC_POSSIBLE 0x01 +diff --git a/fs/exfat/file.c b/fs/exfat/file.c +index 536c8078f0c19..c97e93b4ae70d 100644 +--- a/fs/exfat/file.c ++++ b/fs/exfat/file.c +@@ -32,6 +32,7 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) + return ret; + + num_clusters = EXFAT_B_TO_CLU(exfat_ondisk_size(inode), sbi); ++ /* integer overflow is already checked in inode_newsize_ok(). */ + new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi); + + if (new_num_clusters == num_clusters) +diff --git a/fs/exfat/super.c b/fs/exfat/super.c +index 581754001128b..ee4182742b808 100644 +--- a/fs/exfat/super.c ++++ b/fs/exfat/super.c +@@ -531,9 +531,14 @@ static int exfat_read_boot_sector(struct super_block *sb) + if (sbi->vol_flags & MEDIA_FAILURE) + exfat_warn(sb, "Medium has reported failures. Some data may be lost."); + +- /* exFAT file size is limited by a disk volume size */ +- sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << +- sbi->cluster_size_bits; ++ /* ++ * Set to the max possible volume size for this volume's cluster size so ++ * that any integer overflow from bytes to cluster size conversion is ++ * checked in inode_newsize_ok(). Clamped to MAX_LFS_FILESIZE for 32-bit ++ * machines. ++ */ ++ sb->s_maxbytes = min(MAX_LFS_FILESIZE, ++ EXFAT_CLU_TO_B((loff_t)EXFAT_MAX_NUM_CLUSTER, sbi)); + + /* check logical sector size */ + if (exfat_calibrate_blocksize(sb, 1 << p_boot->sect_size_bits)) +-- +2.53.0 + diff --git a/queue-6.18/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-6.18/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..00a9d01ae5 --- /dev/null +++ b/queue-6.18/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From a7ed4564352971ab6182bc08d831931746206aae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index f9501c3a3666b..5176fbf21a8ce 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -701,7 +701,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-6.18/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch b/queue-6.18/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch new file mode 100644 index 0000000000..bfe2f4eba0 --- /dev/null +++ b/queue-6.18/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch @@ -0,0 +1,45 @@ +From 48f5501dca89850dc58b028893ab41be5de12ec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 02:20:52 +0000 +Subject: ext2: avoid drop_nlink() during unlink of zero-nlink inode in + ext2_unlink() + +From: Ziyi Guo + +[ Upstream commit 19134a133184fcc49c41cf42797cb2e7fef76065 ] + +ext2_unlink() calls inode_dec_link_count() unconditionally, which +invokes drop_nlink(). If the inode was loaded from a corrupted disk +image with i_links_count == 0, drop_nlink() +triggers WARN_ON(inode->i_nlink == 0) + +Follow the ext4 pattern from __ext4_unlink(): check i_nlink before +decrementing. If already zero, skip the decrement. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260211022052.973114-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/namei.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c +index bde617a66cecd..728c487308baf 100644 +--- a/fs/ext2/namei.c ++++ b/fs/ext2/namei.c +@@ -293,7 +293,10 @@ static int ext2_unlink(struct inode *dir, struct dentry *dentry) + goto out; + + inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); +- inode_dec_link_count(inode); ++ ++ if (inode->i_nlink) ++ inode_dec_link_count(inode); ++ + err = 0; + out: + return err; +-- +2.53.0 + diff --git a/queue-6.18/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-6.18/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..97b6c2edee --- /dev/null +++ b/queue-6.18/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From 3347b54005e7a74beca7878fd24dd772ef1c1c51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index 4aac18942eccd..cfb2aa9ed9a26 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -638,7 +638,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-6.18/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch b/queue-6.18/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch new file mode 100644 index 0000000000..82cda98e7f --- /dev/null +++ b/queue-6.18/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch @@ -0,0 +1,98 @@ +From 6fd0e61652e92bfdef1b9bb5daac7c87dee9791a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:29:14 +0530 +Subject: ext4: unmap invalidated folios from page tables in + mpage_release_unused_pages() + +From: Deepanshu Kartikey + +[ Upstream commit 9b25f381de6b8942645f43735cb0a4fb0ab3a6d1 ] + +When delayed block allocation fails (e.g., due to filesystem corruption +detected in ext4_map_blocks()), the writeback error handler calls +mpage_release_unused_pages(invalidate=true) which invalidates affected +folios by clearing their uptodate flag via folio_clear_uptodate(). + +However, these folios may still be mapped in process page tables. If a +subsequent operation (such as ftruncate calling ext4_block_truncate_page) +triggers a write fault, the existing page table entry allows access to +the now-invalidated folio. This leads to ext4_page_mkwrite() being called +with a non-uptodate folio, which then gets marked dirty, triggering: + + WARNING: CPU: 0 PID: 5 at mm/page-writeback.c:2960 + __folio_mark_dirty+0x578/0x880 + + Call Trace: + fault_dirty_shared_page+0x16e/0x2d0 + do_wp_page+0x38b/0xd20 + handle_pte_fault+0x1da/0x450 + +The sequence leading to this warning is: + +1. Process writes to mmap'd file, folio becomes uptodate and dirty +2. Writeback begins, but delayed allocation fails due to corruption +3. mpage_release_unused_pages(invalidate=true) is called: + - block_invalidate_folio() clears dirty flag + - folio_clear_uptodate() clears uptodate flag + - But folio remains mapped in page tables +4. Later, ftruncate triggers ext4_block_truncate_page() +5. This causes a write fault on the still-mapped folio +6. ext4_page_mkwrite() is called with folio that is !uptodate +7. block_page_mkwrite() marks buffers dirty +8. fault_dirty_shared_page() tries to mark folio dirty +9. block_dirty_folio() calls __folio_mark_dirty(warn=1) +10. WARNING triggers: WARN_ON_ONCE(warn && !uptodate && !dirty) + +Fix this by unmapping folios from page tables before invalidating them +using unmap_mapping_pages(). This ensures that subsequent accesses +trigger new page faults rather than reusing invalidated folios through +stale page table entries. + +Note that this results in data loss for any writes to the mmap'd region +that couldn't be written back, but this is expected behavior when +writeback fails due to filesystem corruption. The existing error message +already states "This should not happen!! Data will be lost". + +Reported-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Tested-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a +Suggested-by: Matthew Wilcox +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20251205055914.1393799-1-kartikey406@gmail.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 3ed0c2656e2e1..75dccaeebd5bc 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1759,8 +1759,22 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd, + BUG_ON(!folio_test_locked(folio)); + BUG_ON(folio_test_writeback(folio)); + if (invalidate) { +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { + folio_clear_dirty_for_io(folio); ++ /* ++ * Unmap folio from page ++ * tables to prevent ++ * subsequent accesses through ++ * stale PTEs. This ensures ++ * future accesses trigger new ++ * page faults rather than ++ * reusing the invalidated ++ * folio. ++ */ ++ unmap_mapping_pages(folio->mapping, ++ folio->index, ++ folio_nr_pages(folio), false); ++ } + block_invalidate_folio(folio, 0, + folio_size(folio)); + folio_clear_uptodate(folio); +-- +2.53.0 + diff --git a/queue-6.18/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch b/queue-6.18/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch new file mode 100644 index 0000000000..dc54c67daf --- /dev/null +++ b/queue-6.18/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch @@ -0,0 +1,115 @@ +From 5210d33e29142ff3edfd1ba3c67a1b302c4ab7c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:54 -0700 +Subject: f2fs: fix to freeze GC and discard threads quickly + +From: Daeho Jeong + +[ Upstream commit 02d91398a602c394d72cd61a67c84e2730c5f79b ] + +Suspend can fail if kernel threads do not freeze for a while. +f2fs_gc and f2fs_discard threads can perform long-running operations +that prevent them from reaching a freeze point in a timely manner. + +This patch adds explicit freezing checks in the following locations: +1. f2fs_gc: Added a check at the 'retry' label to exit the loop quickly + if freezing is requested, especially during heavy GC rounds. +2. __issue_discard_cmd: Added a 'suspended' flag to break both inner and + outer loops during discard command issuance if freezing is detected + after at least one command has been issued. +3. __issue_discard_cmd_orderly: Added a similar check for orderly discard + to ensure responsiveness. + +These checks ensure that the threads release locks safely and enter the +frozen state. + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 10 ++++++++++ + fs/f2fs/segment.c | 12 +++++++++++- + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 5d4202564f257..d107f54f4bf0d 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1879,12 +1879,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + sbi->next_victim_seg[gc_type] = + (cur_segno + 1 < sec_end_segno) ? + cur_segno + 1 : NULL_SEGNO; ++ ++ if (unlikely(freezing(current))) { ++ folio_put_refs(sum_folio, 2); ++ goto stop; ++ } + } + next_block: + folio_put_refs(sum_folio, 2); + segno = block_end_segno; + } + ++stop: + if (submitted) + f2fs_submit_merged_write(sbi, data_type); + +@@ -1958,6 +1964,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control) + goto stop; + } + retry: ++ if (unlikely(freezing(current))) { ++ ret = 0; ++ goto stop; ++ } + ret = __get_victim(sbi, &segno, gc_type, gc_control->one_time); + if (ret) { + /* allow to search victim from sections has pinned data */ +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index a7cf8627d8881..ed3c330445195 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -1621,6 +1621,9 @@ static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, + if (dc->state != D_PREP) + goto next; + ++ if (*issued > 0 && unlikely(freezing(current))) ++ break; ++ + if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { + io_interrupted = true; + break; +@@ -1660,6 +1663,7 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + struct blk_plug plug; + int i, issued; + bool io_interrupted = false; ++ bool suspended = false; + + if (dpolicy->timeout) + f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT); +@@ -1690,6 +1694,11 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + list_for_each_entry_safe(dc, tmp, pend_list, list) { + f2fs_bug_on(sbi, dc->state != D_PREP); + ++ if (issued > 0 && unlikely(freezing(current))) { ++ suspended = true; ++ break; ++ } ++ + if (dpolicy->timeout && + f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) + break; +@@ -1709,7 +1718,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + next: + mutex_unlock(&dcc->cmd_lock); + +- if (issued >= dpolicy->max_requests || io_interrupted) ++ if (issued >= dpolicy->max_requests || io_interrupted || ++ suspended) + break; + } + +-- +2.53.0 + diff --git a/queue-6.18/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-6.18/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..917e8b2f9d --- /dev/null +++ b/queue-6.18/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From c29fe65fc7af7b6c2a9d52926e36de00d3ebb417 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 3d9f326ae840a..5d4202564f257 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -905,6 +905,9 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-6.18/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-6.18/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..0e435db543 --- /dev/null +++ b/queue-6.18/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From 31a3871dfff9924ddae3de024e44ce92bcdf2703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index 211f23648686c..79688c2cc6d68 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-6.18/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-6.18/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..3fc3124d68 --- /dev/null +++ b/queue-6.18/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From f989b46380406b5a1cca03424d63ff6b22f9f4b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index ac41f8f37589f..c2f79357c8da0 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-6.18/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-6.18/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..37284c6100 --- /dev/null +++ b/queue-6.18/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From 05a6e3a00a4150ac9c9b3489f8ecf5de5bc79dce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index 8673fced87492..3fa2304fbda7e 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-6.18/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-6.18/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..4b460e05f1 --- /dev/null +++ b/queue-6.18/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From 1ecd52d95a5df8b2fdb682cf64a43366b5015ddc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 0fbbb7286008d..6b8cfbee3b9d6 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-6.18/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch new file mode 100644 index 0000000000..217b18b4a4 --- /dev/null +++ b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch @@ -0,0 +1,36 @@ +From 8dd881bbd6681098fd6ae4724205433d4245d965 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Feb 2026 09:32:54 +0100 +Subject: firmware: qcom: scm: allow QSEECOM on ASUS Vivobook X1P42100 variant + +From: Jens Glathe + +[ Upstream commit 26b86610650eaac17bf6574f34d9119151b95483 ] + +Enables access to EFI variables on this machine. + +Reviewed-by: Dmitry Baryshkov +Tested-by: Colin K. Williams +Signed-off-by: Jens Glathe +Link: https://lore.kernel.org/r/20260214-b4-vivobook-v3-2-3c88065bbf77@oldschoolsolutions.biz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index e777b7cb9b127..b4b8a3a2aa431 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -1992,6 +1992,7 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); + */ + static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "asus,vivobook-s15" }, ++ { .compatible = "asus,vivobook-s15-x1p4" }, + { .compatible = "asus,zenbook-a14-ux3407qa" }, + { .compatible = "asus,zenbook-a14-ux3407ra" }, + { .compatible = "dell,inspiron-14-plus-7441" }, +-- +2.53.0 + diff --git a/queue-6.18/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch new file mode 100644 index 0000000000..18183db529 --- /dev/null +++ b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch @@ -0,0 +1,35 @@ +From f2f10832aa2f69395752c18bde4602352170ea54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:30:13 -0300 +Subject: firmware: qcom: scm: Allow QSEECOM on ECS LIVA QC710 + +From: Val Packett + +[ Upstream commit 34a49e8508b5d00816d25fe3758b474471e7e051 ] + +Allow this machine to access efivars through qseecom/uefisecapp. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260120234029.419825-11-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index b4b8a3a2aa431..f4af30d26da42 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -1998,6 +1998,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "dell,inspiron-14-plus-7441" }, + { .compatible = "dell,latitude-7455" }, + { .compatible = "dell,xps13-9345" }, ++ { .compatible = "ecs,liva-qc710" }, + { .compatible = "hp,elitebook-ultra-g1q" }, + { .compatible = "hp,omnibook-x14" }, + { .compatible = "huawei,gaokun3" }, +-- +2.53.0 + diff --git a/queue-6.18/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch new file mode 100644 index 0000000000..95878ba9ae --- /dev/null +++ b/queue-6.18/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch @@ -0,0 +1,37 @@ +From 4fa69f08f044a9d523a3016176bfa7693be7578e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 21:31:27 -0500 +Subject: firmware: qcom: scm: Allow QSEECOM on Lenovo IdeaCentre Mini X + +From: Bjorn Andersson + +[ Upstream commit a31ad9339eff4ce401dec816b01a94b4e3c47898 ] + +The Hamoa-based Lenovo IdeaCentre Mini X provides the same UEFI variable +access through uefisecapp as other Hamoa devices, add it to the +allowlist. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20260401-ideacentre-v2-3-5745fe2c764e@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index f4af30d26da42..7d9c605cff3cd 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -2003,6 +2003,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "hp,omnibook-x14" }, + { .compatible = "huawei,gaokun3" }, + { .compatible = "lenovo,flex-5g" }, ++ { .compatible = "lenovo,ideacentre-mini-01q8x10" }, + { .compatible = "lenovo,thinkbook-16" }, + { .compatible = "lenovo,thinkpad-t14s" }, + { .compatible = "lenovo,thinkpad-x13s", }, +-- +2.53.0 + diff --git a/queue-6.18/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch b/queue-6.18/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch new file mode 100644 index 0000000000..bbd2145791 --- /dev/null +++ b/queue-6.18/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch @@ -0,0 +1,124 @@ +From e0c530dad21010a579b1c094f18ecd5515dba7bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 16:46:29 +0900 +Subject: fprobe: Fix unregister_fprobe() to wait for RCU grace period + +From: Masami Hiramatsu (Google) + +[ Upstream commit 657b594b2084b39a4bc6d8493aa2140cb00cea49 ] + +Commit 4346ba1604093 ("fprobe: Rewrite fprobe on function-graph tracer") +changed fprobe to register struct fprobe to an rcu-hlist, but it forgot +to wait for RCU GP. Thus there can be use-after-free if the fprobe is +released right after unregistering. This can be happened on fprobe +event and sample module code. + +To fix this issue, add synchronize_rcu() in unregister_fprobe(). + +Note that BPF is OK because fprobe is used as a part of +bpf_kprobe_multi_link. This unregisters its fprobe in +bpf_kprobe_multi_link_release() and it is deallocated via +bpf_kprobe_multi_link_dealloc(), which is invoked from +bpf_link_defer_dealloc_rcu_gp() RCU callback. + +For BPF, this also introduced unregister_fprobe_async() which does +NOT wait for RCU grace priod. + +Link: https://lore.kernel.org/all/177813998919.256460.2809243930741138224.stgit@mhiramat.tok.corp.google.com/ + +Fixes: 4346ba1604093 ("fprobe: Rewrite fprobe on function-graph tracer") +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/linux/fprobe.h | 5 +++++ + kernel/trace/bpf_trace.c | 3 ++- + kernel/trace/fprobe.c | 23 +++++++++++++++++++++-- + 3 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h +index 0a3bcd1718f37..be1b38c981d4d 100644 +--- a/include/linux/fprobe.h ++++ b/include/linux/fprobe.h +@@ -94,6 +94,7 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter + int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num); + int register_fprobe_syms(struct fprobe *fp, const char **syms, int num); + int unregister_fprobe(struct fprobe *fp); ++int unregister_fprobe_async(struct fprobe *fp); + bool fprobe_is_registered(struct fprobe *fp); + int fprobe_count_ips_from_filter(const char *filter, const char *notfilter); + #else +@@ -113,6 +114,10 @@ static inline int unregister_fprobe(struct fprobe *fp) + { + return -EOPNOTSUPP; + } ++static inline int unregister_fprobe_async(struct fprobe *fp) ++{ ++ return -EOPNOTSUPP; ++} + static inline bool fprobe_is_registered(struct fprobe *fp) + { + return false; +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 70f1292b7ddbd..88f470b31375a 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2371,7 +2371,8 @@ static void bpf_kprobe_multi_link_release(struct bpf_link *link) + struct bpf_kprobe_multi_link *kmulti_link; + + kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); +- unregister_fprobe(&kmulti_link->fp); ++ /* Don't wait for RCU GP here. */ ++ unregister_fprobe_async(&kmulti_link->fp); + kprobe_multi_put_modules(kmulti_link->mods, kmulti_link->mods_cnt); + } + +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 8fa5bff2c26fa..27bb4cbfd4831 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -945,14 +945,15 @@ static int unregister_fprobe_nolock(struct fprobe *fp) + } + + /** +- * unregister_fprobe() - Unregister fprobe. ++ * unregister_fprobe_async() - Unregister fprobe without RCU GP wait + * @fp: A fprobe data structure to be unregistered. + * + * Unregister fprobe (and remove ftrace hooks from the function entries). ++ * This function will NOT wait until the fprobe is no longer used. + * + * Return 0 if @fp is unregistered successfully, -errno if not. + */ +-int unregister_fprobe(struct fprobe *fp) ++int unregister_fprobe_async(struct fprobe *fp) + { + guard(mutex)(&fprobe_mutex); + if (!fp || !fprobe_registered(fp)) +@@ -960,6 +961,24 @@ int unregister_fprobe(struct fprobe *fp) + + return unregister_fprobe_nolock(fp); + } ++ ++/** ++ * unregister_fprobe() - Unregister fprobe with RCU GP wait ++ * @fp: A fprobe data structure to be unregistered. ++ * ++ * Unregister fprobe (and remove ftrace hooks from the function entries). ++ * This function will block until the fprobe is no longer used. ++ * ++ * Return 0 if @fp is unregistered successfully, -errno if not. ++ */ ++int unregister_fprobe(struct fprobe *fp) ++{ ++ int ret = unregister_fprobe_async(fp); ++ ++ if (!ret) ++ synchronize_rcu(); ++ return ret; ++} + EXPORT_SYMBOL_GPL(unregister_fprobe); + + static int __init fprobe_initcall(void) +-- +2.53.0 + diff --git a/queue-6.18/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-6.18/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..bc59def595 --- /dev/null +++ b/queue-6.18/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 3ccc9ab7ccf18a0a4e09a49af249e19bfe43d3a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 5bc1333864078..5f239fa9fc4a6 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-6.18/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch b/queue-6.18/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch new file mode 100644 index 0000000000..c12ebe3c9d --- /dev/null +++ b/queue-6.18/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch @@ -0,0 +1,55 @@ +From f69494d70f1fa7134758942940ac02f6a7f7b918 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 May 2026 15:10:58 +0800 +Subject: fs: Fix return in jfs_mkdir and orangefs_mkdir + +From: Hongling Zeng + +[ Upstream commit a7cf1da7ac016490d6a1106f2aa6b602d34e9a12 ] + +Return NULL instead of passing to ERR_PTR while err is zero +Fixes these smatch warnings: + - fs/jfs/namei.c:311 jfs_mkdir() warn: passing zero to 'ERR_PTR' + - fs/orangefs/namei.c:369 orangefs_mkdir() warn: passing zero + to 'ERR_PTR' + +Fixes: 88d5baf69082 ("Change inode_operations.mkdir to return struct dentry *") +Signed-off-by: Hongling Zeng +Link: https://patch.msgid.link/20260501071058.1243245-1-zenghongling@kylinos.cn +Reviewed-by: Jori Koolstra +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/jfs/namei.c | 2 +- + fs/orangefs/namei.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c +index 7879c049632b3..553fca69cf425 100644 +--- a/fs/jfs/namei.c ++++ b/fs/jfs/namei.c +@@ -308,7 +308,7 @@ static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, + out1: + + jfs_info("jfs_mkdir: rc:%d", rc); +- return ERR_PTR(rc); ++ return rc ? ERR_PTR(rc) : NULL; + } + + /* +diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c +index bec5475de094d..75e65e72c2d64 100644 +--- a/fs/orangefs/namei.c ++++ b/fs/orangefs/namei.c +@@ -362,7 +362,7 @@ static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + __orangefs_setattr(dir, &iattr); + out: + op_release(new_op); +- return ERR_PTR(ret); ++ return ret ? ERR_PTR(ret) : NULL; + } + + static int orangefs_rename(struct mnt_idmap *idmap, +-- +2.53.0 + diff --git a/queue-6.18/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-6.18/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..cf425bb05b --- /dev/null +++ b/queue-6.18/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From 6b9df1350552a24866a42d2253fa21e9bfa98c6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index 142ecb3847e59..e6035e2f2c366 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1025,7 +1025,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-6.18/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-6.18/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..d23fea8983 --- /dev/null +++ b/queue-6.18/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From c8f1b8deba395ade6ca43eb04065dd9f27268e06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 9a2e3d0efd998..40540c4e4ac64 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1616,7 +1616,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + if (boot2) { +-- +2.53.0 + diff --git a/queue-6.18/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-6.18/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..7a4c72d2c5 --- /dev/null +++ b/queue-6.18/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 2accc1f1cea312ee9dc9bfccae6b4d9f94dacf12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 90d1de22fee68..0c9d77301063b 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-6.18/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch b/queue-6.18/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch new file mode 100644 index 0000000000..abecfd2517 --- /dev/null +++ b/queue-6.18/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch @@ -0,0 +1,49 @@ +From 38087587fe4eb5ee8b8afa43800b7baf1cc2bde3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 May 2026 20:26:49 +0900 +Subject: fs/statmount: fix slab out-of-bounds write in statmount_mnt_idmap + +From: Junyoung Jang + +[ Upstream commit a3bf0f28d4ba16e1f35f8c983bb04426b87e2a78 ] + +statmount_mnt_idmap() writes one mapping with seq_printf() and then +manually advances seq->count to include the NUL separator. + +If seq_printf() overflows, seq_set_overflow() sets seq->count to +seq->size. The manual seq->count++ changes this to seq->size + 1. +seq_has_overflowed() then no longer detects the overflow. The corrupted +count returns to statmount_string(), which later executes: + + seq->buf[seq->count++] = '\0'; + +This causes a 1-byte NULL out-of-bounds write on the dynamically +allocated seq buffer. + +Fix this by checking for overflow immediately after seq_printf(). + +Fixes: 37c4a9590e1e ("statmount: allow to retrieve idmappings") +Signed-off-by: Junyoung Jang +Link: https://patch.msgid.link/20260504112649.1862936-1-graypanda.inzag@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/mnt_idmapping.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/mnt_idmapping.c b/fs/mnt_idmapping.c +index a37991fdb194d..3640230a4d43b 100644 +--- a/fs/mnt_idmapping.c ++++ b/fs/mnt_idmapping.c +@@ -375,6 +375,8 @@ int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_ + continue; + + seq_printf(seq, "%u %u %u", extent->first, lower, extent->count); ++ if (seq_has_overflowed(seq)) ++ return -EAGAIN; + + seq->count++; /* mappings are separated by \0 */ + if (seq_has_overflowed(seq)) +-- +2.53.0 + diff --git a/queue-6.18/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-6.18/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..0a492fd34c --- /dev/null +++ b/queue-6.18/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From 62d8dac5dc3b45a9ed02e0c30c2a53d7191155b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 7821781245121..d2f9bbbb475bd 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -117,6 +117,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-6.18/fuse-validate-outarg-offset-and-size-in-notify-store.patch b/queue-6.18/fuse-validate-outarg-offset-and-size-in-notify-store.patch new file mode 100644 index 0000000000..b4ac7022c7 --- /dev/null +++ b/queue-6.18/fuse-validate-outarg-offset-and-size-in-notify-store.patch @@ -0,0 +1,81 @@ +From 2c7bf060bd91bebafd35313084213377e28d5826 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:44:46 -0800 +Subject: fuse: validate outarg offset and size in notify store/retrieve + +From: Joanne Koong + +[ Upstream commit 65161470f95bb579a72673bf303ecf0800b9054b ] + +Add validation checking for outarg offset and outarg size values passed +in by the server. MAX_LFS_FILESIZE is the maximum file size supported. +The fuse_notify_store_out and fuse_notify_retrieve_out structs take in +a uint64_t offset. + +Add logic to ensure: +* outarg.offset is less than MAX_LFS_FILESIZE +* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE +* potential uint64_t overflow is fixed when adding outarg.offset and + outarg.size. + +Signed-off-by: Joanne Koong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 039fe9c0c3cba..e8a74bd0ec905 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1790,7 +1790,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + if (size - sizeof(outarg) != outarg.size) + return -EINVAL; + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + nodeid = outarg.nodeid; ++ num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset); + + down_read(&fc->killsb); + +@@ -1803,13 +1807,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + index = outarg.offset >> PAGE_SHIFT; + offset = outarg.offset & ~PAGE_MASK; + file_size = i_size_read(inode); +- end = outarg.offset + outarg.size; ++ end = outarg.offset + num; + if (end > file_size) { + file_size = end; +- fuse_write_update_attr(inode, file_size, outarg.size); ++ fuse_write_update_attr(inode, file_size, num); + } + +- num = outarg.size; + while (num) { + struct folio *folio; + unsigned int folio_offset; +@@ -1889,7 +1892,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, + num = min(outarg->size, fc->max_write); + if (outarg->offset > file_size) + num = 0; +- else if (outarg->offset + num > file_size) ++ else if (num > file_size - outarg->offset) + num = file_size - outarg->offset; + + num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -1971,6 +1974,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, + + fuse_copy_finish(cs); + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + down_read(&fc->killsb); + err = -ENOENT; + nodeid = outarg.nodeid; +-- +2.53.0 + diff --git a/queue-6.18/gcc-plugins-always-define-const_cast_gimple-and-cons.patch b/queue-6.18/gcc-plugins-always-define-const_cast_gimple-and-cons.patch new file mode 100644 index 0000000000..a515130fec --- /dev/null +++ b/queue-6.18/gcc-plugins-always-define-const_cast_gimple-and-cons.patch @@ -0,0 +1,45 @@ +From 6ba5ef07d34506905a282e57004049d6d4846d91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 14:24:56 +0100 +Subject: gcc-plugins: Always define CONST_CAST_GIMPLE and CONST_CAST_TREE + +From: Kees Cook + +[ Upstream commit 905c559e51497b8bfdbb68df8be56d2f70f0de8e ] + +For gcc-16, the CONST_CAST macro family was removed. Add back what +we were using in gcc-common.h, as they are simple wrappers. + +See GCC commits: + c3d96ff9e916c02584aa081f03ab999292efbb50 + 458c7926d48959abcb2c1adaa22458e27459a551 + +Suggested-by: Ingo Saitz +Link: https://lore.kernel.org/lkml/ab6OKoay0OWkywjK@spatz.zoo +Fixes: 6b90bd4ba40b ("GCC plugin infrastructure") +Tested-by: Ivan Bulatovic +Tested-by: Christopher Cradock +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + scripts/gcc-plugins/gcc-common.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h +index 8f1b3500f8e2d..abb1964c44d4e 100644 +--- a/scripts/gcc-plugins/gcc-common.h ++++ b/scripts/gcc-plugins/gcc-common.h +@@ -309,7 +309,9 @@ typedef const gimple *const_gimple_ptr; + #define gimple gimple_ptr + #define const_gimple const_gimple_ptr + #undef CONST_CAST_GIMPLE +-#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X)) ++#define CONST_CAST_GIMPLE(X) const_cast((X)) ++#undef CONST_CAST_TREE ++#define CONST_CAST_TREE(X) const_cast((X)) + + /* gimple related */ + static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL) +-- +2.53.0 + diff --git a/queue-6.18/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..d12876e834 --- /dev/null +++ b/queue-6.18/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 00fe1be2cf435db014518c7dedbbb407485c2512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 7c95bb36511e1..cc5b1746f2fe8 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static int bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.18/gpio-cgbc-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-cgbc-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..8fc1dcb957 --- /dev/null +++ b/queue-6.18/gpio-cgbc-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,39 @@ +From 03df02162002d1a262c928e25852f01b3175c10e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:51 -0800 +Subject: gpio: cgbc: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 49621f1c97788216f2f10f1a9e903f216e289f5d ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by cgbc_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-2-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-cgbc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-cgbc.c b/drivers/gpio/gpio-cgbc.c +index 0efa1b61001ad..84b5ed3c6e22b 100644 +--- a/drivers/gpio/gpio-cgbc.c ++++ b/drivers/gpio/gpio-cgbc.c +@@ -47,8 +47,8 @@ static int cgbc_gpio_get(struct gpio_chip *chip, unsigned int offset) + + if (ret) + return ret; +- else +- return (int)(val & (u8)BIT(offset)); ++ ++ return !!(val & BIT(offset)); + } + + static int __cgbc_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.18/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..97dd96660e --- /dev/null +++ b/queue-6.18/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 6c0f22df3db3b8160f16f90e0d425c6b05daa8d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index a09bd6eb93cfb..1949a6ea8ec61 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-6.18/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..834b78c758 --- /dev/null +++ b/queue-6.18/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 86b99a2371f8fb6ceba4cc907d14beac6bbc5fbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 5376708a81bfe..f4413fa5a8110 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -55,7 +55,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static int lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.18/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..cbcf785560 --- /dev/null +++ b/queue-6.18/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 19d02ec43038fc14809c49e8723a268626e98dd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 84b17b83476f5..df770ecf28bc4 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -50,7 +50,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static int tps65086_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.18/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-6.18/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..b3d5da47ef --- /dev/null +++ b/queue-6.18/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 1ec6923f0369eef0fa3bf9af47eca01729a4cf03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index 15e495c109d2a..89087fd48a819 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -288,7 +288,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-6.18/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-6.18/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..8f2c02ebf9 --- /dev/null +++ b/queue-6.18/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From 20221c315eee9c34fec05bfcd2087c80d757dcce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 1aff3bbb8cfcf..2d2c8a71585e6 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -912,11 +912,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -928,7 +933,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-6.18/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..236973a368 --- /dev/null +++ b/queue-6.18/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From a1230e018f5c1a11e5fed2f2aee3d0c12a4cfb39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-6.18/hfsplus-fix-generic-642-failure.patch b/queue-6.18/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..6d84c65e65 --- /dev/null +++ b/queue-6.18/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From 957947bb4fe9fe1911f70ac7932d42a860cfec8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index b4645102feecd..12f1fd8b69ecf 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-6.18/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch b/queue-6.18/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch new file mode 100644 index 0000000000..864a88099d --- /dev/null +++ b/queue-6.18/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch @@ -0,0 +1,47 @@ +From 972c1e269a4f81ea3797492c9350e60b6d32d236 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 10:10:02 +0300 +Subject: HID: intel-thc-hid: Intel-quickspi: Fix some error codes + +From: Dan Carpenter + +[ Upstream commit ae4ac077332ea3341a0f4c0973556c6b7ac5b7a1 ] + +If we have a partial read that is supposed to be treated as failure but +in this code we forgot to set the error code. Return -EINVAL. + +Fixes: 9d8d51735a3a ("HID: intel-thc-hid: intel-quickspi: Add HIDSPI protocol implementation") +Signed-off-by: Dan Carpenter +Reviewed-by: Even Xu +Reviewed-by: Mark Pearson +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c +index 16f780bc879b1..cb19057f1191b 100644 +--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c ++++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c +@@ -94,7 +94,7 @@ static int quickspi_get_device_descriptor(struct quickspi_device *qsdev) + dev_err_once(qsdev->dev, "Read DEVICE_DESCRIPTOR failed, ret = %d\n", ret); + dev_err_once(qsdev->dev, "DEVICE_DESCRIPTOR expected len = %u, actual read = %u\n", + input_len, read_len); +- return ret; ++ return ret ?: -EINVAL; + } + + input_rep_type = ((struct input_report_body_header *)read_buf)->input_report_type; +@@ -318,7 +318,7 @@ int reset_tic(struct quickspi_device *qsdev) + dev_err_once(qsdev->dev, "Read RESET_RESPONSE body failed, ret = %d\n", ret); + dev_err_once(qsdev->dev, "RESET_RESPONSE body expected len = %u, actual = %u\n", + read_len, actual_read_len); +- return ret; ++ return ret ?: -EINVAL; + } + + input_rep_type = FIELD_GET(HIDSPI_IN_REP_BDY_HDR_REP_TYPE, reset_response); +-- +2.53.0 + diff --git a/queue-6.18/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch b/queue-6.18/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch new file mode 100644 index 0000000000..6a376e9eb2 --- /dev/null +++ b/queue-6.18/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch @@ -0,0 +1,56 @@ +From 28f599cb165df83f906015882821eabc089d6afe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:40:51 +0200 +Subject: HID: logitech-hidpp: Check bounds when deleting force-feedback + effects +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Günther Noack + +[ Upstream commit e606d8329be1e19b7eb3e0c6c72a73cbbb25ae3d ] + +Without this bounds check, this might otherwise overwrite index -1. + +Triggering this condition requires action both from the USB device and from +userspace, which reduces the scenarios in which it can be exploited. + +Cc: Lee Jones +Signed-off-by: Günther Noack +Reviewed-by: Lee Jones +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index 2eb67d0caebb2..1cc2428ebb4ab 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -2501,12 +2501,15 @@ static void hidpp_ff_work_handler(struct work_struct *w) + } + break; + case HIDPP_FF_DESTROY_EFFECT: +- if (wd->effect_id >= 0) +- /* regular effect destroyed */ +- data->effect_ids[wd->params[0]-1] = -1; +- else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) +- /* autocenter spring destroyed */ +- data->slot_autocenter = 0; ++ slot = wd->params[0]; ++ if (slot > 0 && slot <= data->num_effects) { ++ if (wd->effect_id >= 0) ++ /* regular effect destroyed */ ++ data->effect_ids[slot-1] = -1; ++ else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) ++ /* autocenter spring destroyed */ ++ data->slot_autocenter = 0; ++ } + break; + case HIDPP_FF_SET_GLOBAL_GAINS: + data->gain = (wd->params[0] << 8) + wd->params[1]; +-- +2.53.0 + diff --git a/queue-6.18/hid-logitech-hidpp-fix-race-condition-when-accessing.patch b/queue-6.18/hid-logitech-hidpp-fix-race-condition-when-accessing.patch new file mode 100644 index 0000000000..ddc38a84e5 --- /dev/null +++ b/queue-6.18/hid-logitech-hidpp-fix-race-condition-when-accessing.patch @@ -0,0 +1,112 @@ +From a677f0aa4fa3b428dbc2fa562efaa5288d1b4b7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:48:11 +0000 +Subject: HID: logitech-hidpp: fix race condition when accessing stale stack + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit e2aaf2d3ad92ac4a8afa6b69ad4c38e7747d3d6e ] + +The driver uses hidpp->send_receive_buf to point to a stack-allocated +buffer in the synchronous command path (__do_hidpp_send_message_sync). +However, this pointer is not cleared when the function returns. + +If an event is processed (e.g. by a different thread) while the +send_mutex is held by a new command, but before that command has +updated send_receive_buf, the handler (hidpp_raw_hidpp_event) will +observe that the mutex is locked and dereference the stale pointer. + +This results in an out-of-bounds access on a different thread's kernel +stack (or a NULL pointer dereference on the very first command). + +Fix this by: +1. Clearing hidpp->send_receive_buf to NULL before releasing the mutex + in the synchronous command path. +2. Moving the assignment of the local 'question' and 'answer' pointers + inside the mutex_is_locked() block in the handler, and adding + a NULL check before dereferencing. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index 1cc2428ebb4ab..35dc5bc0a7543 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -306,21 +306,22 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + if (ret) { + dbg_hid("__hidpp_send_report returned err: %d\n", ret); + memset(response, 0, sizeof(struct hidpp_report)); +- return ret; ++ goto out; + } + + if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, + 5*HZ)) { + dbg_hid("%s:timeout waiting for response\n", __func__); + memset(response, 0, sizeof(struct hidpp_report)); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + + if (response->report_id == REPORT_ID_HIDPP_SHORT && + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + + if ((response->report_id == REPORT_ID_HIDPP_LONG || +@@ -328,10 +329,14 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + response->fap.feature_index == HIDPP20_ERROR) { + ret = response->fap.params[1]; + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + +- return 0; ++ ret = 0; ++ ++out: ++ hidpp->send_receive_buf = NULL; ++ return ret; + } + + /* +@@ -3842,8 +3847,7 @@ static int hidpp_input_configured(struct hid_device *hdev, + static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + int size) + { +- struct hidpp_report *question = hidpp->send_receive_buf; +- struct hidpp_report *answer = hidpp->send_receive_buf; ++ struct hidpp_report *question, *answer; + struct hidpp_report *report = (struct hidpp_report *)data; + int ret; + int last_online; +@@ -3853,6 +3857,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + * previously sent command. + */ + if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { ++ question = hidpp->send_receive_buf; ++ answer = hidpp->send_receive_buf; ++ ++ if (!question) ++ return 0; ++ + /* + * Check for a correct hidpp20 answer or the corresponding + * error +-- +2.53.0 + diff --git a/queue-6.18/hid-playstation-validate-num_touch_reports-in-dualsh.patch b/queue-6.18/hid-playstation-validate-num_touch_reports-in-dualsh.patch new file mode 100644 index 0000000000..6d52b85b49 --- /dev/null +++ b/queue-6.18/hid-playstation-validate-num_touch_reports-in-dualsh.patch @@ -0,0 +1,64 @@ +From 062c79b626f2456beb28aae288ed67aba2474c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:47:37 +0000 +Subject: HID: playstation: validate num_touch_reports in DualShock 4 reports +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit 82a4fc46330910b4c1d9b189561439d468e3ff11 ] + +The DualShock 4 HID driver fails to validate the num_touch_reports field +received from the device in both USB and Bluetooth input reports. +A malicious device could set this field to a value larger than the +allocated size of the touch_reports array (3 for USB, 4 for Bluetooth), +leading to an out-of-bounds read in dualshock4_parse_report(). + +This can result in kernel memory disclosure when processing malicious +HID reports. + +Validate num_touch_reports against the array size for the respective +connection types before processing the touch data. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 12fad45ac1065..4a17fd0c12f89 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -2377,6 +2377,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + struct dualshock4_input_report_usb *usb = + (struct dualshock4_input_report_usb *)data; + ++ if (usb->num_touch_reports > ARRAY_SIZE(usb->touch_reports)) { ++ hid_err(hdev, "DualShock4 USB input report has invalid num_touch_reports=%d\n", ++ usb->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &usb->common; + num_touch_reports = min_t(u8, usb->num_touch_reports, + ARRAY_SIZE(usb->touch_reports)); +@@ -2392,6 +2398,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + return -EILSEQ; + } + ++ if (bt->num_touch_reports > ARRAY_SIZE(bt->touch_reports)) { ++ hid_err(hdev, "DualShock4 BT input report has invalid num_touch_reports=%d\n", ++ bt->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &bt->common; + num_touch_reports = min_t(u8, bt->num_touch_reports, + ARRAY_SIZE(bt->touch_reports)); +-- +2.53.0 + diff --git a/queue-6.18/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-6.18/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..608f27a8f7 --- /dev/null +++ b/queue-6.18/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From c48332b4bfbea147185fa9abdbb5088fdc564799 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index f6be3ffee0232..04d3ec360c1dc 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -234,7 +234,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-6.18/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-6.18/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..22e55cfe5f --- /dev/null +++ b/queue-6.18/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From a13980d2196728497f0c3c195cf4ffb5f3f8a1d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 04d3ec360c1dc..396feed716ee0 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -134,6 +134,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-6.18/hid-uclogic-fix-regression-of-input-name-assignment.patch b/queue-6.18/hid-uclogic-fix-regression-of-input-name-assignment.patch new file mode 100644 index 0000000000..84ecb0436e --- /dev/null +++ b/queue-6.18/hid-uclogic-fix-regression-of-input-name-assignment.patch @@ -0,0 +1,44 @@ +From 3dec4cf1e011e8b57bca365a0b88a42fe26a322f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:33:16 +0200 +Subject: HID: uclogic: Fix regression of input name assignment + +From: Takashi Iwai + +[ Upstream commit 487359284509a6745e14b8c0518768bc277809b0 ] + +The previous fix for adding the devm_kasprintf() return check in the +commit bd07f751208b ("HID: uclogic: Add NULL check in +uclogic_input_configured()") changed the condition of hi->input->name +assignment, and it resulted in missing the proper input device name +when no custom suffix is defined. + +Restore the conditional to the original content to address the +regression. + +Fixes: bd07f751208b ("HID: uclogic: Add NULL check in uclogic_input_configured()") +Signed-off-by: Takashi Iwai +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-uclogic-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index 34fb03ae8ee2f..c6db3e7c5fd30 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -184,7 +184,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } else { ++ } ++ ++ if (suffix) { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); + if (!hi->input->name) +-- +2.53.0 + diff --git a/queue-6.18/hinic3-add-msg_send_lock-for-message-sending-concurr.patch b/queue-6.18/hinic3-add-msg_send_lock-for-message-sending-concurr.patch new file mode 100644 index 0000000000..19a501275c --- /dev/null +++ b/queue-6.18/hinic3-add-msg_send_lock-for-message-sending-concurr.patch @@ -0,0 +1,91 @@ +From 3352371012d1ac1ea1e85cfe3f2c21f6bce256ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:04:53 +0800 +Subject: hinic3: Add msg_send_lock for message sending concurrecy + +From: Fan Gong + +[ Upstream commit 2a76f900d17dcb9e8322770ac9bcae34517805b3 ] + +As send_mbox_msg is invoked by 3 functions: hinic3_send_mbox_to_mgmt, +hinic3_response_mbox_to_mgmt and hinic3_send_mbox_to_mgmt_no_ack, only +hinic3_response_mbox_to_mgmt does not has mutex and the other two has +mbox->mbox_send_lock because their send actions are mutually exclusive. + As hinic3_response_mbox_to_mgmt does not conflict with them in send +actions but in mailbox resources, add the new mutex(msg_send_lock) in +send_mbox_msg to ensure message concurrency. + + Besdies, in mbox_send_seg change FIELD_PREP to FIELD_GET in +MBOX_STATUS_FINISHED and MBOX_STATUS_SUCCESS to be more reasonable. + +Co-developed-by: Zhu Yikai +Signed-off-by: Zhu Yikai +Signed-off-by: Fan Gong +Link: https://patch.msgid.link/d83f7f6eb4b5e94642a558fab75d61292c347e48.1773062356.git.zhuyikai1@h-partners.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c | 9 +++++++-- + drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h | 4 ++++ + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +index cf67e26acece2..dea6b2e44ac25 100644 +--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c ++++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +@@ -50,9 +50,9 @@ + #define MBOX_WB_STATUS_NOT_FINISHED 0x00 + + #define MBOX_STATUS_FINISHED(wb) \ +- ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED) ++ ((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED) + #define MBOX_STATUS_SUCCESS(wb) \ +- ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) == \ ++ ((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) == \ + MBOX_WB_STATUS_FINISHED_SUCCESS) + #define MBOX_STATUS_ERRCODE(wb) \ + ((wb) & MBOX_WB_ERROR_CODE_MASK) +@@ -380,6 +380,7 @@ static int hinic3_mbox_pre_init(struct hinic3_hwdev *hwdev, + { + mbox->hwdev = hwdev; + mutex_init(&mbox->mbox_send_lock); ++ mutex_init(&mbox->mbox_seg_send_lock); + spin_lock_init(&mbox->mbox_lock); + + mbox->workq = create_singlethread_workqueue(HINIC3_MBOX_WQ_NAME); +@@ -684,6 +685,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd, + else + rsp_aeq_id = 0; + ++ mutex_lock(&mbox->mbox_seg_send_lock); ++ + if (dst_func == MBOX_MGMT_FUNC_ID && + !(hwdev->features[0] & MBOX_COMM_F_MBOX_SEGMENT)) { + err = mbox_prepare_dma_msg(mbox, ack_type, &dma_msg, +@@ -737,6 +740,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd, + } + + err_send: ++ mutex_unlock(&mbox->mbox_seg_send_lock); ++ + return err; + } + +diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +index e71629e950863..5954c88e0388f 100644 +--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h ++++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +@@ -114,6 +114,10 @@ struct hinic3_mbox { + struct hinic3_hwdev *hwdev; + /* lock for send mbox message and ack message */ + struct mutex mbox_send_lock; ++ /* lock for send message transmission. ++ * The lock hierarchy is mbox_send_lock -> mbox_seg_send_lock. ++ */ ++ struct mutex mbox_seg_send_lock; + struct hinic3_send_mbox send_mbox; + struct mbox_dma_queue sync_msg_queue; + struct mbox_dma_queue async_msg_queue; +-- +2.53.0 + diff --git a/queue-6.18/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch b/queue-6.18/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch new file mode 100644 index 0000000000..fe8b764b27 --- /dev/null +++ b/queue-6.18/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch @@ -0,0 +1,65 @@ +From ff8bb8a3571f9e004fc88d93f8e127675aeb0103 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 16:16:18 +0100 +Subject: hwmon: (asus-ec-sensors )add ROG CROSSHAIR X670E EXTREME + +From: Timothy C. Sweeney-Fanelli + +[ Upstream commit ab4b7071ae0a831e4c2fd45c626c3b1d66cc1201 ] + +Add support for ROG CROSSHAIR X670E EXTREME + +Signed-off-by: Timothy C. Sweeney-Fanelli +Signed-off-by: Eugene Shalygin +Link: https://lore.kernel.org/r/20260215151743.20138-3-eugene.shalygin@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + Documentation/hwmon/asus_ec_sensors.rst | 1 + + drivers/hwmon/asus-ec-sensors.c | 11 +++++++++++ + 2 files changed, 12 insertions(+) + +diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst +index a5a58c00c3223..75587aa9a1ae6 100644 +--- a/Documentation/hwmon/asus_ec_sensors.rst ++++ b/Documentation/hwmon/asus_ec_sensors.rst +@@ -20,6 +20,7 @@ Supported boards: + * ROG CROSSHAIR VIII FORMULA + * ROG CROSSHAIR VIII HERO + * ROG CROSSHAIR VIII IMPACT ++ * ROG CROSSHAIR X670E EXTREME + * ROG CROSSHAIR X670E HERO + * ROG CROSSHAIR X670E GENE + * ROG MAXIMUS XI HERO +diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c +index 95c50d3a788ce..1c9bd221fd8c1 100644 +--- a/drivers/hwmon/asus-ec-sensors.c ++++ b/drivers/hwmon/asus-ec-sensors.c +@@ -434,6 +434,15 @@ static const struct ec_board_info board_info_crosshair_viii_impact = { + .family = family_amd_500_series, + }; + ++static const struct ec_board_info board_info_crosshair_x670e_extreme = { ++ .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | ++ SENSOR_TEMP_MB | SENSOR_TEMP_VRM | ++ SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_WATER_IN | ++ SENSOR_TEMP_WATER_OUT, ++ .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, ++ .family = family_amd_600_series, ++}; ++ + static const struct ec_board_info board_info_crosshair_x670e_gene = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_T_SENSOR | +@@ -758,6 +767,8 @@ static const struct dmi_system_id dmi_table[] = { + &board_info_crosshair_viii_hero), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT", + &board_info_crosshair_viii_impact), ++ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E EXTREME", ++ &board_info_crosshair_x670e_extreme), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE", + &board_info_crosshair_x670e_gene), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", +-- +2.53.0 + diff --git a/queue-6.18/hwmon-gpd-fan-add-gpd-win-5.patch b/queue-6.18/hwmon-gpd-fan-add-gpd-win-5.patch new file mode 100644 index 0000000000..6d8d901985 --- /dev/null +++ b/queue-6.18/hwmon-gpd-fan-add-gpd-win-5.patch @@ -0,0 +1,43 @@ +From 702ad472af26c6b7563ad2c9a76822813148b711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 17:16:01 +0100 +Subject: hwmon: (gpd-fan) Add GPD Win 5 + +From: Antheas Kapenekakis + +[ Upstream commit 4853b53264869e51378cad7bf1556d4e8049d445 ] + +The GPD Win 5 is a new device by GPD with an AMD AI MAX 385/395 chip. +It uses the same fan control registers as the GPD Win Duo. This +information was provided by GPD. + +Signed-off-by: Antheas Kapenekakis +Link: https://lore.kernel.org/r/20260220161601.2344291-1-lkml@antheas.dev +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/gpd-fan.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c +index f81c3bc422f4c..d7cea846647b8 100644 +--- a/drivers/hwmon/gpd-fan.c ++++ b/drivers/hwmon/gpd-fan.c +@@ -199,6 +199,14 @@ static const struct dmi_system_id dmi_table[] = { + }, + .driver_data = &gpd_duo_drvdata, + }, ++ { ++ // GPD Win 5 with AMD AI MAX 395 ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "GPD"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "G1618-05"), ++ }, ++ .driver_data = &gpd_duo_drvdata, ++ }, + { + // GPD Pocket 4 + .matches = { +-- +2.53.0 + diff --git a/queue-6.18/hwmon-lm90-add-lock-protection-to-lm90_alert.patch b/queue-6.18/hwmon-lm90-add-lock-protection-to-lm90_alert.patch new file mode 100644 index 0000000000..590df9dbc1 --- /dev/null +++ b/queue-6.18/hwmon-lm90-add-lock-protection-to-lm90_alert.patch @@ -0,0 +1,58 @@ +From 9481613e86c23b984150e7d6ebd3c918dce12b96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 14:41:00 -0700 +Subject: hwmon: (lm90) Add lock protection to lm90_alert + +From: Guenter Roeck + +[ Upstream commit 873e919e3101063a7a75989510ccfc125a4391cf ] + +Sashiko reports: + +lm90_alert() executes in the smbus alert context and calls +lm90_update_confreg() to disable the hardware alert line, without +acquiring hwmon_lock. + +Concurrently, sysfs write operations (such as lm90_write_convrate) hold +the hwmon_lock, temporarily modify data->config, and then restore it. + +If an alert interrupt occurs concurrently with a sysfs write, the sysfs +path will overwrite the alert handler's modifications to data->config +and the hardware register. + +This unintentionally re-enables the hardware alert line while the alarm is +still active, causing an interrupt storm. + +Add the missing lock to lm90_alert() to solve the problem. + +Fixes: 7a1d220ccb0cc ("hwmon: (lm90) Introduce function to update configuration register") +Reported-by: Sashiko +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/lm90.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c +index 41ee2309fe8a2..a465a8a7ef5af 100644 +--- a/drivers/hwmon/lm90.c ++++ b/drivers/hwmon/lm90.c +@@ -2963,6 +2963,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + */ + struct lm90_data *data = i2c_get_clientdata(client); + ++ hwmon_lock(data->hwmon_dev); + if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) && + (data->current_alarms & data->alert_alarms)) { + if (!(data->config & 0x80)) { +@@ -2972,6 +2973,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + schedule_delayed_work(&data->alert_work, + max_t(int, HZ, msecs_to_jiffies(data->update_interval))); + } ++ hwmon_unlock(data->hwmon_dev); + } else { + dev_dbg(&client->dev, "Everything OK\n"); + } +-- +2.53.0 + diff --git a/queue-6.18/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch b/queue-6.18/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch new file mode 100644 index 0000000000..2193a05069 --- /dev/null +++ b/queue-6.18/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch @@ -0,0 +1,108 @@ +From b875597af850a04b2e04f7261f27a5abd1bb1418 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 14:31:49 -0700 +Subject: hwmon: (lm90) Stop work before releasing hwmon device + +From: Guenter Roeck + +[ Upstream commit b09a45601094c7f4ec4db8090b825fa61e169d93 ] + +Sashiko reports: + +In lm90_probe(), the devm action to cancel the alert_work and report_work +(lm90_restore_conf) is registered in lm90_init_client() before +devm_hwmon_device_register_with_info() is called. + +Because devm executes cleanup actions in reverse order during module +unbind or probe failure, the hwmon device is unregistered and freed first. + +If lm90_alert_work() or lm90_report_alarms() runs in the window between +the hwmon device being freed and the delayed works being cancelled, +lm90_update_alarms() will dereference the freed data->hwmon_dev here. + +Fix the problem by canceling the workers separately after registering +the hwmon device and before registering the interrupt handler. This ensures +that the workers are canceled after interrupts are disabled and before +the hwmon device is released. Add "shutdown" flag to indicate that device +shutdown is in progress to prevent workers from being re-armed. + +Fixes: f6d0775119fb9 ("hwmon: (lm90) Rework alarm/status handling") +Reported-by: Sashiko +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/lm90.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c +index c1f528e292f3d..41ee2309fe8a2 100644 +--- a/drivers/hwmon/lm90.c ++++ b/drivers/hwmon/lm90.c +@@ -738,6 +738,7 @@ struct lm90_data { + struct mutex update_lock; + struct delayed_work alert_work; + struct work_struct report_work; ++ bool shutdown; /* true if shutting down */ + bool valid; /* true if register values are valid */ + bool alarms_valid; /* true if status register values are valid */ + unsigned long last_updated; /* in jiffies */ +@@ -1156,6 +1157,9 @@ static void lm90_report_alarms(struct work_struct *work) + + static int lm90_update_alarms_locked(struct lm90_data *data, bool force) + { ++ if (data->shutdown) ++ return 0; ++ + if (force || !data->alarms_valid || + time_after(jiffies, data->alarms_updated + msecs_to_jiffies(data->update_interval))) { + struct i2c_client *client = data->client; +@@ -2600,15 +2604,23 @@ static void lm90_restore_conf(void *_data) + struct lm90_data *data = _data; + struct i2c_client *client = data->client; + +- cancel_delayed_work_sync(&data->alert_work); +- cancel_work_sync(&data->report_work); +- + /* Restore initial configuration */ + if (data->flags & LM90_HAVE_CONVRATE) + lm90_write_convrate(data, data->convrate_orig); + lm90_write_reg(client, LM90_REG_CONFIG1, data->config_orig); + } + ++static void lm90_stop_work(void *_data) ++{ ++ struct lm90_data *data = _data; ++ ++ hwmon_lock(data->hwmon_dev); ++ data->shutdown = true; ++ hwmon_unlock(data->hwmon_dev); ++ cancel_delayed_work_sync(&data->alert_work); ++ cancel_work_sync(&data->report_work); ++} ++ + static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) + { + struct device_node *np = client->dev.of_node; +@@ -2919,6 +2931,10 @@ static int lm90_probe(struct i2c_client *client) + + data->hwmon_dev = hwmon_dev; + ++ err = devm_add_action_or_reset(&client->dev, lm90_stop_work, data); ++ if (err) ++ return err; ++ + if (client->irq) { + dev_dbg(dev, "IRQ: %d\n", client->irq); + err = devm_request_threaded_irq(dev, client->irq, +@@ -2947,7 +2963,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + */ + struct lm90_data *data = i2c_get_clientdata(client); + +- if ((data->flags & LM90_HAVE_BROKEN_ALERT) && ++ if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) && + (data->current_alarms & data->alert_alarms)) { + if (!(data->config & 0x80)) { + dev_dbg(&client->dev, "Disabling ALERT#\n"); +-- +2.53.0 + diff --git a/queue-6.18/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch b/queue-6.18/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch new file mode 100644 index 0000000000..ba1755b247 --- /dev/null +++ b/queue-6.18/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch @@ -0,0 +1,49 @@ +From 1175a17086c6e41563bb2ce0c6ae2865768630be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 00:17:27 +0000 +Subject: hwmon: (nct6683) Add customer ID for ASRock B650I Lightning WiFi + +From: Petr Klotz + +[ Upstream commit ff708b549c4dbecb308fa97e360a8fe0b2f89309 ] + +The ASRock B650I Lightning WiFi motherboard uses an NCT6686D chip with a +customer ID of 0x1633. Without this ID, the nct6683 driver fails to +recognize the hardware on this board, preventing hardware monitoring +from working. + +Add NCT6683_CUSTOMER_ID_ASROCK6 (0x1633) to the list of supported customer +IDs and update the probe function to handle it + +Signed-off-by: Petr Klotz +Link: https://lore.kernel.org/r/20260412000911.9063-2-pklotz0@protonmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/nct6683.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c +index 4a83804140386..0581770380cc5 100644 +--- a/drivers/hwmon/nct6683.c ++++ b/drivers/hwmon/nct6683.c +@@ -182,6 +182,7 @@ superio_exit(int ioreg) + #define NCT6683_CUSTOMER_ID_ASROCK3 0x1631 + #define NCT6683_CUSTOMER_ID_ASROCK4 0x163e + #define NCT6683_CUSTOMER_ID_ASROCK5 0x1621 ++#define NCT6683_CUSTOMER_ID_ASROCK6 0x1633 + + #define NCT6683_REG_BUILD_YEAR 0x604 + #define NCT6683_REG_BUILD_MONTH 0x605 +@@ -1245,6 +1246,8 @@ static int nct6683_probe(struct platform_device *pdev) + break; + case NCT6683_CUSTOMER_ID_ASROCK5: + break; ++ case NCT6683_CUSTOMER_ID_ASROCK6: ++ break; + default: + if (!force) + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.18/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch b/queue-6.18/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch new file mode 100644 index 0000000000..4e12a3c2f8 --- /dev/null +++ b/queue-6.18/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch @@ -0,0 +1,73 @@ +From 1cb6efc92ce8e664337521415f27c8ed1db07a5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:02:08 +0800 +Subject: hwmon: (pmbus/isl68137) Add support for Renesas RAA228942 and + RAA228943 + +From: Dawei Liu + +[ Upstream commit 7c760db74c9f30da7281c7f450d0676ec78ec3e6 ] + +Add I2C device IDs for Renesas RAA228942 and RAA228943. + +At the Linux PMBus hwmon interface level currently supported by this +driver, these devices are compatible with the existing 2-rail non-TC +controllers, so devicetree will use fallback compatibles and no +dedicated OF match entries are needed. + +Signed-off-by: Dawei Liu +Link: https://lore.kernel.org/r/20260325090208.857-3-dawei.liu.jy@renesas.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + Documentation/hwmon/isl68137.rst | 20 ++++++++++++++++++++ + drivers/hwmon/pmbus/isl68137.c | 2 ++ + 2 files changed, 22 insertions(+) + +diff --git a/Documentation/hwmon/isl68137.rst b/Documentation/hwmon/isl68137.rst +index 5bc029c98383d..8467053c1d461 100644 +--- a/Documentation/hwmon/isl68137.rst ++++ b/Documentation/hwmon/isl68137.rst +@@ -394,6 +394,26 @@ Supported chips: + + Provided by Renesas upon request and NDA + ++ * Renesas RAA228942 ++ ++ Prefix: 'raa228942' ++ ++ Addresses scanned: - ++ ++ Datasheet: ++ ++ Provided by Renesas upon request and NDA ++ ++ * Renesas RAA228943 ++ ++ Prefix: 'raa228943' ++ ++ Addresses scanned: - ++ ++ Datasheet: ++ ++ Provided by Renesas upon request and NDA ++ + * Renesas RAA229001 + + Prefix: 'raa229001' +diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c +index ab54184b4878e..46935151d2789 100644 +--- a/drivers/hwmon/pmbus/isl68137.c ++++ b/drivers/hwmon/pmbus/isl68137.c +@@ -485,6 +485,8 @@ static const struct i2c_device_id raa_dmpvr_id[] = { + {"raa228228", raa_dmpvr2_2rail_nontc}, + {"raa228244", raa_dmpvr2_2rail_nontc}, + {"raa228246", raa_dmpvr2_2rail_nontc}, ++ {"raa228942", raa_dmpvr2_2rail_nontc}, ++ {"raa228943", raa_dmpvr2_2rail_nontc}, + {"raa229001", raa_dmpvr2_2rail}, + {"raa229004", raa_dmpvr2_2rail}, + {"raa229621", raa_dmpvr2_2rail}, +-- +2.53.0 + diff --git a/queue-6.18/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch b/queue-6.18/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch new file mode 100644 index 0000000000..9ab7ccde58 --- /dev/null +++ b/queue-6.18/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch @@ -0,0 +1,36 @@ +From cb525415a1bee7de1b261afb737296b6a58d053e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 13:34:08 +0530 +Subject: i2c: usbio: Add ACPI device-id for NVL platforms + +From: Arun T + +[ Upstream commit e43f2df330a1b87c97235e4faade860d15787735 ] + +Add device IDs of Nova Lake into i2c-usbio support list + +Signed-off-by: Arun T +Reviewed-by: Vadillo Miguel +Reviewed-by: Sakari Ailus +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260410080408.562311-1-arun.t@intel.com +Signed-off-by: Sasha Levin +--- + drivers/i2c/busses/i2c-usbio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/i2c/busses/i2c-usbio.c b/drivers/i2c/busses/i2c-usbio.c +index e7799abf67877..259754e5fd05b 100644 +--- a/drivers/i2c/busses/i2c-usbio.c ++++ b/drivers/i2c/busses/i2c-usbio.c +@@ -29,6 +29,7 @@ static const struct acpi_device_id usbio_i2c_acpi_hids[] = { + { "INTC10B6" }, /* LNL */ + { "INTC10D2" }, /* MTL-CVF */ + { "INTC10E3" }, /* PTL */ ++ { "INTC1118" }, /* NVL */ + { } + }; + +-- +2.53.0 + diff --git a/queue-6.18/i3c-master-move-bus_init-error-suppression.patch b/queue-6.18/i3c-master-move-bus_init-error-suppression.patch new file mode 100644 index 0000000000..435c13bbba --- /dev/null +++ b/queue-6.18/i3c-master-move-bus_init-error-suppression.patch @@ -0,0 +1,98 @@ +From 861f0b4a77ea8e1bf6daaae6283b0332144b7aa9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:31 +0100 +Subject: i3c: master: Move bus_init error suppression + +From: Jorge Marques + +[ Upstream commit 49775afa983e3e5ce8e7d00ee241791073be214d ] + +Prepare to fix improper Mx positive error propagation in later commits +by handling Mx error codes where the i3c_ccc_cmd command is allocated. +The CCC DISEC to broadcast address is invoked with +i3c_master_enec_disec_locked() and yields error I3C_ERROR_M2 if there +are no devices active on the bus. This is expected at the bus +initialization stage, where it is not known yet that there are no active +devices on the bus. Add bool suppress_m2 argument to +i3c_master_enec_disec_locked() and update the call site at +i3c_master_bus_init() with the exact corner case to not require +propagating positive Mx error codes. Other call site should not suppress +the error code, for example, if a driver requests to peripheral to +disable events and the transfer is not acknowledged, this is an error +and should not proceed. + +Reviewed-by: Frank Li +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-3-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 425e36b36009b..14093521df0ae 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -979,7 +979,8 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master) + EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); + + static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, +- u8 addr, bool enable, u8 evts) ++ u8 addr, bool enable, u8 evts, ++ bool suppress_m2) + { + struct i3c_ccc_events *events; + struct i3c_ccc_cmd_dest dest; +@@ -999,6 +1000,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + i3c_ccc_cmd_dest_cleanup(&dest); + ++ if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2) ++ ret = 0; ++ + return ret; + } + +@@ -1019,7 +1023,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, false, evts); ++ return i3c_master_enec_disec_locked(master, addr, false, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + +@@ -1040,7 +1044,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, true, evts); ++ return i3c_master_enec_disec_locked(master, addr, true, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + +@@ -1999,11 +2003,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + +- /* Disable all slave events before starting DAA. */ +- ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, +- I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +- I3C_CCC_EVENT_HJ); +- if (ret && ret != I3C_ERROR_M2) ++ /* ++ * Disable all slave events before starting DAA. When no active device ++ * is on the bus, returns Mx error code M2, this error is ignored. ++ */ ++ ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false, ++ I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | ++ I3C_CCC_EVENT_HJ, true); ++ if (ret) + goto err_bus_cleanup; + + /* +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-6.18/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..4d45580062 --- /dev/null +++ b/queue-6.18/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From ec022f1b6d86f8f4cf289aecdabd26c9ba9fafa3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index 9fc8681cc58ea..270f5a00ece3a 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -537,14 +537,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + int ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-setting-rss-vsi-hash-for-e830.patch b/queue-6.18/ice-fix-setting-rss-vsi-hash-for-e830.patch new file mode 100644 index 0000000000..2c82ceb01a --- /dev/null +++ b/queue-6.18/ice-fix-setting-rss-vsi-hash-for-e830.patch @@ -0,0 +1,56 @@ +From 28fb6e8567e13051c9e8784147fc983ef78c9d3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:14 -0700 +Subject: ice: fix setting RSS VSI hash for E830 + +From: Marcin Szycik + +[ Upstream commit b3cda96feb60d91fe88d52b974ff110dcfa91239 ] + +ice_set_rss_hfunc() performs a VSI update, in which it sets hashing +function, leaving other VSI options unchanged. However, ::q_opt_flags is +mistakenly set to the value of another field, instead of its original +value, probably due to a typo. What happens next is hardware-dependent: + +On E810, only the first bit is meaningful (see +ICE_AQ_VSI_Q_OPT_PE_FLTR_EN) and can potentially end up in a different +state than before VSI update. + +On E830, some of the remaining bits are not reserved. Setting them +to some unrelated values can cause the firmware to reject the update +because of invalid settings, or worse - succeed. + +Reproducer: + sudo ethtool -X $PF1 equal 8 + +Output in dmesg: + Failed to configure RSS hash for VSI 6, error -5 + +Fixes: 352e9bf23813 ("ice: enable symmetric-xor RSS for Toeplitz hash function") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Signed-off-by: Marcin Szycik +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-5-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index c064c3653c540..7ecc643d59517 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -8069,7 +8069,7 @@ int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc) + ctx->info.q_opt_rss |= + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hfunc); + ctx->info.q_opt_tc = vsi->info.q_opt_tc; +- ctx->info.q_opt_flags = vsi->info.q_opt_rss; ++ ctx->info.q_opt_flags = vsi->info.q_opt_flags; + + err = ice_update_vsi(hw, vsi->idx, ctx, NULL); + if (err) { +-- +2.53.0 + diff --git a/queue-6.18/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch b/queue-6.18/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch new file mode 100644 index 0000000000..4b9c1b746d --- /dev/null +++ b/queue-6.18/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch @@ -0,0 +1,91 @@ +From 0721297661c74afedc0c13be8073b7be6b37299c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:12 -0700 +Subject: idpf: fix read_dev_clk_lock spinlock init in idpf_ptp_init() + +From: Emil Tantilov + +[ Upstream commit da4f76b6a84ede14a71282ef841768299ead0221 ] + +In idpf_ptp_init(), read_dev_clk_lock is initialized after +ptp_schedule_worker() had already been called (and after +idpf_ptp_settime64() could reach the lock). The PTP aux worker +fires immediately upon scheduling and can call into +idpf_ptp_read_src_clk_reg_direct(), which takes +spin_lock(&ptp->read_dev_clk_lock) on an uninitialized lock, triggering +the lockdep "non-static key" warning: + +[12973.796587] idpf 0000:83:00.0: Device HW Reset initiated +[12974.094507] INFO: trying to register non-static key. +... +[12974.097208] Call Trace: +[12974.097213] +[12974.097218] dump_stack_lvl+0x93/0xe0 +[12974.097234] register_lock_class+0x4c4/0x4e0 +[12974.097249] ? __lock_acquire+0x427/0x2290 +[12974.097259] __lock_acquire+0x98/0x2290 +[12974.097272] lock_acquire+0xc6/0x310 +[12974.097281] ? idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097311] ? lockdep_hardirqs_on_prepare+0xde/0x190 +[12974.097318] ? finish_task_switch.isra.0+0xd2/0x350 +[12974.097330] ? __pfx_ptp_aux_kworker+0x10/0x10 [ptp] +[12974.097343] _raw_spin_lock+0x30/0x40 +[12974.097353] ? idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097373] idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097391] ? kthread_worker_fn+0x88/0x3d0 +[12974.097404] ? kthread_worker_fn+0x4e/0x3d0 +[12974.097411] idpf_ptp_update_cached_phctime+0x26/0x120 [idpf] +[12974.097428] ? _raw_spin_unlock_irq+0x28/0x50 +[12974.097436] idpf_ptp_do_aux_work+0x15/0x20 [idpf] +[12974.097454] ptp_aux_kworker+0x20/0x40 [ptp] +[12974.097464] kthread_worker_fn+0xd5/0x3d0 +[12974.097474] ? __pfx_kthread_worker_fn+0x10/0x10 +[12974.097482] kthread+0xf4/0x130 +[12974.097489] ? __pfx_kthread+0x10/0x10 +[12974.097498] ret_from_fork+0x32c/0x410 +[12974.097512] ? __pfx_kthread+0x10/0x10 +[12974.097519] ret_from_fork_asm+0x1a/0x30 +[12974.097540] + +Move the call to spin_lock_init() up a bit to make sure read_dev_clk_lock +is not touched before it's been initialized. + +Fixes: 5cb8805d2366 ("idpf: negotiate PTP capabilities and get PTP clock") +Signed-off-by: Emil Tantilov +Reviewed-by: Madhu Chittim +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Samuel Salin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-3-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/idpf/idpf_ptp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +index 0a8b50350b860..31c5593550e1a 100644 +--- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c ++++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +@@ -949,6 +949,8 @@ int idpf_ptp_init(struct idpf_adapter *adapter) + goto free_ptp; + } + ++ spin_lock_init(&adapter->ptp->read_dev_clk_lock); ++ + err = idpf_ptp_create_clock(adapter); + if (err) + goto free_ptp; +@@ -974,8 +976,6 @@ int idpf_ptp_init(struct idpf_adapter *adapter) + goto remove_clock; + } + +- spin_lock_init(&adapter->ptp->read_dev_clk_lock); +- + pci_dbg(adapter->pdev, "PTP init successful\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/iio-abi-fix-current_trigger-description.patch b/queue-6.18/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..0a4ef16911 --- /dev/null +++ b/queue-6.18/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From 9068b48ff5fb988f8ff86d0b376d2febe67b1b45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index 89b4740dcfa14..b191e4ff834a3 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1412,7 +1412,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-6.18/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch b/queue-6.18/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch new file mode 100644 index 0000000000..9a18b86170 --- /dev/null +++ b/queue-6.18/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch @@ -0,0 +1,39 @@ +From a605d6aee6fd66b677ffb749b5cf682da667eb8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:36:26 +0100 +Subject: iio: imu: st_lsm6dsx: Add ACPI ID for SHIFT13mi gyroscope + +From: Milan Misic + +[ Upstream commit 7913c1de9c3cbe3018fc29ce25a4d462ac2eaa82 ] + +The SHIFT13mi or SHIFTbook tablet device by the German manufacturer +SHIFT contains an STM LSM6DSO IMU declared in the DSDT with the +hardware ID SMOCF00. Add this ID to the ACPI match table so that the +driver binds correctly to this device. + +WHO_AM_I register returns 0x6c, confirming LSM6DSO. + +Signed-off-by: Milan Misic +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +index 7c933218036b8..b2a7c2eaf50dc 100644 +--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c ++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +@@ -144,6 +144,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); + + static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { + { "SMO8B30", ST_LSM6DS3TRC_ID, }, ++ { "SMOCF00", ST_LSM6DSO_ID, }, + { } + }; + MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); +-- +2.53.0 + diff --git a/queue-6.18/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch b/queue-6.18/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch new file mode 100644 index 0000000000..5bad7c2034 --- /dev/null +++ b/queue-6.18/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch @@ -0,0 +1,149 @@ +From 07223de5a9ef7d5217dc758fed5b08ccb064e546 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 13:06:45 +0100 +Subject: ima: Define and use a digest_size field in the ima_algo_desc + structure + +From: Roberto Sassu + +[ Upstream commit a74d7197ebe5b1b8028911d47e78c119d9aaf193 ] + +Add the digest_size field to the ima_algo_desc structure to determine the +digest size from the correct source. + +If the hash algorithm is among allocated PCR banks, take the value from the +TPM bank info (equal to the value from the crypto subsystem if the TPM +algorithm is supported by it; otherwise, not exceding the size of the +digest buffer in the tpm_digest structure, used by IMA). + +If the hash algorithm is SHA1, use the predefined value. Lastly, if the +hash algorithm is the default one but not among the PCR banks, take the +digest size from the crypto subsystem (the default hash algorithm is +checked when parsing the ima_hash= command line option). + +Finally, use the new information to correctly show the template digest in +ima_measurements_show() and ima_ascii_measurements_show(). + +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima.h | 1 + + security/integrity/ima/ima_crypto.c | 6 ++++++ + security/integrity/ima/ima_fs.c | 18 ++++++------------ + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h +index e3d71d8d56e38..cc147e1208852 100644 +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -53,6 +53,7 @@ extern atomic_t ima_setxattr_allowed_hash_algorithms; + struct ima_algo_desc { + struct crypto_shash *tfm; + enum hash_algo algo; ++ unsigned int digest_size; + }; + + /* set during initialization */ +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 8ae7821a65c26..c2a859710d20f 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -109,6 +109,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) + + int __init ima_init_crypto(void) + { ++ unsigned int digest_size; + enum hash_algo algo; + long rc; + int i; +@@ -147,7 +148,9 @@ int __init ima_init_crypto(void) + + for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { + algo = ima_tpm_chip->allocated_banks[i].crypto_id; ++ digest_size = ima_tpm_chip->allocated_banks[i].digest_size; + ima_algo_array[i].algo = algo; ++ ima_algo_array[i].digest_size = digest_size; + + /* unknown TPM algorithm */ + if (algo == HASH_ALGO__LAST) +@@ -183,12 +186,15 @@ int __init ima_init_crypto(void) + } + + ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; ++ ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE; + } + + if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && + ima_hash_algo_idx != ima_sha1_idx) { ++ digest_size = hash_digest_size[ima_hash_algo]; + ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; + ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; ++ ima_algo_array[ima_hash_algo_idx].digest_size = digest_size; + } + + return 0; +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 25970867f594e..0aa1a50e877c2 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v) + char *template_name; + u32 pcr, namelen, template_data_len; /* temporary fields */ + bool is_ima_template = false; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v) + ima_putc(m, &pcr, sizeof(e->pcr)); + + /* 2nd: template digest */ +- ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_putc(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3rd: template name size */ + namelen = !ima_canonical_fmt ? strlen(template_name) : +@@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + struct ima_queue_entry *qe = v; + struct ima_template_entry *e; + char *template_name; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + seq_printf(m, "%2d ", e->pcr); + + /* 2nd: template hash */ +- ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_print_digest(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3th: template name */ + seq_printf(m, " %s", template_name); +-- +2.53.0 + diff --git a/queue-6.18/io_uring-cancel-validate-opcode-for-ioring_async_can.patch b/queue-6.18/io_uring-cancel-validate-opcode-for-ioring_async_can.patch new file mode 100644 index 0000000000..44da0dfda0 --- /dev/null +++ b/queue-6.18/io_uring-cancel-validate-opcode-for-ioring_async_can.patch @@ -0,0 +1,53 @@ +From 809781b561b618c495cad0c3a144822bf9036c52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:51:13 +0330 +Subject: io_uring/cancel: validate opcode for IORING_ASYNC_CANCEL_OP + +From: Amir Mohammad Jahangirzad + +[ Upstream commit 85a58309c0d5b5f5a4b65658312ceaf2c34c9bbf ] + +io_async_cancel_prep() reads the opcode selector from sqe->len and +stores it in cancel->opcode, which is an 8-bit field. Since sqe->len +is a 32-bit value, values larger than U8_MAX are implicitly truncated. + +This can cause unintended opcode matches when the truncated value +corresponds to a valid io_uring opcode. For example, submitting a value +such as 0x10b will be truncated to 0x0b (IORING_OP_TIMEOUT), allowing a +cancel request to match operations it did not intend to target. +Validate the opcode value before assigning it to the 8-bit field and +reject values outside the valid io_uring opcode range. + +Signed-off-by: Amir Mohammad Jahangirzad +Link: https://patch.msgid.link/20260331232113.615972-1-a.jahangirzad@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index 64b51e82baa24..7c4ad19ae099e 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -155,9 +155,16 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + cancel->fd = READ_ONCE(sqe->fd); + } + if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ u32 op; ++ + if (cancel->flags & IORING_ASYNC_CANCEL_ANY) + return -EINVAL; +- cancel->opcode = READ_ONCE(sqe->len); ++ ++ op = READ_ONCE(sqe->len); ++ if (op >= IORING_OP_LAST) ++ return -EINVAL; ++ ++ cancel->opcode = op; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch b/queue-6.18/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch new file mode 100644 index 0000000000..23782971d1 --- /dev/null +++ b/queue-6.18/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch @@ -0,0 +1,60 @@ +From db7a77e6bf2063c85fd9d70dfc3062dd8b20b651 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 13:14:54 -0600 +Subject: io_uring/rsrc: unify nospec indexing for direct descriptors + +From: Jens Axboe + +[ Upstream commit 53262c91f7b81f96495ff24e9d1fa8b1632e69c8 ] + +For file updates, the node reset isn't capping the value via +array_index_nospec() like the other paths do. Ensure it's all sane and +have the update path do the proper capping as well. + +Reviewed-by: Gabriel Krisman Bertazi +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/rsrc.c | 3 +++ + io_uring/rsrc.h | 9 +++++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c +index dc87c6a86e346..720bee15c95b4 100644 +--- a/io_uring/rsrc.c ++++ b/io_uring/rsrc.c +@@ -251,6 +251,9 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx, + continue; + + i = up->offset + done; ++ if (i >= ctx->file_table.data.nr) ++ break; ++ i = array_index_nospec(i, ctx->file_table.data.nr); + if (io_reset_rsrc_node(ctx, &ctx->file_table.data, i)) + io_file_bitmap_clear(&ctx->file_table, i); + +diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h +index a3ca6ba66596f..dffa273276ece 100644 +--- a/io_uring/rsrc.h ++++ b/io_uring/rsrc.h +@@ -105,10 +105,15 @@ static inline void io_put_rsrc_node(struct io_ring_ctx *ctx, struct io_rsrc_node + } + + static inline bool io_reset_rsrc_node(struct io_ring_ctx *ctx, +- struct io_rsrc_data *data, int index) ++ struct io_rsrc_data *data, ++ unsigned int index) + { +- struct io_rsrc_node *node = data->nodes[index]; ++ struct io_rsrc_node *node; + ++ if (index >= data->nr) ++ return false; ++ index = array_index_nospec(index, data->nr); ++ node = data->nodes[index]; + if (!node) + return false; + io_put_rsrc_node(ctx, node); +-- +2.53.0 + diff --git a/queue-6.18/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch b/queue-6.18/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch new file mode 100644 index 0000000000..df11c16801 --- /dev/null +++ b/queue-6.18/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch @@ -0,0 +1,112 @@ +From e5e2db0a8c401da83c2061b3d709f7f7d4dded79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 15:46:16 +0200 +Subject: io_uring: take page references for NOMMU pbuf_ring mmaps + +From: Greg Kroah-Hartman + +[ Upstream commit d0be8884f56b0b800cd8966e37ce23417cd5044e ] + +Under !CONFIG_MMU, io_uring_get_unmapped_area() returns the kernel +virtual address of the io_mapped_region's backing pages directly; +the user's VMA aliases the kernel allocation. io_uring_mmap() then +just returns 0 -- it takes no page references. + +The CONFIG_MMU path uses vm_insert_pages(), which takes a reference on +each inserted page. Those references are released when the VMA is torn +down (zap_pte_range -> put_page). io_free_region() -> release_pages() +drops the io_uring-side references, but the pages survive until munmap +drops the VMA-side references. + +Under NOMMU there are no VMA-side references. io_unregister_pbuf_ring -> +io_put_bl -> io_free_region -> release_pages drops the only references +and the pages return to the buddy allocator while the user's VMA still +has vm_start pointing into them. The user can then write into whatever +the allocator hands out next. + +Mirror the MMU lifetime: take get_page references in io_uring_mmap() and +release them via vm_ops->close. NOMMU's delete_vma() calls vma_close() +which runs ->close on munmap. + +This also incidentally addresses the duplicate-vm_start case: two mmaps +of SQ_RING and CQ_RING resolve to the same ctx->ring_region pointer. +With page refs taken per mmap, the second mmap takes its own refs and +the pages survive until both mmaps are closed. The nommu rb-tree BUG_ON +on duplicate vm_start is a separate mm/nommu.c concern (it should share +the existing region rather than BUG), but the page lifetime is now +correct. + +Cc: Jens Axboe +Reported-by: Anthropic +Assisted-by: gkh_clanker_t1000 +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026042115-body-attention-d15b@gregkh +[axboe: get rid of region lookup, just iterate pages in vma] +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/memmap.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 45 insertions(+), 1 deletion(-) + +diff --git a/io_uring/memmap.c b/io_uring/memmap.c +index add03ca75cb90..42b1587b7602e 100644 +--- a/io_uring/memmap.c ++++ b/io_uring/memmap.c +@@ -392,9 +392,53 @@ unsigned long io_uring_get_unmapped_area(struct file *filp, unsigned long addr, + + #else /* !CONFIG_MMU */ + ++/* ++ * Drop the pages that were initially referenced and added in ++ * io_uring_mmap(). We cannot have had a mremap() as that isn't supported, ++ * hence the vma should be identical to the one we initially referenced and ++ * mapped, and partial unmaps and splitting isn't possible on a file backed ++ * mapping. ++ */ ++static void io_uring_nommu_vm_close(struct vm_area_struct *vma) ++{ ++ unsigned long index; ++ ++ for (index = vma->vm_start; index < vma->vm_end; index += PAGE_SIZE) ++ put_page(virt_to_page((void *) index)); ++} ++ ++static const struct vm_operations_struct io_uring_nommu_vm_ops = { ++ .close = io_uring_nommu_vm_close, ++}; ++ + int io_uring_mmap(struct file *file, struct vm_area_struct *vma) + { +- return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -EINVAL; ++ struct io_ring_ctx *ctx = file->private_data; ++ struct io_mapped_region *region; ++ unsigned long i; ++ ++ if (!is_nommu_shared_mapping(vma->vm_flags)) ++ return -EINVAL; ++ ++ guard(mutex)(&ctx->mmap_lock); ++ region = io_mmap_get_region(ctx, vma->vm_pgoff); ++ if (!region || !io_region_is_set(region)) ++ return -EINVAL; ++ ++ if ((vma->vm_end - vma->vm_start) != ++ (unsigned long) region->nr_pages << PAGE_SHIFT) ++ return -EINVAL; ++ ++ /* ++ * Pin the pages so io_free_region()'s release_pages() does not ++ * drop the last reference while this VMA exists. delete_vma() ++ * in mm/nommu.c calls vma_close() which runs ->close above. ++ */ ++ for (i = 0; i < region->nr_pages; i++) ++ get_page(region->pages[i]); ++ ++ vma->vm_ops = &io_uring_nommu_vm_ops; ++ return 0; + } + + unsigned int io_uring_nommu_mmap_capabilities(struct file *file) +-- +2.53.0 + diff --git a/queue-6.18/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch b/queue-6.18/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch new file mode 100644 index 0000000000..2e0d8eadea --- /dev/null +++ b/queue-6.18/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch @@ -0,0 +1,142 @@ +From 22c5bc2ff1651ae96b750f960f74f5ce52e58262 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 15:37:54 +0800 +Subject: iommu/amd: Fix illegal cap/mmio access in IOMMU debugfs + +From: Guanghui Feng + +[ Upstream commit 0e59645683b7b6fa20eceb21a6f420e4f7412943 ] + +In the current AMD IOMMU debugfs, when multiple processes simultaneously +access the IOMMU mmio/cap registers using the IOMMU debugfs, illegal +access issues can occur in the following execution flow: + +1. CPU1: Sets a valid access address using iommu_mmio/capability_write, +and verifies the access address's validity in iommu_mmio/capability_show + +2. CPU2: Sets an invalid address using iommu_mmio/capability_write + +3. CPU1: accesses the IOMMU mmio/cap registers based on the invalid +address, resulting in an illegal access. + +This patch modifies the execution process to first verify the address's +validity and then access it based on the same address, ensuring +correctness and robustness. + +Signed-off-by: Guanghui Feng +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/debugfs.c | 42 +++++++++++++++++-------------------- + 1 file changed, 19 insertions(+), 23 deletions(-) + +diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c +index 0b03e0622f67e..4e66473d7ceaf 100644 +--- a/drivers/iommu/amd/debugfs.c ++++ b/drivers/iommu/amd/debugfs.c +@@ -26,22 +26,19 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf, + { + struct seq_file *m = filp->private_data; + struct amd_iommu *iommu = m->private; +- int ret; +- +- iommu->dbg_mmio_offset = -1; ++ int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1; + + if (cnt > OFS_IN_SZ) + return -EINVAL; + +- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_mmio_offset); ++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset); + if (ret) + return ret; + +- if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) { +- iommu->dbg_mmio_offset = -1; +- return -EINVAL; +- } ++ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) ++ return -EINVAL; + ++ iommu->dbg_mmio_offset = dbg_mmio_offset; + return cnt; + } + +@@ -49,14 +46,16 @@ static int iommu_mmio_show(struct seq_file *m, void *unused) + { + struct amd_iommu *iommu = m->private; + u64 value; ++ int dbg_mmio_offset = iommu->dbg_mmio_offset; + +- if (iommu->dbg_mmio_offset < 0) { ++ if (dbg_mmio_offset < 0 || dbg_mmio_offset > ++ iommu->mmio_phys_end - sizeof(u64)) { + seq_puts(m, "Please provide mmio register's offset\n"); + return 0; + } + +- value = readq(iommu->mmio_base + iommu->dbg_mmio_offset); +- seq_printf(m, "Offset:0x%x Value:0x%016llx\n", iommu->dbg_mmio_offset, value); ++ value = readq(iommu->mmio_base + dbg_mmio_offset); ++ seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value); + + return 0; + } +@@ -67,23 +66,20 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf + { + struct seq_file *m = filp->private_data; + struct amd_iommu *iommu = m->private; +- int ret; +- +- iommu->dbg_cap_offset = -1; ++ int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1; + + if (cnt > OFS_IN_SZ) + return -EINVAL; + +- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_cap_offset); ++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset); + if (ret) + return ret; + + /* Capability register at offset 0x14 is the last IOMMU capability register. */ +- if (iommu->dbg_cap_offset > 0x14) { +- iommu->dbg_cap_offset = -1; ++ if (dbg_cap_offset > 0x14) + return -EINVAL; +- } + ++ iommu->dbg_cap_offset = dbg_cap_offset; + return cnt; + } + +@@ -91,21 +87,21 @@ static int iommu_capability_show(struct seq_file *m, void *unused) + { + struct amd_iommu *iommu = m->private; + u32 value; +- int err; ++ int err, dbg_cap_offset = iommu->dbg_cap_offset; + +- if (iommu->dbg_cap_offset < 0) { ++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) { + seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n"); + return 0; + } + +- err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + iommu->dbg_cap_offset, &value); ++ err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value); + if (err) { + seq_printf(m, "Not able to read capability register at 0x%x\n", +- iommu->dbg_cap_offset); ++ dbg_cap_offset); + return 0; + } + +- seq_printf(m, "Offset:0x%x Value:0x%08x\n", iommu->dbg_cap_offset, value); ++ seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch b/queue-6.18/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch new file mode 100644 index 0000000000..858fe9d80f --- /dev/null +++ b/queue-6.18/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch @@ -0,0 +1,104 @@ +From f06602e60530b97af38f4fbb45f867dd264118da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 15:37:53 +0800 +Subject: iommu/amd: Fix illegal device-id access in IOMMU debugfs + +From: Guanghui Feng + +[ Upstream commit e4172c5b53fba04fa48b13bc3afde809d0087a7f ] + +In the current AMD IOMMU debugFS, when multiple processes use the IOMMU +debugFS process simultaneously, illegal access issues can occur in the +following execution flow: + +1. CPU1: Sets a valid sbdf via devid_write, then checks the sbdf's +validity in execution flows such as devid_show, iommu_devtbl_show, +and iommu_irqtbl_show. + +2. CPU2: Sets an invalid sbdf via devid_write, at which point the sbdf +value is -1. + +3. CPU1: accesses the IOMMU device table, IRQ table, based on the +invalid SBDF value of -1, resulting in illegal access. + +This is especially problematic in monitoring scripts, where multiple +scripts may access debugFS simultaneously, and some scripts may +unexpectedly set invalid values, which triggers illegal access in +debugfs. + +This patch modifies the execution flow of devid_show, +iommu_devtbl_show, and iommu_irqtbl_show to ensure that these +processes determine the validity and access based on the +same device-id, thus guaranteeing correctness and robustness. + +Signed-off-by: Guanghui Feng +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/debugfs.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c +index 20b04996441d6..0b03e0622f67e 100644 +--- a/drivers/iommu/amd/debugfs.c ++++ b/drivers/iommu/amd/debugfs.c +@@ -197,10 +197,11 @@ static ssize_t devid_write(struct file *filp, const char __user *ubuf, + static int devid_show(struct seq_file *m, void *unused) + { + u16 devid; ++ int sbdf_shadow = sbdf; + +- if (sbdf >= 0) { +- devid = PCI_SBDF_TO_DEVID(sbdf); +- seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf), ++ if (sbdf_shadow >= 0) { ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); ++ seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf_shadow), + PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid)); + } else + seq_puts(m, "No or Invalid input provided\n"); +@@ -237,13 +238,14 @@ static int iommu_devtbl_show(struct seq_file *m, void *unused) + { + struct amd_iommu_pci_seg *pci_seg; + u16 seg, devid; ++ int sbdf_shadow = sbdf; + +- if (sbdf < 0) { ++ if (sbdf_shadow < 0) { + seq_puts(m, "Enter a valid device ID to 'devid' file\n"); + return 0; + } +- seg = PCI_SBDF_TO_SEGID(sbdf); +- devid = PCI_SBDF_TO_DEVID(sbdf); ++ seg = PCI_SBDF_TO_SEGID(sbdf_shadow); ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); + + for_each_pci_segment(pci_seg) { + if (pci_seg->id != seg) +@@ -336,19 +338,20 @@ static int iommu_irqtbl_show(struct seq_file *m, void *unused) + { + struct amd_iommu_pci_seg *pci_seg; + u16 devid, seg; ++ int sbdf_shadow = sbdf; + + if (!irq_remapping_enabled) { + seq_puts(m, "Interrupt remapping is disabled\n"); + return 0; + } + +- if (sbdf < 0) { ++ if (sbdf_shadow < 0) { + seq_puts(m, "Enter a valid device ID to 'devid' file\n"); + return 0; + } + +- seg = PCI_SBDF_TO_SEGID(sbdf); +- devid = PCI_SBDF_TO_DEVID(sbdf); ++ seg = PCI_SBDF_TO_SEGID(sbdf_shadow); ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); + + for_each_pci_segment(pci_seg) { + if (pci_seg->id != seg) +-- +2.53.0 + diff --git a/queue-6.18/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch b/queue-6.18/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch new file mode 100644 index 0000000000..7e6f8227df --- /dev/null +++ b/queue-6.18/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch @@ -0,0 +1,98 @@ +From 825d83850345349e7f6dd918dde3065d1f5e22fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:42:50 +0200 +Subject: iommu/amd: Invalidate IRT cache for DMA aliases + +From: Magnus Kalland + +[ Upstream commit 5aac28784dca6819e96e5f93e644cdee59e50f6e ] + +DMA aliasing causes interrupt remapping table entries (IRTEs) to be shared +between multiple device IDs. See commit 3c124435e8dd +("iommu/amd: Support multiple PCI DMA aliases in IRQ Remapping") for more +information on this. However, the AMD IOMMU driver currently invalidates +IRTE cache entries on a per-device basis whenever an IRTE is updated, not +for each alias. + +This approach leaves stale IRTE cache entries when an IRTE is cached under +one DMA alias but later updated and invalidated through a different alias. +In such cases, the original device ID is never invalidated, since it is +programmed via aliasing. + +This incoherency bug has been observed when IRTEs are cached for one +Non-Transparent Bridge (NTB) DMA alias, later updated via another. + +Fix this by invalidating the interrupt remapping table cache for all DMA +aliases when updating an IRTE. + +Co-developed-by: Lars B. Kristiansen +Signed-off-by: Lars B. Kristiansen +Co-developed-by: Jonas Markussen +Signed-off-by: Jonas Markussen +Co-developed-by: Tore H. Larsen +Signed-off-by: Tore H. Larsen +Signed-off-by: Magnus Kalland +Link: https://lore.kernel.org/linux-iommu/9204da81-f821-4034-b8ad-501e43383b56@amd.com/ +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index dfbd09e2e0ca5..6cd94ae9efff6 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -3086,26 +3086,44 @@ const struct iommu_ops amd_iommu_ops = { + static struct irq_chip amd_ir_chip; + static DEFINE_SPINLOCK(iommu_table_lock); + ++static int iommu_flush_dev_irt(struct pci_dev *unused, u16 devid, void *data) ++{ ++ int ret; ++ struct iommu_cmd cmd; ++ struct amd_iommu *iommu = data; ++ ++ build_inv_irt(&cmd, devid); ++ ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ return ret; ++} ++ + static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid) + { + int ret; + u64 data; + unsigned long flags; +- struct iommu_cmd cmd, cmd2; ++ struct iommu_cmd cmd; ++ struct pci_dev *pdev = NULL; ++ struct iommu_dev_data *dev_data = search_dev_data(iommu, devid); + + if (iommu->irtcachedis_enabled) + return; + +- build_inv_irt(&cmd, devid); ++ if (dev_data && dev_data->dev && dev_is_pci(dev_data->dev)) ++ pdev = to_pci_dev(dev_data->dev); + + raw_spin_lock_irqsave(&iommu->lock, flags); + data = get_cmdsem_val(iommu); +- build_completion_wait(&cmd2, iommu, data); ++ build_completion_wait(&cmd, iommu, data); + +- ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ if (pdev) ++ ret = pci_for_each_dma_alias(pdev, iommu_flush_dev_irt, iommu); ++ else ++ ret = iommu_flush_dev_irt(NULL, devid, iommu); + if (ret) + goto out_err; +- ret = __iommu_queue_command_sync(iommu, &cmd2, false); ++ ++ ret = __iommu_queue_command_sync(iommu, &cmd, false); + if (ret) + goto out_err; + raw_spin_unlock_irqrestore(&iommu->lock, flags); +-- +2.53.0 + diff --git a/queue-6.18/iommu-iova-add-null-check-in-iova_magazine_free.patch b/queue-6.18/iommu-iova-add-null-check-in-iova_magazine_free.patch new file mode 100644 index 0000000000..4c17b28672 --- /dev/null +++ b/queue-6.18/iommu-iova-add-null-check-in-iova_magazine_free.patch @@ -0,0 +1,49 @@ +From 2a4462545466c26cf2d7446330875d77f32711d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Feb 2026 08:09:19 +0000 +Subject: iommu/iova: Add NULL check in iova_magazine_free() + +From: lynn + +[ Upstream commit fa8fb60d36375ca3166a60589a624f0d0bc9ddb5 ] + +When iova_domain_init_rcaches() fails to allocate an iova_magazine +during the initialization of per-cpu rcaches, it jumps to out_err and +calls free_iova_rcaches() for cleanup. + +In free_iova_rcaches(), the code iterates through all possible CPUs to +free both cpu_rcache->loaded and cpu_rcache->prev. However, if the +original allocation failed mid-way through the CPU loop, the pointers +for the remaining CPUs remain NULL. + +Since kmem_cache_free() does not explicitly handle NULL pointers like +kfree() does, passing these NULL pointers leads to a kernel paging +request fault. + +Add a NULL check in iova_magazine_free() to safely handle partially +initialized rcaches in error paths. + +Signed-off-by: lynn +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/iova.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c +index 18f8397218136..e026be5e068bf 100644 +--- a/drivers/iommu/iova.c ++++ b/drivers/iommu/iova.c +@@ -611,7 +611,8 @@ static struct iova_magazine *iova_magazine_alloc(gfp_t flags) + + static void iova_magazine_free(struct iova_magazine *mag) + { +- kmem_cache_free(iova_magazine_cache, mag); ++ if (mag) ++ kmem_cache_free(iova_magazine_cache, mag); + } + + static void +-- +2.53.0 + diff --git a/queue-6.18/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch b/queue-6.18/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch new file mode 100644 index 0000000000..80443c299c --- /dev/null +++ b/queue-6.18/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch @@ -0,0 +1,39 @@ +From 4f4fabb09ffc06bedb9318d5d66439523e054667 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:58 +0800 +Subject: ipmi: ssif_bmc: cancel response timer on remove + +From: Jian Zhang + +[ Upstream commit 7fc3e2546cf3fa9a28a2acc92a512c779a8e5038 ] + +The response timer can stay armed across device teardown. If it fires after +remove, the callback dereferences the SSIF context and the i2c client after +teardown has started. + +Cancel the timer in remove so the callback cannot run after the device is +unregistered. + +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-1-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index a45e80d13e10e..646a1e9ffbb70 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -859,6 +859,7 @@ static void ssif_bmc_remove(struct i2c_client *client) + { + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + ++ timer_delete_sync(&ssif_bmc->response_timer); + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + } +-- +2.53.0 + diff --git a/queue-6.18/ipv4-validate-ipv4_devconf-attributes-properly.patch b/queue-6.18/ipv4-validate-ipv4_devconf-attributes-properly.patch new file mode 100644 index 0000000000..8bd0e35e86 --- /dev/null +++ b/queue-6.18/ipv4-validate-ipv4_devconf-attributes-properly.patch @@ -0,0 +1,106 @@ +From e845ae2de6678a4cb9029abe60a575bc2aae0aea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:26:37 +0100 +Subject: ipv4: validate IPV4_DEVCONF attributes properly + +From: Fernando Fernandez Mancera + +[ Upstream commit fa8fca88714c3a4a74f972ed37328e2f0bbef9fa ] + +As the IPV4_DEVCONF netlink attributes are not being validated, it is +possible to use netlink to set read-only values like mc_forwarding. In +addition, valid ranges are not being validated neither but that is less +relevant as they aren't in sysctl. + +To avoid similar situations in the future, define a NLA policy for +IPV4_DEVCONF attributes which are nested in IFLA_INET_CONF. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260312142637.5704-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 55 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 942a887bf0893..8b3e737e71941 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -2063,12 +2063,50 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { + [IFLA_INET_CONF] = { .type = NLA_NESTED }, + }; + ++static const struct nla_policy inet_devconf_policy[IPV4_DEVCONF_MAX + 1] = { ++ [IPV4_DEVCONF_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MC_FORWARDING] = { .type = NLA_REJECT }, ++ [IPV4_DEVCONF_PROXY_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SECURE_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SEND_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SHARED_MEDIA] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_RP_FILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BOOTP_RELAY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_LOG_MARTIANS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_TAG] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_ARPFILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MEDIUM_ID] = NLA_POLICY_MIN(NLA_S32, -1), ++ [IPV4_DEVCONF_NOXFRM] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_NOPOLICY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_FORCE_IGMP_VERSION] = NLA_POLICY_RANGE(NLA_U32, 0, 3), ++ [IPV4_DEVCONF_ARP_ANNOUNCE] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_IGNORE] = NLA_POLICY_RANGE(NLA_U32, 0, 8), ++ [IPV4_DEVCONF_PROMOTE_SECONDARIES] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_ACCEPT] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_NOTIFY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_LOCAL] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SRC_VMARK] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_PROXY_ARP_PVLAN] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ROUTE_LOCALNET] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BC_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_GRATUITOUS_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_EVICT_NOCARRIER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++}; ++ + static int inet_validate_link_af(const struct net_device *dev, + const struct nlattr *nla, + struct netlink_ext_ack *extack) + { +- struct nlattr *a, *tb[IFLA_INET_MAX+1]; +- int err, rem; ++ struct nlattr *tb[IFLA_INET_MAX + 1], *nested_tb[IPV4_DEVCONF_MAX + 1]; ++ int err; + + if (dev && !__in_dev_get_rtnl(dev)) + return -EAFNOSUPPORT; +@@ -2079,15 +2117,12 @@ static int inet_validate_link_af(const struct net_device *dev, + return err; + + if (tb[IFLA_INET_CONF]) { +- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { +- int cfgid = nla_type(a); ++ err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX, ++ tb[IFLA_INET_CONF], inet_devconf_policy, ++ extack); + +- if (nla_len(a) < 4) +- return -EINVAL; +- +- if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) +- return -EINVAL; +- } ++ if (err < 0) ++ return err; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-6.18/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..e449eb6482 --- /dev/null +++ b/queue-6.18/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From faafe5fd0153dad3cc461bcfd9d95cd4312af300 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 9e2449db0bdf2..61a5a79f367eb 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -62,6 +62,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -428,11 +430,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-6.18/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch b/queue-6.18/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch new file mode 100644 index 0000000000..24636e0223 --- /dev/null +++ b/queue-6.18/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch @@ -0,0 +1,59 @@ +From 0e72b6de52aa3cd614505f7b36d449b91ca7e234 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 14:37:58 +0100 +Subject: ipv6: discard fragment queue earlier if there is malformed datagram + +From: Fernando Fernandez Mancera + +[ Upstream commit 9ff2d2a9837015ff4b3579b028aeae8c180aa8d3 ] + +Currently the kernel IPv6 implementation is not dicarding the fragment +queue upon receiving a IPv6 fragment that is not 8 bytes aligned. It +relies on queue expiration to free the queue. + +While RFC 8200 section 4.5 does not explicitly mention that the rest of +fragments must be discarded, it does not make sense to keep them. The +parameter problem message is sent regardless that. In addition, if the +sender is able to re-compose the datagram so it is 8 bytes aligned it +would qualify as a new whole datagram not fitting into the same fragment +queue. + +The same situation happens if segment end is exceeding the IPv6 maximum +packet length. The sooner we can free resources the better during +reassembly, the better. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260225133758.4553-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/reassembly.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 25ec8001898df..11f9144bebbe2 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -132,6 +132,9 @@ static int ip6_frag_queue(struct net *net, + /* note that if prob_offset is set, the skb is freed elsewhere, + * we do not free it here. + */ ++ inet_frag_kill(&fq->q, refs); ++ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), ++ IPSTATS_MIB_REASMFAILS); + return -1; + } + +@@ -163,6 +166,9 @@ static int ip6_frag_queue(struct net *net, + * this case. -DaveM + */ + *prob_offset = offsetof(struct ipv6hdr, payload_len); ++ inet_frag_kill(&fq->q, refs); ++ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), ++ IPSTATS_MIB_REASMFAILS); + return -1; + } + if (end > fq->q.len) { +-- +2.53.0 + diff --git a/queue-6.18/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch b/queue-6.18/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch new file mode 100644 index 0000000000..472c81c498 --- /dev/null +++ b/queue-6.18/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch @@ -0,0 +1,150 @@ +From 43e8cd1ffac9a89010fa9f30c09df15da02fcf85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:36:49 +0200 +Subject: ipv6: move IFA_F_PERMANENT percpu allocation in process scope + +From: Paolo Abeni + +[ Upstream commit 8e6405f8218b3f412d36b772318e94d589513eba ] + +Observed at boot time: + + CPU: 43 UID: 0 PID: 3595 Comm: (t-daemon) Not tainted 6.12.0 #1 + Call Trace: + + dump_stack_lvl+0x4e/0x70 + pcpu_alloc_noprof.cold+0x1f/0x4b + fib_nh_common_init+0x4c/0x110 + fib6_nh_init+0x387/0x740 + ip6_route_info_create+0x46d/0x640 + addrconf_f6i_alloc+0x13b/0x180 + addrconf_permanent_addr+0xd0/0x220 + addrconf_notify+0x93/0x540 + notifier_call_chain+0x5a/0xd0 + __dev_notify_flags+0x5c/0xf0 + dev_change_flags+0x54/0x70 + do_setlink+0x36c/0xce0 + rtnl_setlink+0x11f/0x1d0 + rtnetlink_rcv_msg+0x142/0x3f0 + netlink_rcv_skb+0x50/0x100 + netlink_unicast+0x242/0x390 + netlink_sendmsg+0x21b/0x470 + __sys_sendto+0x1dc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x7d/0x160 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + RIP: 0033:0x7f5c3852f127 + Code: 0c 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 80 3d 85 ef 0c 00 00 41 89 ca 74 10 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 71 c3 55 48 83 ec 30 44 89 4c 24 2c 4c 89 44 + RSP: 002b:00007ffe86caf4c8 EFLAGS: 00000202 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 0000556c5cd93210 RCX: 00007f5c3852f127 + RDX: 0000000000000020 RSI: 0000556c5cd938b0 RDI: 0000000000000003 + RBP: 00007ffe86caf5a0 R08: 00007ffe86caf4e0 R09: 0000000000000080 + R10: 0000000000000000 R11: 0000000000000202 R12: 0000556c5cd932d0 + R13: 00000000021d05d1 R14: 00000000021d05d1 R15: 0000000000000001 + +IFA_F_PERMANENT addresses require the allocation of a bunch of percpu +pointers, currently in atomic scope. + +Similar to commit 51454ea42c1a ("ipv6: fix locking issues with loops +over idev->addr_list"), move fixup_permanent_addr() outside the +&idev->lock scope, and do the allocations with GFP_KERNEL. With such +change fixup_permanent_addr() is invoked with the BH enabled, and the +ifp lock acquired there needs the BH variant. + +Note that we don't need to acquire a reference to the permanent +addresses before releasing the mentioned write lock, because +addrconf_permanent_addr() runs under RTNL and ifa removal always happens +under RTNL, too. + +Also the PERMANENT flag is constant in the relevant scope, as it can be +cleared only by inet6_addr_modify() under the RTNL lock. + +Reviewed-by: David Ahern +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/46a7a030727e236af2dc7752994cd4f04f4a91d2.1775658924.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 2d4c3d9c1a2a5..bc58028b2147c 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3581,15 +3581,15 @@ static int fixup_permanent_addr(struct net *net, + struct fib6_info *f6i, *prev; + + f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false, +- GFP_ATOMIC, NULL); ++ GFP_KERNEL, NULL); + if (IS_ERR(f6i)) + return PTR_ERR(f6i); + + /* ifp->rt can be accessed outside of rtnl */ +- spin_lock(&ifp->lock); ++ spin_lock_bh(&ifp->lock); + prev = ifp->rt; + ifp->rt = f6i; +- spin_unlock(&ifp->lock); ++ spin_unlock_bh(&ifp->lock); + + fib6_info_release(prev); + } +@@ -3597,7 +3597,7 @@ static int fixup_permanent_addr(struct net *net, + if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, + ifp->rt_priority, idev->dev, 0, 0, +- GFP_ATOMIC); ++ GFP_KERNEL); + } + + if (ifp->state == INET6_IFADDR_STATE_PREDAD) +@@ -3608,29 +3608,36 @@ static int fixup_permanent_addr(struct net *net, + + static void addrconf_permanent_addr(struct net *net, struct net_device *dev) + { +- struct inet6_ifaddr *ifp, *tmp; ++ struct inet6_ifaddr *ifp; ++ LIST_HEAD(tmp_addr_list); + struct inet6_dev *idev; + ++ /* Mutual exclusion with other if_list_aux users. */ ++ ASSERT_RTNL(); ++ + idev = __in6_dev_get(dev); + if (!idev) + return; + + write_lock_bh(&idev->lock); ++ list_for_each_entry(ifp, &idev->addr_list, if_list) { ++ if (ifp->flags & IFA_F_PERMANENT) ++ list_add_tail(&ifp->if_list_aux, &tmp_addr_list); ++ } ++ write_unlock_bh(&idev->lock); + +- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { +- if ((ifp->flags & IFA_F_PERMANENT) && +- fixup_permanent_addr(net, idev, ifp) < 0) { +- write_unlock_bh(&idev->lock); ++ while (!list_empty(&tmp_addr_list)) { ++ ifp = list_first_entry(&tmp_addr_list, ++ struct inet6_ifaddr, if_list_aux); ++ list_del(&ifp->if_list_aux); + ++ if (fixup_permanent_addr(net, idev, ifp) < 0) { + net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n", + idev->dev->name, &ifp->addr); + in6_ifa_hold(ifp); + ipv6_del_addr(ifp); +- write_lock_bh(&idev->lock); + } + } +- +- write_unlock_bh(&idev->lock); + } + + static int addrconf_notify(struct notifier_block *this, unsigned long event, +-- +2.53.0 + diff --git a/queue-6.18/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch b/queue-6.18/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch new file mode 100644 index 0000000000..619f6b06b5 --- /dev/null +++ b/queue-6.18/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch @@ -0,0 +1,68 @@ +From 126c41d0cd4ac24be8f3e9b23541bb34c80984ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:32:29 +0800 +Subject: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 91840be8f710370607f949a627e070896faeddb8 ] + +On PREEMPT_RT, non-HARD irq_work runs in per-CPU kthreads via +run_irq_workd(), so irq_work_sync() uses rcuwait() to wait for BUSY==0. + +After irq_work_single() clears BUSY via atomic_cmpxchg(), it still +dereferences @work for irq_work_is_hard() and rcuwait_wake_up(). + +An irq_work_sync() caller on another CPU that enters after BUSY is cleared +can observe BUSY==0 immediately, return, and free the work before those +accesses complete — causing a use-after-free. + +Fix this by wrapping run_irq_workd() in guard(rcu)() so that the entire +irq_work_single() execution is within an RCU read-side critical +section. Then add synchronize_rcu() in irq_work_sync() after +rcuwait_wait_event() to ensure the caller waits for the RCU grace period +before returning, preventing premature frees. + +Fixes: 810979682ccc ("irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.") +Suggested-by: Sebastian Andrzej Siewior +Suggested-by: Steven Rostedt +Signed-off-by: Jiayuan Chen +Signed-off-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260330073234.303732-1-jiayuan.chen@linux.dev +Signed-off-by: Sasha Levin +--- + kernel/irq_work.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 73f7e1fd4ab4d..bf411656c3160 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -292,6 +292,12 @@ void irq_work_sync(struct irq_work *work) + !arch_irq_work_has_interrupt()) { + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), + TASK_UNINTERRUPTIBLE); ++ /* ++ * Ensure irq_work_single() does not access @work ++ * after removing IRQ_WORK_BUSY. It is always ++ * accessed within a RCU-read section. ++ */ ++ synchronize_rcu(); + return; + } + +@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); + + static void run_irq_workd(unsigned int cpu) + { ++ guard(rcu)(); + irq_work_run_list(this_cpu_ptr(&lazy_list)); + } + +-- +2.53.0 + diff --git a/queue-6.18/irqchip-ath79-cpu-remove-unused-function.patch b/queue-6.18/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..2e3ce37606 --- /dev/null +++ b/queue-6.18/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From c3e6e7e2d84b4deaec67fa3be14191abf27def24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-6.18/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-6.18/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..1dd340fdb0 --- /dev/null +++ b/queue-6.18/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From 5d0d831909573c61430f1299d1903ccf92a196d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index cdfa699cd7c8f..5fa6dd3a6ba28 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-6.18/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-6.18/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..5a42349fb8 --- /dev/null +++ b/queue-6.18/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From 73b4470764aa9da3bfbace8d401f081ba0cd8b9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 9ab3f2fc61d17..8abd9c7663ea4 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4297,3 +4297,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index ecb8e05b8b848..de0738858d4e4 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-6.18/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-6.18/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..87c2480e87 --- /dev/null +++ b/queue-6.18/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From 5602809be7ab3f73ac7c34f46b6d91ac1f320df3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 52e6b58c5dbd2..dac822f150701 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -378,11 +378,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-6.18/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-6.18/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..ad7f4aad6d --- /dev/null +++ b/queue-6.18/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From dd27b9e414ba6b35b495f3af34c7a87f9004cc55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 871cf4fb36366..0d6c40e7e551b 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -270,6 +270,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -379,7 +380,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index 7840a03e5bcb7..a5a5bc0a266d9 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-6.18/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-6.18/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..4b1204770a --- /dev/null +++ b/queue-6.18/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From add3361a6756ff2f4f4cf2e1cb34b490f139baa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 5b1c5da041630..59f94c28007da 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 8b8994e48cd08..09e0ef6aeccef 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 8ec43f53f6865..18569f1eaabdb 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-6.18/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-6.18/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..fd68d26ccc --- /dev/null +++ b/queue-6.18/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 16b58287dfbf212ef5668f741e441001529c9085 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 59f94c28007da..23f6a1a7a16b2 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2178,8 +2178,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2194,12 +2192,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2223,8 +2219,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2276,8 +2271,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2288,6 +2281,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2300,9 +2294,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-6.18/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch b/queue-6.18/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch new file mode 100644 index 0000000000..e70d843b46 --- /dev/null +++ b/queue-6.18/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch @@ -0,0 +1,103 @@ +From f07dac7344cfec1393d5b032a92a49b8236aa353 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist() + +From: Jianpeng Chang + +[ Upstream commit 307abfac04a254c09c5705d816b33354acee97a0 ] + +When kprobe_add_area_blacklist() iterates through a section like +.kprobes.text, the start address may not correspond to a named symbol. +On ARM64 with CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y (introduced by +commit baaf553d3bc3 ("arm64: Implement +HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")), the compiler flag +-fpatchable-function-entry=4,2 inserts 2 NOPs before each function entry +point for ftrace call_ops. These pre-function NOPs sit at the section base +address, before the first named function symbol. The compiler emits a $x +mapping symbol at offset 0x00 to mark the start of code, but +find_kallsyms_symbol() ignores mapping symbols. + +Without CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS (e.g. defconfig), no +pre-function NOPs are inserted, the first function starts at offset +0x00, and the bug does not trigger. + +This only affects modules that have a .kprobes.text section (i.e. those +using the __kprobes annotation). Modules using NOKPROBE_SYMBOL() instead +(like kretprobe_example.ko) blacklist exact function addresses via the +_kprobe_blacklist section and are not affected. + +For kprobe_example.ko on ARM64 with -fpatchable-function-entry=4,2, +the .kprobes.text section layout is: + + offset 0x00: $x + 2 NOPs (mapping symbol + ftrace preamble) + offset 0x08: handler_post (64 bytes) + offset 0x50: handler_pre (68 bytes) + +kprobe_add_area_blacklist() starts iterating from the section base +address (offset 0x00), which only has the $x mapping symbol. +kprobe_add_ksym_blacklist() then calls kallsyms_lookup_size_offset() +for this address, which goes through: + + kallsyms_lookup_size_offset() + -> module_address_lookup() + -> find_kallsyms_symbol() + +find_kallsyms_symbol() scans all module symbols to find the closest +preceding symbol. + +Since no named text symbol exists at offset 0x00, +find_kallsyms_symbol() picks __UNIQUE_ID_vermagic (a .modinfo symbol +whose address is in the temporary image) as the "best" match. The +computed "size" = next_text_symbol - modinfo_symbol spans across +these two unrelated memory regions, creating a blacklist entry with +a bogus range of tens of terabytes. + +Whether this causes a visible failure depends on address randomization, +here is what happens on Raspberry Pi 4/5: + + - On RPi5, the bogus size was ~35 TB. start + size stayed within + 64-bit range, so the blacklist entry covered the entire kernel + text. register_kprobe() in the module's own init function failed + with -EINVAL. + + - On RPi4, the bogus size was ~75 TB. start + size overflowed + 64 bits and wrapped to a small address near zero. The range + check (addr >= start && addr < end) then failed because end + wrapped around, so the bogus entry was accidentally harmless + and kprobes worked by luck. + +The same bug exists on both machines, but randomization determines whether +the integer overflow masks it or not. + +Fix this by adding notrace to the __kprobes macro. Functions in +.kprobes.text are kprobe infrastructure handlers that should never be +traced by ftrace. With notrace, the compiler stops inserting them and the +non-symbol gap at the section start disappears entirely. + +Link: https://lore.kernel.org/all/20260506012706.2785785-1-jianpeng.chang.cn@windriver.com/ + +Fixes: baaf553d3bc3 ("arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS") +Signed-off-by: Jianpeng Chang +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/asm-generic/kprobes.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/asm-generic/kprobes.h b/include/asm-generic/kprobes.h +index 060eab094e5a2..5290a2b2e15a0 100644 +--- a/include/asm-generic/kprobes.h ++++ b/include/asm-generic/kprobes.h +@@ -14,7 +14,7 @@ static unsigned long __used \ + _kbl_addr_##fname = (unsigned long)fname; + # define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) + /* Use this to forbid a kprobes attach on very low level functions */ +-# define __kprobes __section(".kprobes.text") ++# define __kprobes notrace __section(".kprobes.text") + # define nokprobe_inline __always_inline + #else + # define NOKPROBE_SYMBOL(fname) +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-6.18/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..af9225ba19 --- /dev/null +++ b/queue-6.18/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 0a9aa3917a76c527ce94338afa1cc06f11db85ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index f309e8dbeae23..fe44a423d088f 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3067,7 +3067,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -3081,7 +3081,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-6.18/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..e9f1f04713 --- /dev/null +++ b/queue-6.18/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From 93ca2a239052e12d003c69079bca605256cd1185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index fe44a423d088f..4531ddbb6073d 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -7481,7 +7481,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-6.18/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-6.18/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..d34c439fe8 --- /dev/null +++ b/queue-6.18/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From 3f8d4c771dc57609ebf49711e703e276f2c64446 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 7a6af361d2fc6..2b9fd107a69fe 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-6.18/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-6.18/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..8c9b3dbdf7 --- /dev/null +++ b/queue-6.18/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From c816f49fa5ef950380d465d29461cc54f6645196 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 2b9fd107a69fe..889380c2702c3 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-6.18/leds-core-implement-fallback-to-software-node-name-f.patch b/queue-6.18/leds-core-implement-fallback-to-software-node-name-f.patch new file mode 100644 index 0000000000..f9b89fbb8e --- /dev/null +++ b/queue-6.18/leds-core-implement-fallback-to-software-node-name-f.patch @@ -0,0 +1,44 @@ +From 5764de658ce45e4a7601b884c9d64750b2bd032b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 18:43:27 -0700 +Subject: leds: core: Implement fallback to software node name for LED names + +From: Dmitry Torokhov + +[ Upstream commit 4f530c65487636dc1536b3fa1041f9a877a66a7f ] + +If a software node defining an LED is missing explicit 'label', 'color', +or 'function' properties, led_compose_name() currently fails with +-EINVAL, because fallback to using node name in place of LED name/label +is only implemented for OF nodes. + +Implement similar fallback for software nodes. Unlike OF nodes, which +use the short 'name' attribute of the device tree node to avoid +including the address block, use fwnode_get_name() directly since +swnodes do not include an address block and always have a valid name. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260311-led-swnode-name-v1-1-798a49e041c6@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/led-core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c +index 59473f286b31f..8ce41b36c6455 100644 +--- a/drivers/leds/led-core.c ++++ b/drivers/leds/led-core.c +@@ -581,6 +581,9 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data, + } else if (is_of_node(fwnode)) { + n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", + to_of_node(fwnode)->name); ++ } else if (is_software_node(fwnode)) { ++ n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", ++ fwnode_get_name(fwnode)); + } else + return -EINVAL; + +-- +2.53.0 + diff --git a/queue-6.18/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-6.18/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..ef2b206a9e --- /dev/null +++ b/queue-6.18/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From 75e540d41562c457f9ddf7d43552c28d33485644 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 3d9ef9a54805c..0f27c68e27411 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-6.18/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-6.18/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..24827bc6ad --- /dev/null +++ b/queue-6.18/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 491b028bfd996feb52be98b794338abdf779ee6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 72e95663b62ff..c257cc415c478 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -18,6 +18,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -70,9 +77,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -96,16 +102,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-6.18/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch b/queue-6.18/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch new file mode 100644 index 0000000000..9dc483d2be --- /dev/null +++ b/queue-6.18/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch @@ -0,0 +1,43 @@ +From bda9a6edfac7984f46d9e8ec8d297b25e0d565ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 16:34:52 +0800 +Subject: mailbox: cix: Add IRQF_NO_SUSPEND to mailbox interrupt + +From: Dylan Wu + +[ Upstream commit 80784b427970219ebc338a6fb4118cde67a6c317 ] + +During the system suspend process, device interrupts are masked in the +noirq phase. However, SCMI often needs to exchange final messages with the +firmware to complete the power-down transition. Without the IRQF_NO_SUSPEND +flag, the mailbox ISR cannot run during this late stage, leading to SCMI +communication timeouts and error messages like "SCMI protocol wait for +resp timeout" during suspend. + +Add the IRQF_NO_SUSPEND flag to the interrupt request to ensure the mailbox +can continue to handle responses during the noirq stages of suspend and +resume, thereby ensuring a reliable power state transition. + +Signed-off-by: Dylan Wu +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/cix-mailbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c +index 5bb1416c26a50..5e27c2bf34923 100644 +--- a/drivers/mailbox/cix-mailbox.c ++++ b/drivers/mailbox/cix-mailbox.c +@@ -405,7 +405,7 @@ static int cix_mbox_startup(struct mbox_chan *chan) + int index = cp->index, ret; + u32 val; + +- ret = request_irq(priv->irq, cix_mbox_isr, 0, ++ ret = request_irq(priv->irq, cix_mbox_isr, IRQF_NO_SUSPEND, + dev_name(priv->dev), chan); + if (ret) { + dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); +-- +2.53.0 + diff --git a/queue-6.18/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch b/queue-6.18/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch new file mode 100644 index 0000000000..393d989503 --- /dev/null +++ b/queue-6.18/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch @@ -0,0 +1,144 @@ +From c22c3ce5a02b81fcb70a23cee31d9262442db9d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 00:35:48 -0400 +Subject: md/raid5: Fix UAF on IO across the reshape position + +From: Benjamin Marzinski + +[ Upstream commit 418b3e64e4459feb3f75979de9ec89e085745343 ] + +If make_stripe_request() returns STRIPE_WAIT_RESHAPE, +raid5_make_request() will free the cloned bio. But raid5_make_request() +can call make_stripe_request() multiple times, writing to the various +stripes. If that bio got added to the toread or towrite lists of a +stripe disk in an earlier call to make_stripe_request(), then it's not +safe to just free the bio if a later part of it is found to cross the +reshape position. Doing so can lead to a UAF error, when bio_endio() +is called on the bio for the earlier stripes. + +Instead, raid5_make_request() needs to wait until all parts of the bio +have called bio_endio(). To do this, bios that cross the reshape +position while the reshape can't make progress are flagged as needing to +wait for all parts to complete. When raid5_make_request() has a bio that +failed make_stripe_request() with STRIPE_WAIT_RESHAPE, it sets +bi->bi_private to a completion struct and waits for completion after +ending the bio. When the bio_endio() is called for the last time on a +clone bio with bi->bi_private set, it wakes up the waiter. This +guarantees that raid5_make_request() doesn't return until the cloned bio +needing a retry for io across the reshape boundary is safely cleaned up. + +There is a simple reproducer available at [1]. Compile the kernel with +KASAN for more useful reporting when the error is triggered (this is not +necessary to see the bug). + +[1] https://gist.github.com/bmarzins/e48598824305cf2171289e47d7241fa5 + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Xiao Ni +Link: https://lore.kernel.org/r/20260408043548.1695157-1-bmarzins@redhat.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 31 ++++++++----------------------- + drivers/md/md.h | 1 - + drivers/md/raid5.c | 7 ++++++- + 3 files changed, 14 insertions(+), 25 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index b7d47c018a12f..b96738fb67ea3 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -9256,9 +9256,11 @@ static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone) + + static void md_end_clone_io(struct bio *bio) + { +- struct md_io_clone *md_io_clone = bio->bi_private; ++ struct md_io_clone *md_io_clone = container_of(bio, struct md_io_clone, ++ bio_clone); + struct bio *orig_bio = md_io_clone->orig_bio; + struct mddev *mddev = md_io_clone->mddev; ++ struct completion *reshape_completion = bio->bi_private; + + if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) + md_bitmap_end(mddev, md_io_clone); +@@ -9270,7 +9272,10 @@ static void md_end_clone_io(struct bio *bio) + bio_end_io_acct(orig_bio, md_io_clone->start_time); + + bio_put(bio); +- bio_endio(orig_bio); ++ if (unlikely(reshape_completion)) ++ complete(reshape_completion); ++ else ++ bio_endio(orig_bio); + percpu_ref_put(&mddev->active_io); + } + +@@ -9295,7 +9300,7 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio) + } + + clone->bi_end_io = md_end_clone_io; +- clone->bi_private = md_io_clone; ++ clone->bi_private = NULL; + *bio = clone; + } + +@@ -9306,26 +9311,6 @@ void md_account_bio(struct mddev *mddev, struct bio **bio) + } + EXPORT_SYMBOL_GPL(md_account_bio); + +-void md_free_cloned_bio(struct bio *bio) +-{ +- struct md_io_clone *md_io_clone = bio->bi_private; +- struct bio *orig_bio = md_io_clone->orig_bio; +- struct mddev *mddev = md_io_clone->mddev; +- +- if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) +- md_bitmap_end(mddev, md_io_clone); +- +- if (bio->bi_status && !orig_bio->bi_status) +- orig_bio->bi_status = bio->bi_status; +- +- if (md_io_clone->start_time) +- bio_end_io_acct(orig_bio, md_io_clone->start_time); +- +- bio_put(bio); +- percpu_ref_put(&mddev->active_io); +-} +-EXPORT_SYMBOL_GPL(md_free_cloned_bio); +- + /* md_allow_write(mddev) + * Calling this ensures that the array is marked 'active' so that writes + * may proceed without blocking. It is important to call this before +diff --git a/drivers/md/md.h b/drivers/md/md.h +index da312d4692858..3c873e62d455d 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -917,7 +917,6 @@ extern void md_finish_reshape(struct mddev *mddev); + void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev, + struct bio *bio, sector_t start, sector_t size); + void md_account_bio(struct mddev *mddev, struct bio **bio); +-void md_free_cloned_bio(struct bio *bio); + + extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); + void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev, +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 8f5dd1f004cc4..5930379f2c0be 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -6213,7 +6213,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) + if (rw == WRITE) + md_write_end(mddev); + if (res == STRIPE_WAIT_RESHAPE) { +- md_free_cloned_bio(bi); ++ DECLARE_COMPLETION_ONSTACK(done); ++ WRITE_ONCE(bi->bi_private, &done); ++ ++ bio_endio(bi); ++ ++ wait_for_completion(&done); + return false; + } + +-- +2.53.0 + diff --git a/queue-6.18/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-6.18/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..9cf3d9b330 --- /dev/null +++ b/queue-6.18/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From 2301111c722c370c1d30b74979950056a1e95543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index b9f0d01ce01cb..8f5dd1f004cc4 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3916,6 +3916,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-6.18/media-au0828-fix-green-screen-in-analog.patch b/queue-6.18/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..6e96f4b810 --- /dev/null +++ b/queue-6.18/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From c44ccfb7790f733760aa34daba88eaa497903181 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index fbaa542c8259a..3c53105f3d2b3 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1671,6 +1671,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1764,8 +1785,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-6.18/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-6.18/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..eec22e55a8 --- /dev/null +++ b/queue-6.18/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From bd8845e00487af41a8b7c3f1f29a0ea392393b2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index 4eb83636e1027..1605cfa5db19d 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -824,9 +824,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-6.18/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-6.18/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..10fc7eb0aa --- /dev/null +++ b/queue-6.18/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 2963be45b77cb1557a47d088e2d4e5ac748ab54f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index a863063043303..69d5cc648c0fc 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-6.18/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch b/queue-6.18/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch new file mode 100644 index 0000000000..df42b4f529 --- /dev/null +++ b/queue-6.18/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch @@ -0,0 +1,111 @@ +From 6ae8dca40361726d19ff3c43ffed94c0ba1f26f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 16:50:24 +0100 +Subject: media: dw100: Fix kernel oops with PREEMPT_RT enabled + +From: Stefan Klug + +[ Upstream commit 557ec8cc29ade6c72ea768e59389db08cb7742c9 ] + +On kernels with PREEMPT_RT enabled, a "BUG: scheduling while atomic" +kernel oops occurs inside dw100_irq_handler -> vb2_buffer_done. This is +because vb2_buffer_done takes a spinlock which is not allowed within +interrupt context on PREEMPT_RT. + +The first attempt to fix this was to just drop the IRQF_ONESHOT so that +the interrupt is handled threaded on PREEMPT_RT systems. This introduced +a new issue. The dw100 has an internal timeout counter that is gated by +the DW100_BUS_CTRL_AXI_MASTER_ENABLE bit. Depending on the time it takes +for the threaded handler to run and the geometry of the data being +processed it is possible to reach the timeout resulting in +DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT being set and "dw100 +32e30000.dwe: Interrupt error: 0x1" errors in dmesg. + +To properly fix that, split the interrupt into two halves, reset the +DW100_BUS_CTRL_AXI_MASTER_ENABLE bit in the hard interrupt handler and +do the v4l2 buffer handling in the threaded half. The IRQF_ONESHOT can +still be dropped as the interrupt gets disabled in the hard handler and +will only be reenabled on the next dw100_device_run which will not be +called before the current job has finished. + +Signed-off-by: Stefan Klug +Reviewed-by: Xavier Roumegue +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260304-sklug-v6-16-topic-dw100-v3-1-dev-v5-3-1a7e1f721b50@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/nxp/dw100/dw100.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c +index 97744c7b7c034..40ca7414db339 100644 +--- a/drivers/media/platform/nxp/dw100/dw100.c ++++ b/drivers/media/platform/nxp/dw100/dw100.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,7 @@ struct dw100_device { + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; ++ bool frame_failed; + }; + + struct dw100_q_data { +@@ -1393,7 +1395,8 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + { + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; +- bool with_error = true; ++ ++ dw_dev->frame_failed = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; +@@ -1401,7 +1404,7 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); +- with_error = false; ++ dw_dev->frame_failed = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } +@@ -1414,7 +1417,14 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + +- dw100_job_finish(dw_dev, with_error); ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dw100_irq_thread_fn(int irq, void *dev_id) ++{ ++ struct dw100_device *dw_dev = dev_id; ++ ++ dw100_job_finish(dw_dev, dw_dev->frame_failed); + + return IRQ_HANDLED; + } +@@ -1562,8 +1572,9 @@ static int dw100_probe(struct platform_device *pdev) + + pm_runtime_put_sync(&pdev->dev); + +- ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, +- dev_name(&pdev->dev), dw_dev); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, dw100_irq_handler, ++ dw100_irq_thread_fn, 0, ++ dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_pm; +-- +2.53.0 + diff --git a/queue-6.18/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-6.18/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..a5d5b6b8ef --- /dev/null +++ b/queue-6.18/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From c96d32d312666cc2557bd7b375799772c648a429 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index a51cbcf429e13..37c0c6e860242 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2757,10 +2757,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-6.18/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch b/queue-6.18/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch new file mode 100644 index 0000000000..c57a5553b7 --- /dev/null +++ b/queue-6.18/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch @@ -0,0 +1,55 @@ +From 55c76fd5fbec32aa096177ab84202d24dd69f33c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:32 -0500 +Subject: media: em28xx: remove tuner type from Hauppauge DVB DualHD + +From: Bradford Love + +[ Upstream commit a5dcbff7d50a89bf0376e7f2fb1ba3163a6dac0a ] + +This reverts a patch which was perhaps inadvertently added. + +This was changed during the 5.15-rc4 merge. The faulty commit appears +lost in the pull request somehow, I cannot find it to check the +explanation. + +commit c52e7b855b33 ("Merge tag 'v5.15-rc4' into media_tree") + +There was nothing wrong with this device and no reason to moodify the +board profile. The DVB capabilities are added via dvb_module_probe. +Additionally, the device contains *zero* analog inputs, so I'm not +sure why one was added. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 37c0c6e860242..88adc010560a1 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2522,17 +2522,12 @@ const struct em28xx_board em28xx_boards[] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, +- .tuner_type = TUNER_SI2157, ++ .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .has_dual_ts = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, +- .input = { { +- .type = EM28XX_VMUX_COMPOSITE, +- .vmux = TVP5150_COMPOSITE1, +- .amux = EM28XX_AMUX_LINE_IN, +- } }, + }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. +-- +2.53.0 + diff --git a/queue-6.18/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch b/queue-6.18/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch new file mode 100644 index 0000000000..3bf1c2a581 --- /dev/null +++ b/queue-6.18/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch @@ -0,0 +1,47 @@ +From 6b2c0df03b437f0794c6765d2dad1dfcb10559bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:18:15 +0800 +Subject: media: i2c: ar0521: Check return value of devm_gpiod_get_optional() + in ar0521_probe() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chen Ni + +[ Upstream commit 46c2891cf12c767de031a248cbb1f96d203bd3f6 ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Acked-by: Krzysztof Hałasa +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ar0521.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c +index 939bf590d4b21..9241582943c76 100644 +--- a/drivers/media/i2c/ar0521.c ++++ b/drivers/media/i2c/ar0521.c +@@ -1094,6 +1094,9 @@ static int ar0521_probe(struct i2c_client *client) + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(sensor->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), ++ "failed to get reset gpio\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + +-- +2.53.0 + diff --git a/queue-6.18/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch b/queue-6.18/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch new file mode 100644 index 0000000000..74307ea2f4 --- /dev/null +++ b/queue-6.18/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch @@ -0,0 +1,85 @@ +From 61cff68ae9c9ea7cbbd88f6f7071d3345c767801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 02:31:54 +0000 +Subject: media: i2c: imx258: add missing mutex protection for format code + access + +From: Ziyi Guo + +[ Upstream commit c3109ecc3bb76aab9ef65f2e795a97a764a0b4a3 ] + +imx258_open(), imx258_enum_mbus_code(), and imx258_enum_frame_size() +call imx258_get_format_code() without holding imx258->mutex. However, +imx258_get_format_code() has lockdep_assert_held(&imx258->mutex) +indicating that callers must hold this lock. + +All other callers of imx258_get_format_code() properly acquire the mutex: +- imx258_set_pad_format() acquires mutex at imx258.c:918 +- imx258_get_pad_format() acquires mutex at imx258.c:896 + +The mutex is needed to protect access to imx258->vflip->val and +imx258->hflip->val which are used to calculate the bayer format code. + +Add mutex_lock()/mutex_unlock() around the imx258_get_format_code() +calls in the affected functions to fix the missing lock protection. + +Signed-off-by: Ziyi Guo +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/imx258.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index e50dcfd830f52..bc9ee449a87c5 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -709,12 +709,16 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) + v4l2_subdev_state_get_format(fh->state, 0); + struct v4l2_rect *try_crop; + ++ mutex_lock(&imx258->mutex); ++ + /* Initialize try_fmt */ + try_fmt->width = supported_modes[0].width; + try_fmt->height = supported_modes[0].height; + try_fmt->code = imx258_get_format_code(imx258); + try_fmt->field = V4L2_FIELD_NONE; + ++ mutex_unlock(&imx258->mutex); ++ + /* Initialize try_crop */ + try_crop = v4l2_subdev_state_get_crop(fh->state, 0); + try_crop->left = IMX258_PIXEL_ARRAY_LEFT; +@@ -839,7 +843,9 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd, + if (code->index > 0) + return -EINVAL; + ++ mutex_lock(&imx258->mutex); + code->code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); + + return 0; + } +@@ -849,10 +855,16 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_size_enum *fse) + { + struct imx258 *imx258 = to_imx258(sd); ++ u32 code; ++ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + +- if (fse->code != imx258_get_format_code(imx258)) ++ mutex_lock(&imx258->mutex); ++ code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); ++ ++ if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; +-- +2.53.0 + diff --git a/queue-6.18/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-6.18/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..818ed327e1 --- /dev/null +++ b/queue-6.18/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From 2436c8a4cbbd2fe9bba5d09968b0067e5acfd6c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index 1500ee4db47ec..ea5d43d925ffa 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1183,6 +1183,10 @@ static int mt9p031_probe(struct i2c_client *client) + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/media-ipu-bridge-add-ov5675-sensor-config.patch b/queue-6.18/media-ipu-bridge-add-ov5675-sensor-config.patch new file mode 100644 index 0000000000..6dedbd6ec3 --- /dev/null +++ b/queue-6.18/media-ipu-bridge-add-ov5675-sensor-config.patch @@ -0,0 +1,42 @@ +From 311e5b0f45960577ea6a45e83e67c744c885a581 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 10:45:45 +0100 +Subject: media: ipu-bridge: Add OV5675 sensor config + +From: Leif Skunberg + +[ Upstream commit d6576b85d3fe75238e67d3e311222e7f69730b09 ] + +Add the Omnivision OV5675 (ACPI HID OVTI5675) to the +ipu_supported_sensors[] table with a link frequency of 450 MHz. + +This sensor is found in the Lenovo ThinkPad X1 Fold 16 Gen 1 behind +an Intel Vision Sensing Controller (IVSC). Without this entry the IPU +bridge does not create the software-node fwnode graph for the sensor, +preventing the camera from being enumerated. + +Signed-off-by: Leif Skunberg +Reviewed-by: Hans de Goede +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/pci/intel/ipu-bridge.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index 4e579352ab2c0..170cea847d527 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -88,6 +88,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), + /* Omnivision OV2680 */ + IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), ++ /* Omnivision OV5675 */ ++ IPU_SENSOR_CONFIG("OVTI5675", 1, 450000000), + /* Omnivision OV8856 */ + IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), + /* Toshiba T4KA3 */ +-- +2.53.0 + diff --git a/queue-6.18/media-pulse8-cec-handle-partial-deinit.patch b/queue-6.18/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..3b39952db3 --- /dev/null +++ b/queue-6.18/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From 9b89ab02bbe728742bbd26bf881955e309a036f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 60569f1670fe5..67834ed333d32 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-6.18/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-6.18/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..c9d296c986 --- /dev/null +++ b/queue-6.18/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From ed3ead7ada5fbe92a2735145abb2de05d158495e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +index 390ea50f1595a..30e5f5ac09371 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +@@ -170,7 +170,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/media-renesas-vsp1-initialize-format-on-all-pads.patch b/queue-6.18/media-renesas-vsp1-initialize-format-on-all-pads.patch new file mode 100644 index 0000000000..5a147cb070 --- /dev/null +++ b/queue-6.18/media-renesas-vsp1-initialize-format-on-all-pads.patch @@ -0,0 +1,38 @@ +From 908d3ec292940ed53e259d95c0f93a5fe3ef3af7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:07 +0200 +Subject: media: renesas: vsp1: Initialize format on all pads + +From: Laurent Pinchart + +[ Upstream commit 133ac42af0a1b389e8b7b3dc7c1cc8c30ff162b6 ] + +The state initialization function vsp1_entity_init_state() incorrectly +leaves the last entity pad out when initializing formats due to an off +by one error. Fix it. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-14-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_entity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +index a6680d531872a..e8e65eb19a7d8 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +@@ -386,7 +386,7 @@ static int vsp1_entity_init_state(struct v4l2_subdev *subdev, + unsigned int pad; + + /* Initialize all pad formats with default values. */ +- for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { ++ for (pad = 0; pad < subdev->entity.num_pads; ++pad) { + struct v4l2_subdev_format format = { + .pad = pad, + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY +-- +2.53.0 + diff --git a/queue-6.18/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-6.18/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..fd1cda1322 --- /dev/null +++ b/queue-6.18/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From e4d032149a096cfce485f96064f64c16c10acbe1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + .../media/platform/renesas/vsp1/vsp1_rwpf.c | 28 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 9c8085d5d3060..7c7bfb946b779 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -216,6 +216,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *format; +@@ -244,18 +246,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-6.18/media-saa7164-fix-rev2-firmware-filename.patch b/queue-6.18/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..871b8698ce --- /dev/null +++ b/queue-6.18/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 51aee1858b6a415d9cb77c6ec9c9783f96314517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index cc9f384f7f1e9..341cef62452f1 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-6.18/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-6.18/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..33ee81bdf9 --- /dev/null +++ b/queue-6.18/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From d38dbfdc6b15e330ccb2d3d80944e2b1a62239a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index a085cefeebdd1..a0fa457e7c5b3 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-6.18/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-6.18/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..cf5ea75fed --- /dev/null +++ b/queue-6.18/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From f25da7b229a844efc42ce4e335b4e28c54eb17a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index d6b6b8bc7d4e0..a085cefeebdd1 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -572,8 +572,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-6.18/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-6.18/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..ea10afa634 --- /dev/null +++ b/queue-6.18/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From 3286494189ba7eb60d52be978cc3dbc3cc843132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index 13762861b7694..496e0781a957b 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -447,9 +447,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-6.18/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch b/queue-6.18/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch new file mode 100644 index 0000000000..5cad8dbc5d --- /dev/null +++ b/queue-6.18/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch @@ -0,0 +1,67 @@ +From df8df81c55f24bc237924da160a7f7bbc865c484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:32:18 +0000 +Subject: media: synopsys: hdmirx: support use with sleeping GPIOs + +From: Mark Brown + +[ Upstream commit 2fb0481fe0d7891420c1a3df2e4f9a70b1f77dbd ] + +The recent change in commit 20cf2aed89ac ("gpio: rockchip: mark the GPIO +controller as sleeping") to mark the rockchip GPIO driver as sleeping +has started triggering the warning at drivers/gpio/gpiolib.c:3523 +indicating that a sleepable GPIO was called via the non-sleeping APIs on +the Rock 5B: + +<4>[ 14.699308] Call trace: +<4>[ 14.699545] gpiod_get_value+0x90/0x98 (P) +<4>[ 14.699928] tx_5v_power_present+0x44/0xd0 [synopsys_hdmirx] +<4>[ 14.700446] hdmirx_delayed_work_hotplug+0x34/0x128 [synopsys_hdmirx] +<4>[ 14.701031] process_one_work+0x14c/0x28c +<4>[ 14.701405] worker_thread+0x184/0x300 +<4>[ 14.701756] kthread+0x11c/0x128 +<4>[ 14.702065] ret_from_fork+0x10/0x20 + +Currently the active use of the GPIO is all done from process context so +can be simply converted to use gpiod_get_value_cansleep(). There is one use +of the GPIO from hard interrupt context but this is only done so the status +can be displayed in a debug print so can simply be deleted without any +functional effect. + +Reviewed-by: Heiko Stuebner +Acked-by: Dmitry Osipenko +Signed-off-by: Mark Brown +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +index b7d278b3889f2..967cae89dacc0 100644 +--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c ++++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +@@ -230,7 +230,7 @@ static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) + + for (i = 0; i < 10; i++) { + usleep_range(1000, 1100); +- val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); ++ val = gpiod_get_value_cansleep(hdmirx_dev->detect_5v_gpio); + if (val > 0) + cnt++; + if (cnt >= detection_threshold) +@@ -2204,10 +2204,6 @@ static void hdmirx_delayed_work_res_change(struct work_struct *work) + static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id) + { + struct snps_hdmirx_dev *hdmirx_dev = dev_id; +- u32 val; +- +- val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); +- v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: 5v:%d\n", __func__, val); + + queue_delayed_work(system_unbound_wq, + &hdmirx_dev->delayed_work_hotplug, +-- +2.53.0 + diff --git a/queue-6.18/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch b/queue-6.18/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch new file mode 100644 index 0000000000..87dedf1bf5 --- /dev/null +++ b/queue-6.18/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch @@ -0,0 +1,62 @@ +From 4d5baa93eab30e40e45f5427971bde4b1d5aee6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 16:35:00 -0800 +Subject: memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5 + +From: Florian Fainelli + +[ Upstream commit a969a0835152984a0f556434eafdee0b84213670 ] + +The same limitations that apply to LPDDR4 also apply to LPDDR5. Expand +the check and rename accordingly. + +Signed-off-by: Florian Fainelli +Link: https://patch.msgid.link/20260122003501.1191059-1-florian.fainelli@broadcom.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/brcmstb_memc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c +index ba73470b1b134..c28fe90936168 100644 +--- a/drivers/memory/brcmstb_memc.c ++++ b/drivers/memory/brcmstb_memc.c +@@ -14,6 +14,7 @@ + + #define REG_MEMC_CNTRLR_CONFIG 0x00 + #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 ++#define CNTRLR_CONFIG_LPDDR5_SHIFT 6 + #define CNTRLR_CONFIG_MASK 0xf + #define REG_MEMC_SRPD_CFG_21 0x20 + #define REG_MEMC_SRPD_CFG_20 0x34 +@@ -34,14 +35,15 @@ struct brcmstb_memc { + u32 srpd_offset; + }; + +-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc) ++static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc) + { + void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG; + u32 reg; + + reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK; + +- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT; ++ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT || ++ reg == CNTRLR_CONFIG_LPDDR5_SHIFT; + } + + static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc, +@@ -95,7 +97,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr, + * dynamic tuning process will also get affected by the inactivity + * timeout, thus making it non functional. + */ +- if (brcmstb_memc_uses_lpddr4(memc)) ++ if (brcmstb_memc_uses_lpddr45(memc)) + return -EOPNOTSUPP; + + ret = kstrtouint(buf, 10, &val); +-- +2.53.0 + diff --git a/queue-6.18/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch b/queue-6.18/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch new file mode 100644 index 0000000000..fc279f0c71 --- /dev/null +++ b/queue-6.18/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch @@ -0,0 +1,52 @@ +From bc2abdcbaa7212092e495027d110e41efea4818c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 12:03:37 +0200 +Subject: mfd: intel-lpss: Add Intel Nova Lake-H PCI IDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Saranya Gopal + +[ Upstream commit d6e0ef44688249009dfa24f1cd619d41637de060 ] + +Add Intel Nova Lake-H LPSS PCI IDs. + +Signed-off-by: Saranya Gopal +Co-developed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260313100337.3471-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/intel-lpss-pci.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c +index 713a5bfb1a3c2..a9452ac92fb2d 100644 +--- a/drivers/mfd/intel-lpss-pci.c ++++ b/drivers/mfd/intel-lpss-pci.c +@@ -633,6 +633,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0xa879), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87a), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87b), (kernel_ulong_t)&ehl_i2c_info }, ++ /* NVL-H */ ++ { PCI_VDEVICE(INTEL, 0xd325), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd326), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd327), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd330), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd347), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd350), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd351), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd352), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd378), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd379), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37a), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37b), (kernel_ulong_t)&ehl_i2c_info }, + /* PTL-H */ + { PCI_VDEVICE(INTEL, 0xe325), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe326), (kernel_ulong_t)&bxt_uart_info }, +-- +2.53.0 + diff --git a/queue-6.18/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch b/queue-6.18/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch new file mode 100644 index 0000000000..4363da7782 --- /dev/null +++ b/queue-6.18/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch @@ -0,0 +1,94 @@ +From bfec049a59a527a0704cd67e1a5b00b08cefd260 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 23:00:45 +0900 +Subject: mfd: mt6397: Properly fix CID of MT6328, MT6331 and MT6332 + +From: Akari Tsuyukusa + +[ Upstream commit a09506820afa391e0a8ecc4b05c954f21e50b1de ] + +CIDs set for MT6328, MT6331 and MT6332 are not appropriate. +Many Android downstream kernels define CID as below, + +MT6328: + + #define PMIC6328_E1_CID_CODE 0x2810 + #define PMIC6328_E2_CID_CODE 0x2820 + #define PMIC6328_E3_CID_CODE 0x2830 + +MT6331/MT6332: + + #define PMIC6331_E1_CID_CODE 0x3110 + #define PMIC6331_E2_CID_CODE 0x3120 + #define PMIC6331_E3_CID_CODE 0x3130 + + #define PMIC6332_E1_CID_CODE 0x3210 + #define PMIC6332_E2_CID_CODE 0x3220 + #define PMIC6332_E3_CID_CODE 0x3230 + +The current configuration incorrectly uses the revision code as the CID. +Therefore, the driver cannot detect the same PMIC of different revisions. +(E1/E2 for MT6328, E1/E3 for MT6331/MT6332) +Based on these, the CID of MT6328, MT6331 and MT6332 should be corrected. + +Additionally, the incorrect MT6331/MT6332 CID overlaps with the MT6320's +actual CID: + + #define PMIC6320_E1_CID_CODE 0x1020 + #define PMIC6320_E2_CID_CODE 0x2020 + +This causes a conflict in the switch-case statement of mt6397-irq.c, +this prevents adding support for MT6320. + +Signed-off-by: Akari Tsuyukusa +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260302140045.651727-1-akkun11.open@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mt6397-core.c | 4 ++-- + include/linux/mfd/mt6397/core.h | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c +index 3e58d0764c7e0..1bdacda9a933f 100644 +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -297,7 +297,7 @@ static const struct chip_data mt6323_core = { + + static const struct chip_data mt6328_core = { + .cid_addr = MT6328_HWCID, +- .cid_shift = 0, ++ .cid_shift = 8, + .cells = mt6328_devs, + .cell_size = ARRAY_SIZE(mt6328_devs), + .irq_init = mt6397_irq_init, +@@ -313,7 +313,7 @@ static const struct chip_data mt6357_core = { + + static const struct chip_data mt6331_mt6332_core = { + .cid_addr = MT6331_HWCID, +- .cid_shift = 0, ++ .cid_shift = 8, + .cells = mt6331_mt6332_devs, + .cell_size = ARRAY_SIZE(mt6331_mt6332_devs), + .irq_init = mt6397_irq_init, +diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h +index b774c3a4bb62e..340fc72e22aa6 100644 +--- a/include/linux/mfd/mt6397/core.h ++++ b/include/linux/mfd/mt6397/core.h +@@ -12,9 +12,9 @@ + + enum chip_id { + MT6323_CHIP_ID = 0x23, +- MT6328_CHIP_ID = 0x30, +- MT6331_CHIP_ID = 0x20, +- MT6332_CHIP_ID = 0x20, ++ MT6328_CHIP_ID = 0x28, ++ MT6331_CHIP_ID = 0x31, ++ MT6332_CHIP_ID = 0x32, + MT6357_CHIP_ID = 0x57, + MT6358_CHIP_ID = 0x58, + MT6359_CHIP_ID = 0x59, +-- +2.53.0 + diff --git a/queue-6.18/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch b/queue-6.18/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch new file mode 100644 index 0000000000..77c5b77de7 --- /dev/null +++ b/queue-6.18/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch @@ -0,0 +1,64 @@ +From 66a6650fbf71b63de813d37348a2989ae9f026db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:35:52 +0800 +Subject: mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus + width + +From: Luke Wang + +[ Upstream commit e98f926e5a2d8023a74ec2ba7a973b5d76610f4e ] + +UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers +that lack relevant capability registers rely on paring properties provided +by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() +has been introduced to validate such configuration violations, let's also +add checks for UHS/DDR/HS200 modes. + +This fixes an issue where, if the HS200/HS400 property is set while only +a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually +performing the mode switch. Consequently, mmc_select_timing() proceeds +without falling back to mmc_select_hs(), leaving the eMMC device operating +in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). + +Signed-off-by: Luke Wang +[Shawn: reword the commit msg and rework the code] +Signed-off-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/host.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 88c95dbfd9cfd..a457c88fdcbc7 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -624,12 +624,24 @@ static int mmc_validate_host_caps(struct mmc_host *host) + return -EINVAL; + } + ++ /* UHS/DDR/HS200 modes require at least 4-bit bus */ ++ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) && ++ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) { ++ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n"); ++ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR); ++ caps2 &= ~MMC_CAP2_HS200; ++ } ++ ++ /* HS400 and HS400ES modes require 8-bit bus */ + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); +- host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; ++ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400); + } + ++ host->caps = caps; ++ host->caps2 = caps2; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch b/queue-6.18/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch new file mode 100644 index 0000000000..f9d80d2f75 --- /dev/null +++ b/queue-6.18/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch @@ -0,0 +1,69 @@ +From 2858654eee6fadcdce4874048f21b6e68a13bf13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 15:56:03 +0800 +Subject: mmc: sdhci-esdhc-imx: wait for data transfer completion before reset + +From: Luke Wang + +[ Upstream commit 8ceb70c9f970bfbdceb1e51578850a60b9de2236 ] + +On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) +cause system hangs and reboots during manual tuning. These cards exhibit +large gaps (~16us) between tuning command response and data transmission. +When cmd CRC errors occur during tuning, the code assumes data errors even +tuning data hasn't been fully received and then reset host data circuit. + +Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to +make sure no active data transfers. Previously, resetting while data was +in-flight would clear data circuit, including ADMA/SDMA address, causing +data to be transmitted to incorrect memory address. This patch adds +polling for data transfer completion before executing resets. + +Signed-off-by: Luke Wang +Reviewed-by: Bough Chen +Acked-by: Adrian Hunter +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/sdhci-esdhc-imx.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c +index a7a5df673b0f6..97461e20425d8 100644 +--- a/drivers/mmc/host/sdhci-esdhc-imx.c ++++ b/drivers/mmc/host/sdhci-esdhc-imx.c +@@ -216,6 +216,8 @@ + #define ESDHC_FLAG_DUMMY_PAD BIT(19) + + #define ESDHC_AUTO_TUNING_WINDOW 3 ++/* 100ms timeout for data inhibit */ ++#define ESDHC_DATA_INHIBIT_WAIT_US 100000 + + enum wp_types { + ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ +@@ -1453,6 +1455,22 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) + + static void esdhc_reset(struct sdhci_host *host, u8 mask) + { ++ u32 present_state; ++ int ret; ++ ++ /* ++ * For data or full reset, ensure any active data transfer completes ++ * before resetting to avoid system hang. ++ */ ++ if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) { ++ ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state, ++ !(present_state & SDHCI_DATA_INHIBIT), 2, ++ ESDHC_DATA_INHIBIT_WAIT_US); ++ if (ret == -ETIMEDOUT) ++ dev_warn(mmc_dev(host->mmc), ++ "timeout waiting for data transfer completion\n"); ++ } ++ + sdhci_and_cqhci_reset(host, mask); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); +-- +2.53.0 + diff --git a/queue-6.18/module-override-eexist-module-return.patch b/queue-6.18/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..e46d3ef620 --- /dev/null +++ b/queue-6.18/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From 1ec041679a396068bf40266987ff2027d4da3d7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 3745cd02c8479..8b408371ea611 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -3045,6 +3045,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-6.18/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-6.18/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..8dce1d8f94 --- /dev/null +++ b/queue-6.18/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From 9dbff3ec1b9156a63bd298c98f00cccd5f1fbdf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 681d7de89c505..e70618197d222 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -8028,7 +8028,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-6.18/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..0ef6d2df9b --- /dev/null +++ b/queue-6.18/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From 8274eea5e3b2ab9e621ed31dd15a1f1c8f5fbb99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 63f444e13d6f2..40bec34f06a7b 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -123,6 +123,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1445,6 +1446,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1458,7 +1460,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1498,6 +1499,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1508,6 +1510,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1542,6 +1545,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1550,6 +1554,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1559,6 +1564,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1887,6 +1893,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-6.18/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..fe9939eaff --- /dev/null +++ b/queue-6.18/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From 7cb6914a218e4dd81c3d3073296a76655708f834 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 7cf3ed7215a30..63f444e13d6f2 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1494,6 +1494,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-6.18/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..6cca3acbdb --- /dev/null +++ b/queue-6.18/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From 24d15abf6a85fa184d101cc61ca0ddb3b785c5ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 6a2004bbe87f9..7cf3ed7215a30 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1443,10 +1445,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1500,6 +1502,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1550,6 +1553,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1877,6 +1881,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-6.18/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..861240cd00 --- /dev/null +++ b/queue-6.18/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From af33b509010e595e4665cfed0ab6bd21d032be0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index fa5857923db4c..b4bfd6c174e78 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1271,7 +1271,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1298,7 +1297,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch b/queue-6.18/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch new file mode 100644 index 0000000000..0d7f1d063a --- /dev/null +++ b/queue-6.18/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch @@ -0,0 +1,101 @@ +From 1a8359ecf63630c586d19fb79f31d37340780da9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:45:18 +0000 +Subject: net: ethernet: mtk_eth_soc: avoid writing to ESW registers on MT7628 + +From: Joris Vaisvila + +[ Upstream commit 9a04d3b2f0708a9e5e1f731bafb69b040bb934a0 ] + +The MT7628 has a fixed-link PHY and does not expose MAC control +registers. Writes to these registers only corrupt the ESW VLAN +configuration. + +This patch explicitly registers no-op phylink_mac_ops for MT7628, as +after removing the invalid register accesses, the existing +phylink_mac_ops effectively become no-ops. + +This code was introduced by commit 296c9120752b +("net: ethernet: mediatek: Add MT7628/88 SoC support") + +Signed-off-by: Joris Vaisvila +Reviewed-by: Daniel Golle +Reviewed-by: Stefan Roese +Link: https://patch.msgid.link/20260226154547.68553-1-joey@tinyisr.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 ++++++++++++++++++--- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 0f676bd72832b..d0221742df1f9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -562,9 +562,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + int val, ge_mode, err = 0; + u32 i; + +- /* MT76x8 has no hardware settings between for the MAC */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +- mac->interface != state->interface) { ++ if (mac->interface != state->interface) { + /* Setup soc pin functions */ + switch (state->interface) { + case PHY_INTERFACE_MODE_TRGMII: +@@ -956,6 +954,30 @@ static const struct phylink_mac_ops mtk_phylink_ops = { + .mac_enable_tx_lpi = mtk_mac_enable_tx_lpi, + }; + ++static void rt5350_mac_config(struct phylink_config *config, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++} ++ ++static void rt5350_mac_link_down(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++} ++ ++static void rt5350_mac_link_up(struct phylink_config *config, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++} ++ ++/* MT76x8 (rt5350-eth) does not expose any MAC control registers */ ++static const struct phylink_mac_ops rt5350_phylink_ops = { ++ .mac_config = rt5350_mac_config, ++ .mac_link_down = rt5350_mac_link_down, ++ .mac_link_up = rt5350_mac_link_up, ++}; ++ + static void mtk_mdio_config(struct mtk_eth *eth) + { + u32 val; +@@ -4798,6 +4820,7 @@ static const struct net_device_ops mtk_netdev_ops = { + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + { ++ const struct phylink_mac_ops *mac_ops = &mtk_phylink_ops; + const __be32 *_id = of_get_property(np, "reg", NULL); + phy_interface_t phy_mode; + struct phylink *phylink; +@@ -4932,9 +4955,12 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ mac_ops = &rt5350_phylink_ops; ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), +- phy_mode, &mtk_phylink_ops); ++ phy_mode, mac_ops); + if (IS_ERR(phylink)) { + err = PTR_ERR(phylink); + goto free_netdev; +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-6.18/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..fb002770df --- /dev/null +++ b/queue-6.18/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From 9d8fee4c409fea1dea44404f9226fb5cf2a80914 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index e2d7ce1a85e84..50755ed68d063 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2358,6 +2358,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* PHY disconnect */ + if (ndev->phydev) { +-- +2.53.0 + diff --git a/queue-6.18/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch b/queue-6.18/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch new file mode 100644 index 0000000000..dc1e44ab8c --- /dev/null +++ b/queue-6.18/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch @@ -0,0 +1,106 @@ +From 67c10e846edc7b481843beaa346bafaa5a956341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 21:17:38 +0800 +Subject: net: ethtool: fix NULL pointer dereference in phy_reply_size + +From: Quan Sun <2022090917019@std.uestc.edu.cn> + +[ Upstream commit 4908f1395fb1b832ceec11584af649874a2732ea ] + +In phy_prepare_data(), several strings such as 'name', 'drvname', +'upstream_sfp_name', and 'downstream_sfp_name' are allocated using +kstrdup(). However, these allocations were not checked for failure. + +If kstrdup() fails for 'name', it returns NULL while the function +continues. This leads to a kernel NULL pointer dereference and panic +later in phy_reply_size() when it unconditionally calls strlen() on +the NULL pointer. + +While other strings like 'upstream_sfp_name' might be checked before +access in certain code paths, failing to handle these allocations +consistently can lead to incomplete data reporting or hidden bugs. + +Fix this by adding proper NULL checks for all kstrdup() calls in +phy_prepare_data() and implement a centralized error handling path +using goto labels to ensure all previously allocated resources are +freed on failure. + +Fixes: 9dd2ad5e92b9 ("net: ethtool: phy: Convert the PHY_GET command to generic phy dump") +Signed-off-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260507131738.1173835-1-2022090917019@std.uestc.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/phy.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/phy.c b/net/ethtool/phy.c +index 68372bef4b2fe..cb1e0aea450f9 100644 +--- a/net/ethtool/phy.c ++++ b/net/ethtool/phy.c +@@ -76,6 +76,7 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + struct nlattr **tb = info->attrs; + struct phy_device_node *pdn; + struct phy_device *phydev; ++ int ret; + + /* RTNL is held by the caller */ + phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PHY_HEADER, +@@ -88,8 +89,17 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + return -EOPNOTSUPP; + + rep_data->phyindex = phydev->phyindex; ++ + rep_data->name = kstrdup(dev_name(&phydev->mdio.dev), GFP_KERNEL); ++ if (!rep_data->name) ++ return -ENOMEM; ++ + rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL); ++ if (!rep_data->drvname) { ++ ret = -ENOMEM; ++ goto err_free_name; ++ } ++ + rep_data->upstream_type = pdn->upstream_type; + + if (pdn->upstream_type == PHY_UPSTREAM_PHY) { +@@ -97,15 +107,33 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + rep_data->upstream_index = upstream->phyindex; + } + +- if (pdn->parent_sfp_bus) ++ if (pdn->parent_sfp_bus) { + rep_data->upstream_sfp_name = kstrdup(sfp_get_name(pdn->parent_sfp_bus), + GFP_KERNEL); ++ if (!rep_data->upstream_sfp_name) { ++ ret = -ENOMEM; ++ goto err_free_drvname; ++ } ++ } + +- if (phydev->sfp_bus) ++ if (phydev->sfp_bus) { + rep_data->downstream_sfp_name = kstrdup(sfp_get_name(phydev->sfp_bus), + GFP_KERNEL); ++ if (!rep_data->downstream_sfp_name) { ++ ret = -ENOMEM; ++ goto err_free_upstream_sfp; ++ } ++ } + + return 0; ++ ++err_free_upstream_sfp: ++ kfree(rep_data->upstream_sfp_name); ++err_free_drvname: ++ kfree(rep_data->drvname); ++err_free_name: ++ kfree(rep_data->name); ++ return ret; + } + + static int phy_fill_reply(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.18/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-6.18/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..ca1edd5a51 --- /dev/null +++ b/queue-6.18/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From dd87da4011830fdbd17dfe79fd7d72e76341ff0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 045c5177262ea..214fd1f819a1b 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -187,6 +187,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-6.18/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-6.18/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..d0cb38b3c1 --- /dev/null +++ b/queue-6.18/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From b06b6cb4fdc71b648e7157d1aeef5626a0f0690e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index ae5048efde686..8569db4a71401 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1909,6 +1909,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-6.18/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch b/queue-6.18/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch new file mode 100644 index 0000000000..098ac947b7 --- /dev/null +++ b/queue-6.18/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch @@ -0,0 +1,49 @@ +From 15dc41c248b10981ccaf4296c74d162b3cfccac1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 14:39:29 +0200 +Subject: net: hsr: emit notification for PRP slave2 changed hw addr on port + deletion + +From: Fernando Fernandez Mancera + +[ Upstream commit 2ce8a41113eda1adddc1e6dc43cf89383ec6dc22 ] + +On PRP protocol, when deleting the port the MAC address change +notification was missing. In addition to that, make sure to only perform +the MAC address change on slave2 deletion and PRP protocol as the +operation isn't necessary for HSR nor slave1. + +Note that the eth_hw_addr_set() is correct on PRP context as the slaves +are either in promiscuous mode or forward offload enabled. + +Reported-by: Luka Gejak +Closes: https://lore.kernel.org/netdev/DHFCZEM93FTT.1RWFBIE32K7OT@linux.dev/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Felix Maurer +Link: https://patch.msgid.link/20260403123928.4249-2-fmancera@suse.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_slave.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c +index afe06ba00ea44..29cafaf84f03d 100644 +--- a/net/hsr/hsr_slave.c ++++ b/net/hsr/hsr_slave.c +@@ -243,7 +243,11 @@ void hsr_del_port(struct hsr_port *port) + if (!port->hsr->fwd_offloaded) + dev_set_promiscuity(port->dev, -1); + netdev_upper_dev_unlink(port->dev, master->dev); +- eth_hw_addr_set(port->dev, port->original_macaddress); ++ if (hsr->prot_version == PRP_V1 && ++ port->type == HSR_PT_SLAVE_B) { ++ eth_hw_addr_set(port->dev, port->original_macaddress); ++ call_netdevice_notifiers(NETDEV_CHANGEADDR, port->dev); ++ } + } + + kfree_rcu(port, rcu); +-- +2.53.0 + diff --git a/queue-6.18/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-6.18/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..442bbdb489 --- /dev/null +++ b/queue-6.18/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From cf592c3f5580fcc000a6ba5d7bcdcc579bdf2235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 5a38837a58384..9231ebaa0cac8 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2566,6 +2566,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-6.18/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch b/queue-6.18/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch new file mode 100644 index 0000000000..44b89d162e --- /dev/null +++ b/queue-6.18/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch @@ -0,0 +1,82 @@ +From bed96d3cca3202630e3a1837d93d376d3ee1e13d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 12:02:28 +0530 +Subject: net: lan743x: fix SGMII detection on PCI1xxxx B0+ during warm reset + +From: Thangaraj Samynathan + +[ Upstream commit e783e40fb689381caca31e03d28c39e10c82e722 ] + +A warm reset on boards using an EEPROM-only strap configuration (where +no MAC address is set in the image) can cause the driver to incorrectly +revert to RGMII mode. This occurs because the ENET_CONFIG_LOAD_STARTED +bit may not persist or behave as expected. + +Update pci11x1x_strap_get_status() to use revision-specific validation: + +- For PCI11x1x A0: Continue using the legacy check (config load started + or reset protection) to validate the SGMII strap. +- For PCI11x1x B0 and later: Use the newly available + STRAP_READ_USE_SGMII_EN_ bit in the upper strap register to validate + the lower SGMII_EN bit. + +This ensures the SGMII interface is correctly identified even after a +warm reboot. + +Signed-off-by: Thangaraj Samynathan +Link: https://patch.msgid.link/20260318063228.17110-1-thangaraj.s@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 15 +++++++++++---- + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 09d255e78f6cd..fdf6e4bfbe383 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -28,6 +28,12 @@ + + #define RFE_RD_FIFO_TH_3_DWORDS 0x3 + ++static bool pci11x1x_is_a0(struct lan743x_adapter *adapter) ++{ ++ u32 dev_rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_; ++ return dev_rev == ID_REV_CHIP_REV_PCI11X1X_A0_; ++} ++ + static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + { + u32 chip_rev; +@@ -47,10 +53,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); + lan743x_hs_syslock_release(adapter); + hw_cfg = lan743x_csr_read(adapter, HW_CFG); +- +- if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || +- hw_cfg & HW_CFG_RST_PROTECT_) { +- strap = lan743x_csr_read(adapter, STRAP_READ); ++ strap = lan743x_csr_read(adapter, STRAP_READ); ++ if ((pci11x1x_is_a0(adapter) && ++ (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || ++ hw_cfg & HW_CFG_RST_PROTECT_)) || ++ (strap & STRAP_READ_USE_SGMII_EN_)) { + if (strap & STRAP_READ_SGMII_EN_) + adapter->is_sgmii_en = true; + else +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 02a28b7091630..160d94a7cee66 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -27,6 +27,7 @@ + #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) + #define ID_REV_CHIP_REV_A0_ (0x00000000) + #define ID_REV_CHIP_REV_B0_ (0x00000010) ++#define ID_REV_CHIP_REV_PCI11X1X_A0_ (0x000000A0) + #define ID_REV_CHIP_REV_PCI11X1X_B0_ (0x000000B0) + + #define FPGA_REV (0x04) +-- +2.53.0 + diff --git a/queue-6.18/net-lan966x-avoid-unregistering-netdev-on-register-f.patch b/queue-6.18/net-lan966x-avoid-unregistering-netdev-on-register-f.patch new file mode 100644 index 0000000000..1ef5748f6b --- /dev/null +++ b/queue-6.18/net-lan966x-avoid-unregistering-netdev-on-register-f.patch @@ -0,0 +1,65 @@ +From f799b8a3869b83b0c868e3e10597b734db3bc4de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 21:43:11 +0900 +Subject: net: lan966x: avoid unregistering netdev on register failure + +From: Myeonghun Pak + +[ Upstream commit c4f3d6eb1fcf6cd9ce4644f604d5aad1ce594dfc ] + +lan966x_probe_port() stores the newly allocated net_device in the +port before calling register_netdev(). If register_netdev() fails, +the probe error path calls lan966x_cleanup_ports(), which sees +port->dev and calls unregister_netdev() for a device that was never +registered. + +Destroy the phylink instance created for this port and clear port->dev +before returning the registration error. The common cleanup path now skips +ports without port->dev before reaching the registered netdev cleanup, so +it only handles ports that reached the registered-netdev lifetime. + +This also avoids treating an uninitialized FDMA netdev and the failed port +as a NULL == NULL match in the common cleanup path. + +Fixes: d28d6d2e37d1 ("net: lan966x: add port module support") +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260506124331.31945-1-mhun512@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index 47752d3fde0b1..1179a6e127c52 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -749,11 +749,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) + + for (p = 0; p < lan966x->num_phys_ports; p++) { + port = lan966x->ports[p]; +- if (!port) ++ if (!port || !port->dev) + continue; + +- if (port->dev) +- unregister_netdev(port->dev); ++ unregister_netdev(port->dev); + + lan966x_xdp_port_deinit(port); + if (lan966x->fdma && lan966x->fdma_ndev == port->dev) +@@ -873,6 +872,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, + err = register_netdev(dev); + if (err) { + dev_err(lan966x->dev, "register_netdev failed\n"); ++ phylink_destroy(phylink); ++ port->phylink = NULL; ++ port->dev = NULL; + return err; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch b/queue-6.18/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch new file mode 100644 index 0000000000..3e23e12ca7 --- /dev/null +++ b/queue-6.18/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch @@ -0,0 +1,55 @@ +From 83ec420498378b82fd58de2fef6e2952092eb69b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 10:30:56 -0700 +Subject: net: mana: hardening: Validate adapter_mtu from MANA_QUERY_DEV_CONFIG + +From: Erni Sri Satya Vennela + +[ Upstream commit d7709812e13d06132ddae3d21540472ea5cb11c5 ] + +As a part of MANA hardening for CVM, validate the adapter_mtu value +returned from the MANA_QUERY_DEV_CONFIG HWC command. + +The adapter_mtu value is used to compute ndev->max_mtu via: +gc->adapter_mtu - ETH_HLEN. If hardware returns a bogus adapter_mtu +smaller than ETH_HLEN (e.g. 0), the unsigned subtraction wraps to a +huge value, silently allowing oversized MTU settings. + +Add a validation check to reject adapter_mtu values below +ETH_MIN_MTU + ETH_HLEN, returning -EPROTO to fail the device +configuration early with a clear error message. + +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260326173101.2010514-1-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index d1eb77d540427..aa8a6ae1191a5 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1220,10 +1220,16 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, + + *max_num_vports = resp.max_num_vports; + +- if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) ++ if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) { ++ if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { ++ dev_err(dev, "Adapter MTU too small: %u\n", ++ resp.adapter_mtu); ++ return -EPROTO; ++ } + gc->adapter_mtu = resp.adapter_mtu; +- else ++ } else { + gc->adapter_mtu = ETH_FRAME_LEN; ++ } + + if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V3) + *bm_hostmode = resp.bm_hostmode; +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch b/queue-6.18/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch new file mode 100644 index 0000000000..3bbfb5fe09 --- /dev/null +++ b/queue-6.18/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch @@ -0,0 +1,41 @@ +From 30886ec54dc78017cbe271266a632015e8f29072 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:09:23 +0300 +Subject: net/mlx5e: XSK, Increase size for chunk_size param + +From: Dragos Tatulea + +[ Upstream commit 1047e14b44edecbbab02a86514a083b8db9fde4d ] + +When 64K pages are used, chunk_size can take the 64K value +which doesn't fit in u16. This results in overflows that +are detected in mlx5e_mpwrq_log_wqe_sz(). + +Increase the type to u32 to fix this. + +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260403090927.139042-2-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/params.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +index 00617c65fe3cd..c5aaaa4ac3648 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +@@ -8,7 +8,7 @@ + + struct mlx5e_xsk_param { + u16 headroom; +- u16 chunk_size; ++ u32 chunk_size; + bool unaligned; + }; + +-- +2.53.0 + diff --git a/queue-6.18/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-6.18/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..ed7c86d89a --- /dev/null +++ b/queue-6.18/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From 269f585efaa430b4df4b3078b22f8ef34d3d0e70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index 89ccb8eb82c7d..6ab82c132c0ae 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5628,6 +5628,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5763,6 +5765,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-6.18/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch b/queue-6.18/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch new file mode 100644 index 0000000000..fbe08d0d13 --- /dev/null +++ b/queue-6.18/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch @@ -0,0 +1,95 @@ +From d880c891a163a4e5fcf019757c7563a3a1667b29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 09:08:08 +0000 +Subject: net: napi: Avoid gro timer misfiring at end of busypoll + +From: Dragos Tatulea + +[ Upstream commit 58e2330bd45572a6e3d46ea94cf7a9641f43591a ] + +When in irq deferral mode (defer-hard-irqs > 0), a short enough +gro-flush timeout can trigger before NAPI_STATE_SCHED is cleared if the +last poll in busy_poll_stop() takes too long. This can have the effect +of leaving the queue stuck with interrupts disabled and no timer armed +which results in a tx timeout if there is no subsequent busypoll cycle. + +To prevent this, defer the gro-flush timer arm after the last poll. + +Fixes: 7fd3253a7de6 ("net: Introduce preferred busy-polling") +Co-developed-by: Martin Karsten +Signed-off-by: Martin Karsten +Signed-off-by: Dragos Tatulea +Reviewed-by: Tariq Toukan +Reviewed-by: Cosmin Ratiu +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260506090808.820559-2-dtatulea@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 29f2f35ae5ebe..681d7de89c505 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6777,9 +6777,9 @@ static void skb_defer_free_flush(void) + + #if defined(CONFIG_NET_RX_BUSY_POLL) + +-static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule) ++static void __busy_poll_stop(struct napi_struct *napi, unsigned long timeout) + { +- if (!skip_schedule) { ++ if (!timeout) { + gro_normal_list(&napi->gro); + __napi_schedule(napi); + return; +@@ -6789,6 +6789,8 @@ static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule) + gro_flush_normal(&napi->gro, HZ >= 1000); + + clear_bit(NAPI_STATE_SCHED, &napi->state); ++ hrtimer_start(&napi->timer, ns_to_ktime(timeout), ++ HRTIMER_MODE_REL_PINNED); + } + + enum { +@@ -6800,8 +6802,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + unsigned flags, u16 budget) + { + struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx; +- bool skip_schedule = false; +- unsigned long timeout; ++ unsigned long timeout = 0; + int rc; + + /* Busy polling means there is a high chance device driver hard irq +@@ -6821,10 +6822,12 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + + if (flags & NAPI_F_PREFER_BUSY_POLL) { + napi->defer_hard_irqs_count = napi_get_defer_hard_irqs(napi); +- timeout = napi_get_gro_flush_timeout(napi); +- if (napi->defer_hard_irqs_count && timeout) { +- hrtimer_start(&napi->timer, ns_to_ktime(timeout), HRTIMER_MODE_REL_PINNED); +- skip_schedule = true; ++ if (napi->defer_hard_irqs_count) { ++ /* A short enough gro flush timeout and long enough ++ * poll can result in timer firing too early. ++ * Timer will be armed later if necessary. ++ */ ++ timeout = napi_get_gro_flush_timeout(napi); + } + } + +@@ -6839,7 +6842,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + trace_napi_poll(napi, rc, budget); + netpoll_poll_unlock(have_poll_lock); + if (rc == budget) +- __busy_poll_stop(napi, skip_schedule); ++ __busy_poll_stop(napi, timeout); + bpf_net_ctx_clear(bpf_net_ctx); + local_bh_enable(); + } +-- +2.53.0 + diff --git a/queue-6.18/net-phy-dp83tc811-add-reading-of-abilities.patch b/queue-6.18/net-phy-dp83tc811-add-reading-of-abilities.patch new file mode 100644 index 0000000000..ae891b66c4 --- /dev/null +++ b/queue-6.18/net-phy-dp83tc811-add-reading-of-abilities.patch @@ -0,0 +1,40 @@ +From 9c88ba48c6db87182c9124a3fc56baa8b154cbcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 09:19:47 +0200 +Subject: net: phy: DP83TC811: add reading of abilities + +From: Sven Schuchmann + +[ Upstream commit c78bdba7b9666020c0832150a4fc4c0aebc7c6ac ] + +At this time the driver is not listing any speeds +it supports. This should be ETHTOOL_LINK_MODE_100baseT1_Full_BIT +for DP83TC811. Add the missing call for phylib to read the abilities. + +Fixes: b753a9faaf9a ("net: phy: DP83TC811: Introduce support for the DP83TC811 phy") +Suggested-by: Andrew Lunn +Signed-off-by: Sven Schuchmann +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260512071949.6218-1-schuchmann@schleissheimer.de +[pabeni@redhat.com: dropped revision history] +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83tc811.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c +index e480c2a074505..252fb12b3e68e 100644 +--- a/drivers/net/phy/dp83tc811.c ++++ b/drivers/net/phy/dp83tc811.c +@@ -393,6 +393,7 @@ static struct phy_driver dp83811_driver[] = { + .config_init = dp83811_config_init, + .config_aneg = dp83811_config_aneg, + .soft_reset = dp83811_phy_reset, ++ .get_features = genphy_c45_pma_read_ext_abilities, + .get_wol = dp83811_get_wol, + .set_wol = dp83811_set_wol, + .config_intr = dp83811_config_intr, +-- +2.53.0 + diff --git a/queue-6.18/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-6.18/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..ac14e01804 --- /dev/null +++ b/queue-6.18/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From 9f20c9479d316a2afc7dc0e656f2f3f2608b7d6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c645853..4cbf5f934cde1 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -361,7 +361,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -462,7 +462,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-6.18/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-6.18/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..f410a00e64 --- /dev/null +++ b/queue-6.18/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 1d20f52896bfcfd71256642cf2937da1d7e51b6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 0276b393f0e53..e268005819627 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -271,6 +271,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch b/queue-6.18/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch new file mode 100644 index 0000000000..b712dd6480 --- /dev/null +++ b/queue-6.18/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch @@ -0,0 +1,58 @@ +From a06d9c161cac4c9474f2cd54e802dadedbeb2ebf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 20:39:16 +0800 +Subject: net: sched: cls_u32: Avoid memcpy() false-positive warning in + u32_init_knode() + +From: Jiayuan Chen + +[ Upstream commit 34bd3c6b0bd383a76d987c8c45c4f309b681b255 ] + +Syzbot reported a warning in u32_init_knode() [1]. + +Similar to commit 7cba18332e36 ("net: sched: cls_u32: Avoid memcpy() +false-positive warning") which addressed the same issue in u32_change(), +use unsafe_memcpy() in u32_init_knode() to work around the compiler's +inability to see into composite flexible array structs. + +This silences the false-positive reported by syzbot: + + memcpy: detected field-spanning write (size 32) of single field + "&new->sel" at net/sched/cls_u32.c:855 (size 16) + +Since the memory is correctly allocated with kzalloc_flex() using +s->nkeys, this is purely a false positive and does not need a Fixes tag. + +[1] https://syzkaller.appspot.com/bug?extid=d5ace703ed883df56e42 + +Reported-by: syzbot+d5ace703ed883df56e42@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69a811b9.a70a0220.b118c.0019.GAE@google.com/T/ +Reviewed-by: Simon Horman +Acked-by: Gustavo A. R. Silva +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260309123917.402183-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_u32.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 58e849c0acf41..c2d032b9aab72 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -852,7 +852,10 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, + /* Similarly success statistics must be moved as pointers */ + new->pcpu_success = n->pcpu_success; + #endif +- memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); ++ unsafe_memcpy(&new->sel, s, struct_size(s, keys, s->nkeys), ++ /* A composite flex-array structure destination, ++ * which was correctly sized with kzalloc_flex(), ++ * above. */); + + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { + kfree(new); +-- +2.53.0 + diff --git a/queue-6.18/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch b/queue-6.18/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch new file mode 100644 index 0000000000..b6ee968782 --- /dev/null +++ b/queue-6.18/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch @@ -0,0 +1,57 @@ +From 1544479c7122dab4adbbb17020dee0d18955e1dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:11:11 +0200 +Subject: net: sfp: add quirk for ZOERAX SFP-2.5G-T + +From: Jan Hoffmann + +[ Upstream commit 911e2c050963ccf239faec6ae9dee0f5e8f1cc5c ] + +This is a 2.5G copper module which appears to be based on a Motorcomm +YT8821 PHY. There doesn't seem to be a usable way to to access the PHY +(I2C address 0x56 provides only read-only C22 access, and Rollball is +also not working). + +The module does not report the correct extended compliance code for +2.5GBase-T, and instead claims to support SONET OC-48 and Fibre Channel: + + Identifier : 0x03 (SFP) + Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID) + Connector : 0x07 (LC) + Transceiver codes : 0x00 0x01 0x00 0x00 0x40 0x40 0x04 0x00 0x00 + Transceiver type : FC: Multimode, 50um (M5) + Encoding : 0x05 (SONET Scrambled) + BR Nominal : 2500MBd + +Despite this, the kernel still enables the correct 2500Base-X interface +mode. However, for the module to actually work, it is also necessary to +disable inband auto-negotiation. + +Enable the existing "sfp_quirk_oem_2_5g" for this module, which handles +that and also sets the bit for 2500Base-T link mode. + +Signed-off-by: Jan Hoffmann +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260329191304.720160-1-jan@3e8.eu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/sfp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index c62e3f364ea73..011564e42794e 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -588,6 +588,8 @@ static const struct sfp_quirk sfp_quirks[] = { + SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball), ++ ++ SFP_QUIRK_S("ZOERAX", "SFP-2.5G-T", sfp_quirk_oem_2_5g), + }; + + static size_t sfp_strlen(const char *str, size_t maxlen) +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch b/queue-6.18/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch new file mode 100644 index 0000000000..b946fe572f --- /dev/null +++ b/queue-6.18/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch @@ -0,0 +1,46 @@ +From 08f2845e66a2f081e4339feb9fae6a4286982a2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:03 -0700 +Subject: net: shaper: enforce singleton NETDEV scope with id 0 + +From: Jakub Kicinski + +[ Upstream commit b62b29e6de6711f5918940aa6ff2bbab6d6af502 ] + +The NETDEV scope represents a singleton root shaper in the per-device +hierarchy. All code assumes NETDEV shapers have id 0: +net_shaper_default_parent() hardcodes parent->id = 0 when returning +the NETDEV parent for QUEUE/NODE children, and the UAPI documentation +describes NETDEV scope as "the main shaper" (singular, not plural). + +Make sure we reject non-0 IDs. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-10-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index b2d85963243fa..d65008b819dc9 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -482,6 +482,12 @@ static int net_shaper_parse_handle(const struct nlattr *attr, + else if (handle->scope == NET_SHAPER_SCOPE_NODE) + id = NET_SHAPER_ID_UNSPEC; + ++ if (id && handle->scope == NET_SHAPER_SCOPE_NETDEV) { ++ NL_SET_ERR_MSG_ATTR(info->extack, id_attr, ++ "Netdev scope is a singleton, must use ID 0"); ++ return -EINVAL; ++ } ++ + handle->id = id; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch b/queue-6.18/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch new file mode 100644 index 0000000000..df9205cc35 --- /dev/null +++ b/queue-6.18/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch @@ -0,0 +1,60 @@ +From 0b33b7a8f9970a2da64130e1f50fa99769c94a97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:56 -0700 +Subject: net: shaper: fix trivial ordering issue in net_shaper_commit() + +From: Jakub Kicinski + +[ Upstream commit 235fb5376139c3419f2218349f1fa2f06f24f7ad ] + +We should update the entry before we mark it as valid. + +Fixes: 93954b40f6a4 ("net-shapers: implement NL set and delete operations") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 64c9d6cf6756c..92ca3b4c7925d 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -295,6 +295,10 @@ net_shaper_lookup(struct net_shaper_binding *binding, + NET_SHAPER_VALID)) + return NULL; + ++ /* Pairs with smp_wmb() in net_shaper_commit(): if the entry is ++ * valid, its contents must be visible too. ++ */ ++ smp_rmb(); + return xa_load(&hierarchy->shapers, index); + } + +@@ -412,8 +416,9 @@ static void net_shaper_commit(struct net_shaper_binding *binding, + /* Successful update: drop the tentative mark + * and update the hierarchy container. + */ +- __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + *cur = shapers[i]; ++ smp_wmb(); ++ __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + } + xa_unlock(&hierarchy->shapers); + } +@@ -837,6 +842,10 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb, + for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, + U32_MAX, NET_SHAPER_VALID)); + ctx->start_index++) { ++ /* Pairs with smp_wmb() in net_shaper_commit(): the entry ++ * is marked VALID, so its contents must be visible too. ++ */ ++ smp_rmb(); + ret = net_shaper_fill_one(skb, binding, shaper, info); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch b/queue-6.18/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch new file mode 100644 index 0000000000..290b5d1863 --- /dev/null +++ b/queue-6.18/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch @@ -0,0 +1,72 @@ +From 8b0ada1b26a016501683de8fd5f90dcb0613d5c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:00 -0700 +Subject: net: shaper: fix undersized reply skb allocation in GROUP command + +From: Jakub Kicinski + +[ Upstream commit 0f9a857e34d0f8c018a3e4435c6f0e92e8d2f38c ] + +net_shaper_group_send_reply() writes both the NET_SHAPER_A_IFINDEX +attribute (via net_shaper_fill_binding()) and the nested +NET_SHAPER_A_HANDLE attribute (via net_shaper_fill_handle()), but +the reply skb at the call site in net_shaper_nl_group_doit() is +allocated using net_shaper_handle_size(), which only accounts for +the nested handle. + +The allocation is therefore short by nla_total_size(sizeof(u32)) +(8 bytes) for the IFINDEX attribute. In practice the slab allocator +rounds up the small allocation so the bug is latent, but the size +accounting is wrong and could bite if the reply grew further. + +Introduce net_shaper_group_reply_size() that accounts for the full +reply payload and use it both at the genlmsg_new() call site and in +the defensive WARN_ONCE message. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-7-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index ee0d1f0613430..5338842122a2a 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -90,6 +90,12 @@ static int net_shaper_handle_size(void) + nla_total_size(sizeof(u32))); + } + ++static int net_shaper_group_reply_size(void) ++{ ++ return nla_total_size(sizeof(u32)) + /* NET_SHAPER_A_IFINDEX */ ++ net_shaper_handle_size(); /* NET_SHAPER_A_HANDLE */ ++} ++ + static int net_shaper_fill_binding(struct sk_buff *msg, + const struct net_shaper_binding *binding, + u32 type) +@@ -1228,7 +1234,7 @@ static int net_shaper_group_send_reply(struct net_shaper_binding *binding, + free_msg: + /* Should never happen as msg is pre-allocated with enough space. */ + WARN_ONCE(true, "calculated message payload length (%d)", +- net_shaper_handle_size()); ++ net_shaper_group_reply_size()); + nlmsg_free(msg); + return -EMSGSIZE; + } +@@ -1276,7 +1282,7 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + /* Prepare the msg reply in advance, to avoid device operation + * rollback on allocation failure. + */ +- msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL); ++ msg = genlmsg_new(net_shaper_group_reply_size(), GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto free_leaves; +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-flip-the-polarity-of-the-valid-flag.patch b/queue-6.18/net-shaper-flip-the-polarity-of-the-valid-flag.patch new file mode 100644 index 0000000000..d18b231ae4 --- /dev/null +++ b/queue-6.18/net-shaper-flip-the-polarity-of-the-valid-flag.patch @@ -0,0 +1,112 @@ +From af66e5b95093b4d5196b68dfdbfd8ba4c8daeb27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:55 -0700 +Subject: net: shaper: flip the polarity of the valid flag + +From: Jakub Kicinski + +[ Upstream commit 7cee43fcb0c3f71441d2faaa8c2202b6a88b6bef ] + +The usual way of inserting entries which are not yet fully ready +into XArray is to have a VALID flag. The shaper code has a NOT_VALID +flag. Since XArray code does not let us create entries with marks +already set - the creation of entries is currently not atomic. + +Flip the polarity of the VALID flag. This closes the tiny race +in net_shaper_pre_insert() of entries being created without +the NOT_VALID flag. + +Fixes: 93954b40f6a4 ("net-shapers: implement NL set and delete operations") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index e41a82241230d..64c9d6cf6756c 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -275,11 +275,13 @@ static void net_shaper_default_parent(const struct net_shaper_handle *handle, + parent->id = 0; + } + +-/* +- * MARK_0 is already in use due to XA_FLAGS_ALLOC, can't reuse such flag as +- * it's cleared by xa_store(). ++/* MARK_0 is already in use due to XA_FLAGS_ALLOC. The VALID mark is set on ++ * an entry only after the device-side configuration has completed ++ * successfully (see net_shaper_commit()). Lookups and dumps must filter on ++ * this mark to avoid exposing tentative entries inserted by ++ * net_shaper_pre_insert() while the driver call is still in flight. + */ +-#define NET_SHAPER_NOT_VALID XA_MARK_1 ++#define NET_SHAPER_VALID XA_MARK_1 + + static struct net_shaper * + net_shaper_lookup(struct net_shaper_binding *binding, +@@ -289,8 +291,8 @@ net_shaper_lookup(struct net_shaper_binding *binding, + struct net_shaper_hierarchy *hierarchy; + + hierarchy = net_shaper_hierarchy_rcu(binding); +- if (!hierarchy || xa_get_mark(&hierarchy->shapers, index, +- NET_SHAPER_NOT_VALID)) ++ if (!hierarchy || !xa_get_mark(&hierarchy->shapers, index, ++ NET_SHAPER_VALID)) + return NULL; + + return xa_load(&hierarchy->shapers, index); +@@ -370,13 +372,10 @@ static int net_shaper_pre_insert(struct net_shaper_binding *binding, + goto free_id; + } + +- /* Mark 'tentative' shaper inside the hierarchy container. +- * xa_set_mark is a no-op if the previous store fails. ++ /* Insert as 'tentative' (no VALID mark). The mark will be set by ++ * net_shaper_commit() once the driver-side configuration succeeds. + */ +- xa_lock(&hierarchy->shapers); +- prev = __xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL); +- __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_NOT_VALID); +- xa_unlock(&hierarchy->shapers); ++ prev = xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL); + if (xa_err(prev)) { + NL_SET_ERR_MSG(extack, "Can't insert shaper into device store"); + kfree_rcu(cur, rcu); +@@ -413,8 +412,7 @@ static void net_shaper_commit(struct net_shaper_binding *binding, + /* Successful update: drop the tentative mark + * and update the hierarchy container. + */ +- __xa_clear_mark(&hierarchy->shapers, index, +- NET_SHAPER_NOT_VALID); ++ __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + *cur = shapers[i]; + } + xa_unlock(&hierarchy->shapers); +@@ -431,8 +429,9 @@ static void net_shaper_rollback(struct net_shaper_binding *binding) + return; + + xa_lock(&hierarchy->shapers); +- xa_for_each_marked(&hierarchy->shapers, index, cur, +- NET_SHAPER_NOT_VALID) { ++ xa_for_each(&hierarchy->shapers, index, cur) { ++ if (xa_get_mark(&hierarchy->shapers, index, NET_SHAPER_VALID)) ++ continue; + __xa_erase(&hierarchy->shapers, index); + kfree(cur); + } +@@ -836,7 +835,8 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb, + goto out_unlock; + + for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, +- U32_MAX, XA_PRESENT)); ctx->start_index++) { ++ U32_MAX, NET_SHAPER_VALID)); ++ ctx->start_index++) { + ret = net_shaper_fill_one(skb, binding, shaper, info); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-reject-duplicate-leaves-in-group-request.patch b/queue-6.18/net-shaper-reject-duplicate-leaves-in-group-request.patch new file mode 100644 index 0000000000..347e6e6112 --- /dev/null +++ b/queue-6.18/net-shaper-reject-duplicate-leaves-in-group-request.patch @@ -0,0 +1,117 @@ +From 1ab1a5c67606c257d1c9503d548891c6300694bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:57 -0700 +Subject: net: shaper: reject duplicate leaves in GROUP request + +From: Jakub Kicinski + +[ Upstream commit a9a2fa1da619f276580b0d4c5d12efac89e8642b ] + +net_shaper_nl_group_doit() does not deduplicate NET_SHAPER_A_LEAVES +entries. When userspace supplies the same leaf handle twice, the same +old-parent pointer lands twice in old_nodes[]. The cleanup loop double +frees the parent. Of course the same parent may still be in old_nodes[] +twice if we are moving multiple of its leaves. + +Note that this patch also implicitly fixes the fact that the +i >= leaves_count path forgets to set ret. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-4-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 60 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 45 insertions(+), 15 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 92ca3b4c7925d..ae19af13c2247 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -941,6 +941,46 @@ static int net_shaper_handle_cmp(const struct net_shaper_handle *a, + return memcmp(a, b, sizeof(*a)); + } + ++static int net_shaper_parse_leaves(struct net_shaper_binding *binding, ++ struct genl_info *info, ++ const struct net_shaper *node, ++ struct net_shaper *leaves, ++ int leaves_count) ++{ ++ struct nlattr *attr; ++ int i, j, ret, rem; ++ ++ i = 0; ++ nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES, ++ genlmsg_data(info->genlhdr), ++ genlmsg_len(info->genlhdr), rem) { ++ if (WARN_ON_ONCE(i >= leaves_count)) ++ return -EINVAL; ++ ++ ret = net_shaper_parse_leaf(binding, attr, info, ++ node, &leaves[i]); ++ if (ret) ++ return ret; ++ ++ /* Reject duplicates */ ++ for (j = 0; j < i; j++) { ++ if (net_shaper_handle_cmp(&leaves[i].handle, ++ &leaves[j].handle)) ++ continue; ++ ++ NL_SET_ERR_MSG_ATTR_FMT(info->extack, attr, ++ "Duplicate leaf shaper %d:%d", ++ leaves[i].handle.scope, ++ leaves[i].handle.id); ++ return -EINVAL; ++ } ++ ++ i++; ++ } ++ ++ return 0; ++} ++ + static int net_shaper_parent_from_leaves(int leaves_count, + const struct net_shaper *leaves, + struct net_shaper *node, +@@ -1198,10 +1238,9 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + struct net_shaper **old_nodes, *leaves, node = {}; + struct net_shaper_hierarchy *hierarchy; + struct net_shaper_binding *binding; +- int i, ret, rem, leaves_count; ++ int i, ret, leaves_count; + int old_nodes_count = 0; + struct sk_buff *msg; +- struct nlattr *attr; + + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_LEAVES)) + return -EINVAL; +@@ -1229,19 +1268,10 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + if (ret) + goto free_leaves; + +- i = 0; +- nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES, +- genlmsg_data(info->genlhdr), +- genlmsg_len(info->genlhdr), rem) { +- if (WARN_ON_ONCE(i >= leaves_count)) +- goto free_leaves; +- +- ret = net_shaper_parse_leaf(binding, attr, info, +- &node, &leaves[i]); +- if (ret) +- goto free_leaves; +- i++; +- } ++ ret = net_shaper_parse_leaves(binding, info, &node, ++ leaves, leaves_count); ++ if (ret) ++ goto free_leaves; + + /* Prepare the msg reply in advance, to avoid device operation + * rollback on allocation failure. +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch b/queue-6.18/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch new file mode 100644 index 0000000000..9924155642 --- /dev/null +++ b/queue-6.18/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch @@ -0,0 +1,121 @@ +From 575563eb99639f6b32b2207bb08c80c99997b4d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:02 -0700 +Subject: net: shaper: reject handle IDs exceeding internal bit-width + +From: Jakub Kicinski + +[ Upstream commit 8d5806c600fddb907ebe378f9c366d4b52ac3a39 ] + +net_shaper_parse_handle() reads the user-supplied handle ID via +nla_get_u32(), accepting the full u32 range. However, the xarray key +is built by net_shaper_handle_to_index() using +FIELD_PREP(NET_SHAPER_ID_MASK, handle->id), where NET_SHAPER_ID_MASK +is GENMASK(25, 0) - only 26 bits wide. FIELD_PREP silently masks off +the upper bits at runtime. A user-supplied NODE id like 0x04000123 +becomes id 0x123. + +Additionally, a user-supplied id equal to NET_SHAPER_ID_UNSPEC +(0x03FFFFFF, which is NET_SHAPER_ID_MASK itself) would collide with +the sentinel used internally by the group operation to signal +"allocate a new NODE id". + +Reject user-supplied IDs >= NET_SHAPER_ID_MASK (i.e., >= 0x03FFFFFF) +in the policy. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-9-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/net_shaper.yaml | 7 +++++++ + net/shaper/shaper.c | 4 +++- + net/shaper/shaper_nl_gen.c | 7 ++++++- + net/shaper/shaper_nl_gen.h | 2 ++ + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/Documentation/netlink/specs/net_shaper.yaml b/Documentation/netlink/specs/net_shaper.yaml +index 3f2ad772b64b1..de01f922040a5 100644 +--- a/Documentation/netlink/specs/net_shaper.yaml ++++ b/Documentation/netlink/specs/net_shaper.yaml +@@ -33,6 +33,11 @@ doc: | + @cap-get operation. + + definitions: ++ - ++ type: const ++ name: max-handle-id ++ value: 0x3fffffe ++ scope: kernel + - + type: enum + name: scope +@@ -140,6 +145,8 @@ attribute-sets: + - + name: id + type: u32 ++ checks: ++ max: max-handle-id + doc: | + Numeric identifier of a shaper. The id semantic depends on + the scope. For @queue scope it's the queue id and for @node +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 5338842122a2a..b2d85963243fa 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -21,6 +21,8 @@ + + #define NET_SHAPER_ID_UNSPEC NET_SHAPER_ID_MASK + ++static_assert(NET_SHAPER_ID_UNSPEC == NET_SHAPER_MAX_HANDLE_ID + 1); ++ + struct net_shaper_hierarchy { + struct xarray shapers; + }; +@@ -360,7 +362,7 @@ static int net_shaper_pre_insert(struct net_shaper_binding *binding, + handle->id == NET_SHAPER_ID_UNSPEC) { + u32 min, max; + +- handle->id = NET_SHAPER_ID_MASK - 1; ++ handle->id = NET_SHAPER_MAX_HANDLE_ID; + max = net_shaper_handle_to_index(handle); + handle->id = 0; + min = net_shaper_handle_to_index(handle); +diff --git a/net/shaper/shaper_nl_gen.c b/net/shaper/shaper_nl_gen.c +index c52abf13ff0c9..16ab88f5eb7b4 100644 +--- a/net/shaper/shaper_nl_gen.c ++++ b/net/shaper/shaper_nl_gen.c +@@ -10,10 +10,15 @@ + + #include + ++/* Integer value ranges */ ++static const struct netlink_range_validation net_shaper_a_handle_id_range = { ++ .max = NET_SHAPER_MAX_HANDLE_ID, ++}; ++ + /* Common nested types */ + const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1] = { + [NET_SHAPER_A_HANDLE_SCOPE] = NLA_POLICY_MAX(NLA_U32, 3), +- [NET_SHAPER_A_HANDLE_ID] = { .type = NLA_U32, }, ++ [NET_SHAPER_A_HANDLE_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &net_shaper_a_handle_id_range), + }; + + const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1] = { +diff --git a/net/shaper/shaper_nl_gen.h b/net/shaper/shaper_nl_gen.h +index 1e20eebdedd71..3e5e7342ffbbc 100644 +--- a/net/shaper/shaper_nl_gen.h ++++ b/net/shaper/shaper_nl_gen.h +@@ -11,6 +11,8 @@ + + #include + ++#define NET_SHAPER_MAX_HANDLE_ID 67108862 ++ + /* Common nested types */ + extern const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1]; + extern const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1]; +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-reject-queue-scope-handle-with-missing-id.patch b/queue-6.18/net-shaper-reject-queue-scope-handle-with-missing-id.patch new file mode 100644 index 0000000000..e2becfbd6b --- /dev/null +++ b/queue-6.18/net-shaper-reject-queue-scope-handle-with-missing-id.patch @@ -0,0 +1,55 @@ +From d32293a477f7e85265646e1fb85ab4a61d46a156 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:04 -0700 +Subject: net: shaper: reject QUEUE scope handle with missing id + +From: Jakub Kicinski + +[ Upstream commit ce372e869f9f492f3d5aa9a0ae75ed52c61d2d6f ] + +net_shaper_parse_handle() does not enforce that the user provides +the handle ID. For NODE the ID defaults to UNSPEC for all other +cases it defaults to 0. + +For NETDEV 0 is the only option. For QUEUE defaulting to 0 makes +less intuitive sense. Specifically because the behavior should +(IMHO) be the same for all cases where there may be more than +one ID (QUEUE and NODE). + +We should either document this as intentional or reject. +I picked the latter with no strong conviction. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-11-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index d65008b819dc9..23d535f157294 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -477,10 +477,15 @@ static int net_shaper_parse_handle(const struct nlattr *attr, + * shaper (any other value). + */ + id_attr = tb[NET_SHAPER_A_HANDLE_ID]; +- if (id_attr) ++ if (id_attr) { + id = nla_get_u32(id_attr); +- else if (handle->scope == NET_SHAPER_SCOPE_NODE) ++ } else if (handle->scope == NET_SHAPER_SCOPE_NODE) { + id = NET_SHAPER_ID_UNSPEC; ++ } else if (handle->scope == NET_SHAPER_SCOPE_QUEUE) { ++ NL_SET_ERR_ATTR_MISS(info->extack, attr, ++ NET_SHAPER_A_HANDLE_ID); ++ return -EINVAL; ++ } + + if (id && handle->scope == NET_SHAPER_SCOPE_NETDEV) { + NL_SET_ERR_MSG_ATTR(info->extack, id_attr, +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-reject-reparenting-of-existing-nodes.patch b/queue-6.18/net-shaper-reject-reparenting-of-existing-nodes.patch new file mode 100644 index 0000000000..c72ef25812 --- /dev/null +++ b/queue-6.18/net-shaper-reject-reparenting-of-existing-nodes.patch @@ -0,0 +1,90 @@ +From 8bcff22fe944e7a3e46c2f293171ccb241d094f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 16:37:45 -0700 +Subject: net: shaper: Reject reparenting of existing nodes + +From: Mohsin Bashir + +[ Upstream commit a77d5a069d959dc45f5f472d48cba37d8cba0f1c ] + +When an existing node-scope shaper is moved to a different parent +via the group operation, the framework fails to update the leaves +count on both the old and new parent shapers. Only newly created +nodes (handle.id == NET_SHAPER_ID_UNSPEC) trigger the parent +leaves increment at line 1039. + +This causes the parent's leaves counter to diverge from the +actual number of children in the xarray. When the node is later +deleted, pre_del_node() allocates an array sized by the stale +leaves count, but the xarray iteration finds more children than +expected, hitting the WARN_ON_ONCE guard and returning -EINVAL. + +Rather than adding reparenting support with complex leaves count +bookkeeping, reject group calls that attempt to change an existing +node's parent. Updates to an existing node's rate or leaves under +the same parent remain permitted. We expect that for any modification +of the topology user should always create new groups and let the +kernel garbage collect the leaf-less nodes. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Mohsin Bashir +Link: https://patch.msgid.link/20260506233745.111895-1-mohsin.bashr@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index be9999ab62e39..e41a82241230d 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -964,15 +964,22 @@ static int __net_shaper_group(struct net_shaper_binding *binding, + int i, ret; + + if (node->handle.scope == NET_SHAPER_SCOPE_NODE) { ++ struct net_shaper *cur = NULL; ++ + new_node = node->handle.id == NET_SHAPER_ID_UNSPEC; + +- if (!new_node && !net_shaper_lookup(binding, &node->handle)) { +- /* The related attribute is not available when +- * reaching here from the delete() op. +- */ +- NL_SET_ERR_MSG_FMT(extack, "Node shaper %d:%d does not exists", +- node->handle.scope, node->handle.id); +- return -ENOENT; ++ if (!new_node) { ++ cur = net_shaper_lookup(binding, &node->handle); ++ if (!cur) { ++ /* The related attribute is not available ++ * when reaching here from the delete() op. ++ */ ++ NL_SET_ERR_MSG_FMT(extack, ++ "Node shaper %d:%d does not exist", ++ node->handle.scope, ++ node->handle.id); ++ return -ENOENT; ++ } + } + + /* When unspecified, the node parent scope is inherited from +@@ -986,6 +993,15 @@ static int __net_shaper_group(struct net_shaper_binding *binding, + return ret; + } + ++ if (cur && net_shaper_handle_cmp(&cur->parent, ++ &node->parent)) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "Cannot reparent node shaper %d:%d", ++ node->handle.scope, ++ node->handle.id); ++ return -EOPNOTSUPP; ++ } ++ + } else { + net_shaper_default_parent(&node->handle, &node->parent); + } +-- +2.53.0 + diff --git a/queue-6.18/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch b/queue-6.18/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch new file mode 100644 index 0000000000..5f0f536684 --- /dev/null +++ b/queue-6.18/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch @@ -0,0 +1,41 @@ +From 48e91624c251a7bae2f1139a37c5247d19fa0883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:59 -0700 +Subject: net: shaper: set ret to -ENOMEM when genlmsg_new() fails in + group_doit + +From: Jakub Kicinski + +[ Upstream commit 8054f85b83f42a37d482fc77ea7c9ff06a9407d9 ] + +genlmsg_new() alloc failure path in net_shaper_nl_group_doit() forgets +to set ret before jumping to error handling. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-6-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index ae19af13c2247..ee0d1f0613430 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -1277,8 +1277,10 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + * rollback on allocation failure. + */ + msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL); +- if (!msg) ++ if (!msg) { ++ ret = -ENOMEM; + goto free_leaves; ++ } + + hierarchy = net_shaper_hierarchy_setup(binding); + if (!hierarchy) { +-- +2.53.0 + diff --git a/queue-6.18/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch b/queue-6.18/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch new file mode 100644 index 0000000000..0ee2fc6e42 --- /dev/null +++ b/queue-6.18/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch @@ -0,0 +1,65 @@ +From 17ae11fc7e397ef28ee3124167b7856438119f00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 15:26:40 -0700 +Subject: net/smc: avoid NULL deref of conn->lnk in smc_msg_event tracepoint + +From: Xiang Mei + +[ Upstream commit 7bf563badd37cb796df5477d2b78bb64148a1268 ] + +The smc_msg_event tracepoint class, shared by smc_tx_sendmsg and +smc_rx_recvmsg, unconditionally dereferences smc->conn.lnk: + + __string(name, smc->conn.lnk->ibname) + +conn->lnk is only set for SMC-R; for SMC-D it is NULL. Other code on +these paths already handles this (e.g. !conn->lnk in +SMC_STAT_RMB_TX_SIZE_SMALL()). With the tracepoint enabled, the first +sendmsg()/recvmsg() on an SMC-D socket crashes: + + Oops: general protection fault, probably for non-canonical address + KASAN: null-ptr-deref in range [...] + RIP: 0010:strlen+0x1e/0xa0 + Call Trace: + trace_event_raw_event_smc_msg_event (net/smc/smc_tracepoint.h:44) + smc_rx_recvmsg (net/smc/smc_rx.c:515) + smc_recvmsg (net/smc/af_smc.c:2859) + __sys_recvfrom (net/socket.c:2315) + __x64_sys_recvfrom (net/socket.c:2326) + do_syscall_64 + +The faulting address 0x3e0 is offsetof(struct smc_link, ibname), +confirming the NULL ->lnk deref. Enabling the tracepoint requires +root, but the trigger itself is unprivileged: socket(AF_SMC, ...) has +no capability check, and SMC-D negotiation needs no admin step on +s390 or on x86 with the loopback ISM device loaded. + +Log an empty device name for SMC-D instead of dereferencing NULL. + +Fixes: aff3083f10bf ("net/smc: Introduce tracepoints for tx and rx msg") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Dust Li +Reviewed-by: Sidraya Jayagond +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/smc_tracepoint.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/smc/smc_tracepoint.h b/net/smc/smc_tracepoint.h +index a9a6e3c1113aa..53da84f57fd6f 100644 +--- a/net/smc/smc_tracepoint.h ++++ b/net/smc/smc_tracepoint.h +@@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(smc_msg_event, + __field(const void *, smc) + __field(u64, net_cookie) + __field(size_t, len) +- __string(name, smc->conn.lnk->ibname) ++ __string(name, smc->conn.lnk ? smc->conn.lnk->ibname : "") + ), + + TP_fast_assign( +-- +2.53.0 + diff --git a/queue-6.18/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch b/queue-6.18/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch new file mode 100644 index 0000000000..1a1a6631c7 --- /dev/null +++ b/queue-6.18/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch @@ -0,0 +1,63 @@ +From f0c184fb1dea790544424a02e305c3c16c5434ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 23:21:38 -0700 +Subject: net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot + +From: Xiang Mei + +[ Upstream commit 277740023def559a4a2ddc3e8e784ee37a0f16a9 ] + +On the SMC-D client, slot 0 of ini->ism_dev[]/ini->ism_chid[] is +reserved for an SMC-Dv1 device. smc_find_ism_v2_device_clnt() +populates V2 entries starting at index 1, so when no V1 device is +selected slot 0 is left in its kzalloc()'ed state with ism_dev[0] == +NULL and ism_chid[0] == 0. + +smc_v2_determine_accepted_chid() then matches the peer's CHID against +the array starting from index 0 using the CHID alone. A malicious +peer replying to a SMC-Dv2-only proposal with d1.chid == 0 matches +the empty slot, ini->ism_selected becomes 0, and the subsequent +ism_dev[0]->lgr_lock dereference in smc_conn_create() faults at +offsetof(struct smcd_dev, lgr_lock) == 0x68: + + BUG: KASAN: null-ptr-deref in _raw_spin_lock_bh+0x79/0xe0 + Write of size 4 at addr 0000000000000068 by task exploit/144 + Call Trace: + _raw_spin_lock_bh + smc_conn_create (net/smc/smc_core.c:1997) + __smc_connect (net/smc/af_smc.c:1447) + smc_connect (net/smc/af_smc.c:1720) + __sys_connect + __x64_sys_connect + do_syscall_64 + +Require ism_dev[i] to be non-NULL before accepting a CHID match. + +Fixes: a7c9c5f4af7f ("net/smc: CLC accept / confirm V2") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260511062138.2839584-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 6421c2e1c84de..5915fcdef743d 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1400,7 +1400,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc, + int i; + + for (i = 0; i < ini->ism_offered_cnt + 1; i++) { +- if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) { ++ if (ini->ism_dev[i] && ++ ini->ism_chid[i] == ntohs(aclc->d1.chid)) { + ini->ism_selected = i; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch b/queue-6.18/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch new file mode 100644 index 0000000000..a030c41ad9 --- /dev/null +++ b/queue-6.18/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch @@ -0,0 +1,39 @@ +From bc9e01a4c2dedae7b2cc901754d650e4f6c608ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 01:28:13 +0530 +Subject: net: ti: icssm-prueth: fix eth_ports_node leak in probe + +From: Shitalkumar Gandhi + +[ Upstream commit 6635fa84403c3a59455b66007c019a7cc632db30 ] + +The error path on of_property_read_u32() failure inside +icssm_prueth_probe() returns without putting eth_ports_node, +which was acquired before the for_each_child_of_node() loop. + +Drop it before returning. + +Fixes: 511f6c1ae093 ("net: ti: icssm-prueth: Adds ICSSM Ethernet driver") +Signed-off-by: Shitalkumar Gandhi +Link: https://patch.msgid.link/20260506195813.641610-1-shitalkumar.gandhi@cambiumnetworks.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c +index 293b7af04263f..cc92f20685843 100644 +--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c ++++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c +@@ -1347,6 +1347,7 @@ static int icssm_prueth_probe(struct platform_device *pdev) + dev_err(dev, "%pOF error reading port_id %d\n", + eth_node, ret); + of_node_put(eth_node); ++ of_node_put(eth_ports_node); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-6.18/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..82cb9bde82 --- /dev/null +++ b/queue-6.18/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From ffdc1ae181dc39f735f758f26e0450e54d9908ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index f2ea190777f0b..1ad5d0e7ae27f 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -800,11 +800,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-6.18/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-6.18/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..38487a9195 --- /dev/null +++ b/queue-6.18/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From f16b7b1becdab71f0435d9a9d6e0497a2f66abd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 1ad5d0e7ae27f..b28eb04075d1b 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -789,21 +789,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-6.18/net-wangxun-reorder-timer-and-work-sync-cancellation.patch b/queue-6.18/net-wangxun-reorder-timer-and-work-sync-cancellation.patch new file mode 100644 index 0000000000..2ba8f8f376 --- /dev/null +++ b/queue-6.18/net-wangxun-reorder-timer-and-work-sync-cancellation.patch @@ -0,0 +1,64 @@ +From db34ae47fe6a72cb06a46986d9c9da1d223f69e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:56:13 +0800 +Subject: net: wangxun: reorder timer and work sync cancellations + +From: Jiawen Wu + +[ Upstream commit 58f6303572ec66e7c2967ac168125f444c9e880d ] + +When removing the device, timer_delete_sync(&wx->service_timer) is +called in .ndo_stop() after cancel_work_sync(&wx->service_task). This +may cause new work to be queued after device down. + +Move unregister_netdev() before cancel_work_sync(), and use +timer_shutdown_sync() to prevent the timer from being re-armed. + +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260407025616.33652-7-jiawenwu@trustnetic.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/libwx/wx_vf_common.c | 3 ++- + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c +index 5478f2fdfce88..df8b4a3727c34 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c ++++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c +@@ -48,9 +48,10 @@ void wxvf_remove(struct pci_dev *pdev) + struct wx *wx = pci_get_drvdata(pdev); + struct net_device *netdev; + +- cancel_work_sync(&wx->service_task); + netdev = wx->netdev; + unregister_netdev(netdev); ++ timer_shutdown_sync(&wx->service_timer); ++ cancel_work_sync(&wx->service_task); + kfree(wx->vfinfo); + kfree(wx->rss_key); + kfree(wx->mac_table); +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +index 1377ea90a8c28..db51ebc4ac781 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +@@ -951,12 +951,13 @@ static void txgbe_remove(struct pci_dev *pdev) + struct txgbe *txgbe = wx->priv; + struct net_device *netdev; + +- cancel_work_sync(&wx->service_task); +- + netdev = wx->netdev; + wx_disable_sriov(wx); + unregister_netdev(netdev); + ++ timer_shutdown_sync(&wx->service_timer); ++ cancel_work_sync(&wx->service_task); ++ + txgbe_remove_phy(txgbe); + wx_free_isb_resources(wx); + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-6.18/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..25c3790639 --- /dev/null +++ b/queue-6.18/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From 4a9e60702dc3bd906e0305bae45735a462c78b50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index bfaba18f0e6a8..77df9e856c2e7 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2583,19 +2583,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-6.18/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..c10d144f44 --- /dev/null +++ b/queue-6.18/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From d7c0720daed1cf9d3ba82d4be23d63f12d97f674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index e6f9e343b41f1..f05c79f215ea0 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 02b6501c15a5e..0fc03b07e62ae 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -93,18 +93,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 9985a82555c41..8a10375d89099 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -93,16 +93,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-6.18/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..68164ea54e --- /dev/null +++ b/queue-6.18/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From 775c12d21e35e404fe5918ed9ac7a83b5e511e3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 7413602195525..e6f9e343b41f1 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index dacd81b12e626..02b6501c15a5e 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 0f2a8c6118d42..9985a82555c41 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index a04fc17575289..bfaba18f0e6a8 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2556,11 +2560,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-6.18/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..4a07adece1 --- /dev/null +++ b/queue-6.18/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From 114daa7499b3900b692fb3e68c889ac10f94df96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 86d5fc5d28e3b..3e2d521546600 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -78,7 +78,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -789,6 +792,9 @@ static void dump_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-6.18/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..23936d65dd --- /dev/null +++ b/queue-6.18/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From dc71f9a4d88a52190b90e76bfa78ed2a1b5fcb0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 77c778d84d4cb..f7916fd0e8073 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -300,6 +300,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 132b0e4a6d4df..13593391d6058 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 8b8885a73c764..c6d5b927830dd 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 97ead883e4a13..d19fce8589809 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1581,15 +1581,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 23c8deff8095a..663868cc5f6d6 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1789,14 +1789,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1887,7 +1879,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 595bfb492b1c1..0dea754a91209 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -61,7 +61,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index db90db7057cc4..4d3b124923080 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -96,7 +96,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 625a1ca13b1ba..8fc4912e790d8 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -129,6 +129,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index b46a790917306..6f7afec7954bd 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -53,7 +53,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 2b89adc1e5751..81175c20ccbe8 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -50,7 +50,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index d585ac3c11133..08abf0df04500 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1795,14 +1795,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1894,7 +1886,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 9dcd4501fe800..cf561919bde84 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -60,7 +60,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index ce2cbce9e3ed3..1a758f2bc5379 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -89,7 +89,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 5be723232df8f..bb8aa3fc42b45 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -131,6 +131,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 8af0f8bd036dc..923455921c1dd 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -52,7 +52,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 66018b169b010..c44834d93fc79 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -49,7 +49,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 1ca4fa9d249b8..2d93f189a79b9 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1538,6 +1538,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-6.18/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-6.18/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..f6c2fc6bf8 --- /dev/null +++ b/queue-6.18/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From 2e762ed9cd0e72e216c075d9b193bc155cf64f2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index f7916fd0e8073..3aef60abd362c 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -299,8 +299,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index d19fce8589809..f3dadbc416a3a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1583,7 +1582,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 663868cc5f6d6..f4079f0718dea 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1704,12 +1704,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1718,6 +1716,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1791,7 +1790,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 8fc4912e790d8..a0df725540251 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -119,8 +119,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 08abf0df04500..dfaea4f6727ed 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1713,12 +1713,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1727,6 +1725,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1797,7 +1796,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index bb8aa3fc42b45..c2394e2c94b56 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -121,8 +121,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 2d93f189a79b9..76fd0999db4a8 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1522,23 +1525,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1548,6 +1534,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1557,6 +1551,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1567,6 +1562,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2013,8 +2052,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2023,8 +2064,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-6.18/netfilter-x_tables-close-dangling-table-module-init-.patch b/queue-6.18/netfilter-x_tables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..6258470414 --- /dev/null +++ b/queue-6.18/netfilter-x_tables-close-dangling-table-module-init-.patch @@ -0,0 +1,406 @@ +From 163c46bbda75f50b1870c60fc187273b5c469b44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:20 +0200 +Subject: netfilter: x_tables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 16bc4b6686b2c112c10e67d6b493adc3607256d3 ] + +Similar to the previous ebtables patch: +template add exposes the table to userspace, we must do this last to +rnsure the pernet ops are set up (contain the destructors). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_mangle.c | 25 +++++++++++++------------ + net/ipv4/netfilter/iptable_raw.c | 22 +++++++++++----------- + net/ipv4/netfilter/iptable_security.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_filter.c | 22 +++++++++++----------- + net/ipv6/netfilter/ip6table_mangle.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_raw.c | 20 ++++++++++---------- + net/ipv6/netfilter/ip6table_security.c | 23 ++++++++++++----------- + 9 files changed, 105 insertions(+), 99 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 382345567a600..370b635e3523b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = { + + static int __init arptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- arptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); +- if (IS_ERR(arpfilter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(arpfilter_ops)) + return PTR_ERR(arpfilter_ops); +- } + + ret = register_pernet_subsys(&arptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ arptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(arpfilter_ops); +- return ret; ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(arpfilter_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 0dea754a91209..672d7da1071d3 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = { + + static int __init iptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- iptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&iptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ iptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_filter_net_ops); ++ goto err_free; + } + + return 0; ++err_free: ++ kfree(filter_ops); ++ return ret; + } + + static void __exit iptable_filter_fini(void) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 4d3b124923080..13d25d9a4610e 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -111,25 +111,26 @@ static struct pernet_operations iptable_mangle_net_ops = { + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); +- ret = PTR_ERR(mangle_ops); +- return ret; +- } ++ if (IS_ERR(mangle_ops)) ++ return PTR_ERR(mangle_ops); + + ret = register_pernet_subsys(&iptable_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ iptable_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 6f7afec7954bd..2745c22f4034d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, +- iptable_raw_table_init); +- if (ret < 0) +- return ret; +- + rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&iptable_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ++ iptable_raw_table_init); + if (ret < 0) { +- xt_unregister_template(table); +- kfree(rawtable_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 81175c20ccbe8..491894511c544 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = { + + static int __init iptable_security_init(void) + { +- int ret = xt_register_template(&security_table, +- iptable_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&iptable_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ iptable_security_table_init); + if (ret < 0) { +- xt_unregister_template(&security_table); +- kfree(sectbl_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index cf561919bde84..b074fc4776764 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = { + + static int __init ip6table_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- ip6table_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&ip6table_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ip6table_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(filter_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 1a758f2bc5379..e6ee036a9b2c5 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -104,25 +104,26 @@ static struct pernet_operations ip6table_mangle_net_ops = { + + static int __init ip6table_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- ip6table_mangle_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); ++ if (IS_ERR(mangle_ops)) + return PTR_ERR(mangle_ops); +- } + + ret = register_pernet_subsys(&ip6table_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ ip6table_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 923455921c1dd..3b161ee875bcc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, ip6table_raw_table_init); +- if (ret < 0) +- return ret; +- + /* Register hooks */ + rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&ip6table_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ip6table_raw_table_init); + if (ret < 0) { +- kfree(rawtable_ops); +- xt_unregister_template(table); +- return ret; ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index c44834d93fc79..4bd5d97b8ab65 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = { + + static int __init ip6table_security_init(void) + { +- int ret = xt_register_template(&security_table, +- ip6table_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&ip6table_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ ip6table_security_table_init); + if (ret < 0) { +- kfree(sectbl_ops); +- xt_unregister_template(&security_table); +- return ret; ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-x_tables-unregister-the-templates-first.patch b/queue-6.18/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..52c0ad1a70 --- /dev/null +++ b/queue-6.18/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From 2cfe47c0d08679bd88725fc850da65e62fc6fc42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 78cd5ee24448f..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -82,8 +82,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 3ab908b747951..595bfb492b1c1 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -101,8 +101,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 385d945d8ebea..db90db7057cc4 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -135,8 +135,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 0e7f53964d0af..b46a790917306 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -100,9 +100,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index d885443cb2679..2b89adc1e5751 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -89,9 +89,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index e8992693e14a0..9dcd4501fe800 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -100,8 +100,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 8dd4cd0c47bd4..ce2cbce9e3ed3 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -128,8 +128,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index fc9f6754028f2..8af0f8bd036dc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -98,8 +98,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 4df14a9bae782..66018b169b010 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -88,8 +88,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-6.18/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch b/queue-6.18/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch new file mode 100644 index 0000000000..8c2fee7483 --- /dev/null +++ b/queue-6.18/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch @@ -0,0 +1,90 @@ +From 9cefdb313b0349e2af1d5b561b260402fdb3b58c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:34:00 +0100 +Subject: netfs, afs: Fix write skipping in dir/link writepages + +From: David Howells + +[ Upstream commit 9871938f99cc6cb266a77265491660e2375271f5 ] + +Fix netfs_write_single() and afs_single_writepages() to better handle a +write that would be skipped due to lock contention and WB_SYNC_NONE by +returning 1 from netfs_write_single() if it skipped and making +afs_single_writepages() skip also. If a skip occurs, the inode must be +re-marked as the VFS may have cleared the mark. + +This is really only theoretical for directories in netfs_write_single() as +the only path to that is through afs_single_writepages() that takes the +->validate_lock around it, thereby serialising it. + +Fixes: 6dd80936618c ("afs: Use netfslib for directories") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-24-dhowells@redhat.com +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/afs/dir.c | 11 ++++++++++- + fs/netfs/write_issue.c | 7 ++++++- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index 89d36e3e5c799..fa84610e0b0d9 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -2207,7 +2207,14 @@ int afs_single_writepages(struct address_space *mapping, + /* Need to lock to prevent the folio queue and folios from being thrown + * away. + */ +- down_read(&dvnode->validate_lock); ++ if (!down_read_trylock(&dvnode->validate_lock)) { ++ if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* The VFS will have undirtied the inode. */ ++ netfs_single_mark_inode_dirty(&dvnode->netfs.inode); ++ return 0; ++ } ++ down_read(&dvnode->validate_lock); ++ } + + if (is_dir ? + test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) : +@@ -2215,6 +2222,8 @@ int afs_single_writepages(struct address_space *mapping, + iov_iter_folio_queue(&iter, ITER_SOURCE, dvnode->directory, 0, 0, + i_size_read(&dvnode->netfs.inode)); + ret = netfs_writeback_single(mapping, wbc, &iter); ++ if (ret == 1) ++ ret = 0; /* Skipped write due to lock conflict. */ + } + + up_read(&dvnode->validate_lock); +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index 9bf05099155dc..03d170b9022b7 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -829,6 +829,9 @@ static int netfs_write_folio_single(struct netfs_io_request *wreq, + * + * Write a monolithic, non-pagecache object back to the server and/or + * the cache. ++ * ++ * Return: 0 if successful; 1 if skipped due to lock conflict and WB_SYNC_NONE; ++ * or a negative error code. + */ + int netfs_writeback_single(struct address_space *mapping, + struct writeback_control *wbc, +@@ -845,8 +848,10 @@ int netfs_writeback_single(struct address_space *mapping, + + if (!mutex_trylock(&ictx->wb_lock)) { + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* The VFS will have undirtied the inode. */ ++ netfs_single_mark_inode_dirty(&ictx->inode); + netfs_stat(&netfs_n_wb_lock_skip); +- return 0; ++ return 1; + } + netfs_stat(&netfs_n_wb_lock_wait); + mutex_lock(&ictx->wb_lock); +-- +2.53.0 + diff --git a/queue-6.18/netfs-defer-the-emission-of-trace_netfs_folio.patch b/queue-6.18/netfs-defer-the-emission-of-trace_netfs_folio.patch new file mode 100644 index 0000000000..592b63bbbe --- /dev/null +++ b/queue-6.18/netfs-defer-the-emission-of-trace_netfs_folio.patch @@ -0,0 +1,116 @@ +From 96ce3e795a696cda427ea476197d90e2b8dc108a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:49 +0100 +Subject: netfs: Defer the emission of trace_netfs_folio() + +From: David Howells + +[ Upstream commit daeb443b92817021c1234e8eded219e164b7c35d ] + +Change netfs_perform_write() to keep the netfs_folio trace value in a +variable and emit it later to make it easier to choose the value displayed. +This is a prerequisite for a subsequent patch. + +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-13-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Stable-dep-of: 7b4dcf1b9455 ("netfs: Fix streaming write being overwritten") +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 09394ac2c180d..1fa13c2629a73 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -150,6 +150,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + do { ++ enum netfs_folio_trace trace; + struct netfs_folio *finfo; + struct netfs_group *group; + unsigned long long fpos; +@@ -223,7 +224,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_folio_is_uptodate); ++ trace = netfs_folio_is_uptodate; + goto copied; + } + +@@ -239,7 +240,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + folio_zero_segment(folio, offset + copied, flen); + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_modify_and_clear); ++ trace = netfs_modify_and_clear; + goto copied; + } + +@@ -257,7 +258,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_whole_folio_modify); ++ trace = netfs_whole_folio_modify; + goto copied; + } + +@@ -284,7 +285,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_just_prefetch); ++ trace = netfs_just_prefetch; + goto copied; + } + +@@ -298,7 +299,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (offset == 0 && copied == flen) { + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_streaming_filled_page); ++ trace = netfs_streaming_filled_page; + goto copied; + } + +@@ -313,7 +314,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len = copied; + folio_attach_private(folio, (void *)((unsigned long)finfo | + NETFS_FOLIO_INFO)); +- trace_netfs_folio(folio, netfs_streaming_write); ++ trace = netfs_streaming_write; + goto copied; + } + +@@ -333,9 +334,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + folio_detach_private(folio); + folio_mark_uptodate(folio); + kfree(finfo); +- trace_netfs_folio(folio, netfs_streaming_cont_filled_page); ++ trace = netfs_streaming_cont_filled_page; + } else { +- trace_netfs_folio(folio, netfs_streaming_write_cont); ++ trace = netfs_streaming_write_cont; + } + goto copied; + } +@@ -351,6 +352,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + continue; + + copied: ++ trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); + + /* Update the inode size if we moved the EOF marker */ +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch b/queue-6.18/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch new file mode 100644 index 0000000000..ce34d74976 --- /dev/null +++ b/queue-6.18/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch @@ -0,0 +1,342 @@ +From e06ba235256857b2115dc2a0ae84c390cf267169 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:38 +0100 +Subject: netfs: Fix cancellation of a DIO and single read subrequests + +From: David Howells + +[ Upstream commit 6f0f7ac1915abc0d202f0eb4b003a6548a5ba60d ] + +When the preparation of a new subrequest for a read fails, if the +subrequest has already been added to the stream->subrequests list, it can't +simply be put and abandoned as the collector may see it. Also, if it +hasn't been queued yet, it has two outstanding refs that both need to be +put. Both DIO read and single-read dispatch fail at this; further, both +differ in the order they do things to the way buffered read works. + +Fix cancellation of both DIO-read and single-read subrequests that failed +preparation by the following steps: + + (1) Harmonise all three reads (buffered, dio, single) to queue the subreq + before prepping it. + + (2) Make all three call netfs_queue_read() to do the queuing. + + (3) Set NETFS_RREQ_ALL_QUEUED independently of the queuing as we don't + know the length of the subreq at this point. + + (4) In all cases, set the error and NETFS_SREQ_FAILED flag on the subreq + and then call netfs_read_subreq_terminated() to deal with it. This + will pass responsibility off to the collector for dealing with it. + +Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") +Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-2-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 34 +++++++++++++------------------- + fs/netfs/direct_read.c | 42 +++++++++++++--------------------------- + fs/netfs/internal.h | 3 +++ + fs/netfs/read_collect.c | 11 +++++++++++ + fs/netfs/read_single.c | 23 ++++++++++------------ + 5 files changed, 50 insertions(+), 63 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 88361e8c70961..10b13924ed543 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -156,9 +156,8 @@ static void netfs_read_cache_to_pagecache(struct netfs_io_request *rreq, + netfs_cache_read_terminated, subreq); + } + +-static void netfs_queue_read(struct netfs_io_request *rreq, +- struct netfs_io_subrequest *subreq, +- bool last_subreq) ++void netfs_queue_read(struct netfs_io_request *rreq, ++ struct netfs_io_subrequest *subreq) + { + struct netfs_io_stream *stream = &rreq->io_streams[0]; + +@@ -178,11 +177,6 @@ static void netfs_queue_read(struct netfs_io_request *rreq, + } + } + +- if (last_subreq) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- } +- + spin_unlock(&rreq->lock); + } + +@@ -233,6 +227,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + subreq->start = start; + subreq->len = size; + ++ netfs_queue_read(rreq, subreq); ++ + source = netfs_cache_prepare_read(rreq, subreq, rreq->i_size); + subreq->source = source; + if (source == NETFS_DOWNLOAD_FROM_SERVER) { +@@ -253,6 +249,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + rreq->debug_id, subreq->debug_index, + subreq->len, size, + subreq->start, ictx->zero_point, rreq->i_size); ++ netfs_cancel_read(subreq, ret); + break; + } + subreq->len = len; +@@ -261,12 +258,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); + if (ret < 0) { +- subreq->error = ret; +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, +- netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, +- netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } + trace_netfs_sreq(subreq, netfs_sreq_trace_prepare); +@@ -289,23 +281,23 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + + pr_err("Unexpected read source %u\n", source); + WARN_ON_ONCE(1); ++ netfs_cancel_read(subreq, ret); + break; + + issue: + slice = netfs_prepare_read_iterator(subreq, ractl); + if (slice < 0) { + ret = slice; +- subreq->error = ret; +- trace_netfs_sreq(subreq, netfs_sreq_trace_cancel); +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } +- size -= slice; + start += slice; ++ size -= slice; ++ if (size <= 0) { ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); ++ } + +- netfs_queue_read(rreq, subreq, size <= 0); + netfs_issue_read(rreq, subreq); + cond_resched(); + } while (size > 0); +diff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c +index f72e6da88cca7..6a8fb0d55e040 100644 +--- a/fs/netfs/direct_read.c ++++ b/fs/netfs/direct_read.c +@@ -45,12 +45,11 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq) + * Perform a read to a buffer from the server, slicing up the region to be read + * according to the network rsize. + */ +-static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) ++static void netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + unsigned long long start = rreq->start; + ssize_t size = rreq->len; +- int ret = 0; ++ int ret; + + do { + struct netfs_io_subrequest *subreq; +@@ -58,7 +57,10 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + + subreq = netfs_alloc_subrequest(rreq); + if (!subreq) { +- ret = -ENOMEM; ++ /* Stash the error in the request if there's not ++ * already an error set. ++ */ ++ cmpxchg(&rreq->error, 0, -ENOMEM); + break; + } + +@@ -66,25 +68,13 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + subreq->start = start; + subreq->len = size; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { +- if (!stream->active) { +- stream->collected_to = subreq->start; +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- } +- } +- trace_netfs_sreq(subreq, netfs_sreq_trace_added); +- spin_unlock(&rreq->lock); ++ netfs_queue_read(rreq, subreq); + + netfs_stat(&netfs_n_rh_download); + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); + if (ret < 0) { +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } + } +@@ -113,8 +103,6 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + netfs_wake_collector(rreq); + } +- +- return ret; + } + + /* +@@ -137,21 +125,17 @@ static ssize_t netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync) + // TODO: Use bounce buffer if requested + + inode_dio_begin(rreq->inode); ++ netfs_dispatch_unbuffered_reads(rreq); + +- ret = netfs_dispatch_unbuffered_reads(rreq); +- +- if (!rreq->submitted) { +- netfs_put_request(rreq, netfs_rreq_trace_put_no_submit); +- inode_dio_end(rreq->inode); +- ret = 0; +- goto out; +- } ++ /* The collector will get run, even if we don't manage to submit any ++ * subreqs, so we shouldn't call inode_dio_end() here. ++ */ + + if (sync) + ret = netfs_wait_for_read(rreq); + else + ret = -EIOCBQUEUED; +-out: ++ + _leave(" = %zd", ret); + return ret; + } +diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h +index d436e20d34185..645996ecfc803 100644 +--- a/fs/netfs/internal.h ++++ b/fs/netfs/internal.h +@@ -23,6 +23,8 @@ + /* + * buffered_read.c + */ ++void netfs_queue_read(struct netfs_io_request *rreq, ++ struct netfs_io_subrequest *subreq); + void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error); + int netfs_prefetch_for_write(struct file *file, struct folio *folio, + size_t offset, size_t len); +@@ -108,6 +110,7 @@ static inline void netfs_see_subrequest(struct netfs_io_subrequest *subreq, + */ + bool netfs_read_collection(struct netfs_io_request *rreq); + void netfs_read_collection_worker(struct work_struct *work); ++void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error); + void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error); + + /* +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index e5f6665b3341e..d2d902f466271 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -575,6 +575,17 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq) + } + EXPORT_SYMBOL(netfs_read_subreq_terminated); + ++/* ++ * Cancel a read subrequest due to preparation failure. ++ */ ++void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error) ++{ ++ trace_netfs_sreq(subreq, netfs_sreq_trace_cancel); ++ subreq->error = error; ++ __set_bit(NETFS_SREQ_FAILED, &subreq->flags); ++ netfs_read_subreq_terminated(subreq); ++} ++ + /* + * Handle termination of a read from the cache. + */ +diff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c +index 9d48ced80d1fa..cb422de66d0c5 100644 +--- a/fs/netfs/read_single.c ++++ b/fs/netfs/read_single.c +@@ -89,7 +89,6 @@ static void netfs_single_read_cache(struct netfs_io_request *rreq, + */ + static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + struct netfs_io_subrequest *subreq; + int ret = 0; + +@@ -102,14 +101,7 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + subreq->len = rreq->len; + subreq->io_iter = rreq->buffer.iter; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- trace_netfs_sreq(subreq, netfs_sreq_trace_added); +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- spin_unlock(&rreq->lock); ++ netfs_queue_read(rreq, subreq); + + netfs_single_cache_prepare_read(rreq, subreq); + switch (subreq->source) { +@@ -121,10 +113,14 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + goto cancel; + } + ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + rreq->netfs_ops->issue_read(subreq); + rreq->submitted += subreq->len; + break; + case NETFS_READ_FROM_CACHE: ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + trace_netfs_sreq(subreq, netfs_sreq_trace_submit); + netfs_single_read_cache(rreq, subreq); + rreq->submitted += subreq->len; +@@ -134,14 +130,15 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + pr_warn("Unexpected single-read source %u\n", subreq->source); + WARN_ON_ONCE(true); + ret = -EIO; +- break; ++ goto cancel; + } + +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + return ret; + cancel: +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); ++ netfs_wake_collector(rreq); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch b/queue-6.18/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch new file mode 100644 index 0000000000..141e37e4f7 --- /dev/null +++ b/queue-6.18/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch @@ -0,0 +1,82 @@ +From 34e104f627cf95e32a23f91108566260c1c89c70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:54 +0100 +Subject: netfs: Fix early put of sink folio in netfs_read_gaps() + +From: David Howells + +[ Upstream commit 3e5dd91b87a8b1450217b56a336bee315f40da7d ] + +Fix netfs_read_gaps() to release the sink page it uses after waiting for +the request to complete. The way the sink page is used is that an +ITER_BVEC-class iterator is created that has the gaps from the target folio +at either end, but has the sink page tiled over the middle so that a single +read op can fill in both gaps. + +The bug was found by KASAN detecting a UAF on the generic/075 xfstest in +the cifsd kernel thread that handles reception of data from the TCP socket: + + BUG: KASAN: use-after-free in _copy_to_iter+0x48a/0xa20 + Write of size 885 at addr ffff888107f92000 by task cifsd/1285 + CPU: 2 UID: 0 PID: 1285 Comm: cifsd Not tainted 7.0.0 #6 PREEMPT(lazy) + Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x17f/0x4f1 + kasan_report+0x100/0x1e0 + kasan_check_range+0x10f/0x1e0 + __asan_memcpy+0x3c/0x60 + _copy_to_iter+0x48a/0xa20 + __skb_datagram_iter+0x2c9/0x430 + skb_copy_datagram_iter+0x6e/0x160 + tcp_recvmsg_locked+0xce0/0x1130 + tcp_recvmsg+0xeb/0x300 + inet_recvmsg+0xcf/0x3a0 + sock_recvmsg+0xea/0x100 + cifs_readv_from_socket+0x3a6/0x4d0 [cifs] + cifs_read_iter_from_socket+0xdd/0x130 [cifs] + cifs_readv_receive+0xaad/0xb10 [cifs] + cifs_demultiplex_thread+0x1148/0x1740 [cifs] + kthread+0x1cf/0x210 + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Reported-by: Steve French +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-18-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 3531c19eea97a..762ff928bc878 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -456,9 +456,6 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + + netfs_read_to_pagecache(rreq, NULL); + +- if (sink) +- folio_put(sink); +- + ret = netfs_wait_for_read(rreq); + if (ret >= 0) { + if (group) +@@ -470,6 +467,9 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } ++ ++ if (sink) ++ folio_put(sink); + folio_unlock(folio); + netfs_put_request(rreq, netfs_rreq_trace_put_return); + return ret < 0 ? ret : 0; +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch b/queue-6.18/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch new file mode 100644 index 0000000000..7148d159c5 --- /dev/null +++ b/queue-6.18/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch @@ -0,0 +1,307 @@ +From 5dd0d6f864f233c8a4279e37e8cdc0a3e914814a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:58 +0100 +Subject: netfs: Fix folio->private handling in netfs_perform_write() + +From: David Howells + +[ Upstream commit ccde2ac757c713535b224233a296de40efe5212d ] + +Under some circumstances, netfs_perform_write() doesn't correctly +manipulate folio->private between NULL, NETFS_FOLIO_COPY_TO_CACHE, pointing +to a group and pointing to a netfs_folio struct, leading to potential +multiple attachments of private data with associated folio ref leaks and +also leaks of netfs_folio structs or netfs_group refs. + +Fix this by consolidating the place at which a folio is marked uptodate in +one place and having that look at what's attached to folio->private and +decide how to clean it up and then set the new group. Also, the content +shouldn't be flushed if group is NULL, even if a group is specified in the +netfs_group parameter, as that would be the case for a new folio. A +filesystem should always specify netfs_group or never specify netfs_group. + +The Sashiko auto-review tool noted that it was theoretically possible that +the fpos >= ctx->zero_point section might leak if it modified a streaming +write folio. This is unlikely, but with a network filesystem, third party +changes can happen. It also pointed out that __netfs_set_group() would +leak if called multiple times on the same folio from the "whole folio +modify section". + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-22-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 134 +++++++++++++++++++++-------------- + include/trace/events/netfs.h | 1 + + 2 files changed, 82 insertions(+), 53 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 60215a7723574..dd0ce7b769ce0 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -13,24 +13,6 @@ + #include + #include "internal.h" + +-static void __netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- if (netfs_group) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +-} +- +-static void netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- void *priv = folio_get_private(folio); +- +- if (unlikely(priv != netfs_group)) { +- if (netfs_group && (!priv || priv == NETFS_FOLIO_COPY_TO_CACHE)) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +- else if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) +- folio_detach_private(folio); +- } +-} +- + /* + * Grab a folio for writing and lock it. Attempt to allocate as large a folio + * as possible to hold as much of the remaining length as possible in one go. +@@ -158,6 +140,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + size_t offset; /* Offset into pagecache folio */ + size_t part; /* Bytes to write to folio */ + size_t copied; /* Bytes copied from user */ ++ void *priv; + + offset = pos & (max_chunk - 1); + part = min(max_chunk - offset, iov_iter_count(iter)); +@@ -203,6 +186,25 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto error_folio_unlock; + } + ++ finfo = netfs_folio_info(folio); ++ group = netfs_folio_group(folio); ++ ++ /* If the requested group differs from the group set on the ++ * page, then we need to flush out the folio if it has a group ++ * set (ie. is non-NULL). Note that COPY_TO_CACHE is a special ++ * case, being a netfs annotation rather than an actual group. ++ * ++ * The filesystem isn't permitted to mix writes with groups and ++ * writes without groups as the NULL group is used to indicate ++ * that no group is set. ++ */ ++ if (unlikely(group != netfs_group) && ++ group != NETFS_FOLIO_COPY_TO_CACHE && ++ group) { ++ WARN_ON_ONCE(!netfs_group); ++ goto flush_content; ++ } ++ + /* Decide how we should modify a folio. We might be attempting + * to do write-streaming, as we don't want to a local RMW cycle + * if we can avoid it. If we're doing local caching or content +@@ -210,22 +212,14 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + * file is open readably, then we let ->read_folio() fill in + * the gaps. + */ +- finfo = netfs_folio_info(folio); +- group = netfs_folio_group(folio); +- +- if (unlikely(group != netfs_group) && +- group != NETFS_FOLIO_COPY_TO_CACHE) +- goto flush_content; +- + if (folio_test_uptodate(folio)) { + if (mapping_writably_mapped(mapping)) + flush_dcache_folio(folio); + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_folio_is_uptodate; +- goto copied; ++ goto copied_uptodate; + } + + /* If the page is above the zero-point then we assume that the +@@ -238,24 +232,22 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + folio_zero_segment(folio, offset + copied, flen); +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_modify_and_clear; +- goto copied; ++ if (finfo) ++ trace = netfs_modify_and_clear_rm_finfo; ++ else ++ trace = netfs_modify_and_clear; ++ goto mark_uptodate; + } + + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (likely(copied == part)) { +- if (finfo) { ++ if (finfo) + trace = netfs_whole_folio_modify_filled; +- goto folio_now_filled; +- } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; +- goto copied; ++ else ++ trace = netfs_whole_folio_modify; ++ goto mark_uptodate; + } + if (copied == 0) + goto copy_failed; +@@ -273,7 +265,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += finfo->dirty_offset; + if (finfo->dirty_len == flen) { + trace = netfs_whole_folio_modify_filled_efault; +- goto folio_now_filled; ++ goto mark_uptodate; + } + if (copied > finfo->dirty_len) + finfo->dirty_len = copied; +@@ -301,11 +293,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_just_prefetch; +- goto copied; ++ goto copied_uptodate; + } + ++ /* Do a streaming write on a folio that has nothing in it yet. */ + if (!finfo) { + ret = -EIO; + if (WARN_ON(folio_get_private(folio))) +@@ -314,10 +306,8 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + if (offset == 0 && copied == flen) { +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); + trace = netfs_streaming_filled_page; +- goto copied; ++ goto mark_uptodate; + } + + finfo = kzalloc(sizeof(*finfo), GFP_KERNEL); +@@ -346,7 +336,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { + trace = netfs_streaming_cont_filled_page; +- goto folio_now_filled; ++ goto mark_uptodate; + } + trace = netfs_streaming_write_cont; + goto copied; +@@ -362,13 +352,36 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + +- folio_now_filled: +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); ++ /* Mark a folio as being up to data when we've filled it ++ * completely. If the folio has a group attached, then it must ++ * be the same group, otherwise we should have flushed it out ++ * above. We have to get rid of the netfs_folio struct if ++ * there was one. ++ */ ++ mark_uptodate: + folio_mark_uptodate(folio); +- kfree(finfo); ++ ++ copied_uptodate: ++ priv = folio_get_private(folio); ++ if (likely(priv == netfs_group)) { ++ /* Already set correctly; no change required. */ ++ } else if (priv == NETFS_FOLIO_COPY_TO_CACHE) { ++ if (!netfs_group) ++ folio_detach_private(folio); ++ else ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ } else if (!priv) { ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ } else { ++ WARN_ON_ONCE(!finfo); ++ if (netfs_group) ++ /* finfo->netfs_group has a ref */ ++ folio_change_private(folio, netfs_group); ++ else ++ folio_detach_private(folio); ++ kfree(finfo); ++ } ++ + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +@@ -531,6 +544,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + struct inode *inode = file_inode(file); + struct netfs_inode *ictx = netfs_inode(inode); + vm_fault_t ret = VM_FAULT_NOPAGE; ++ void *priv; + int err; + + _enter("%lx", folio->index); +@@ -551,7 +565,9 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + } + + group = netfs_folio_group(folio); +- if (group != netfs_group && group != NETFS_FOLIO_COPY_TO_CACHE) { ++ if (group && ++ group != netfs_group && ++ group != NETFS_FOLIO_COPY_TO_CACHE) { + folio_unlock(folio); + err = filemap_fdatawrite_range(mapping, + folio_pos(folio), +@@ -573,7 +589,19 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + trace_netfs_folio(folio, netfs_folio_trace_mkwrite_plus); + else + trace_netfs_folio(folio, netfs_folio_trace_mkwrite); +- netfs_set_group(folio, netfs_group); ++ ++ priv = folio_get_private(folio); ++ if (priv != netfs_group) { ++ if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_detach_private(folio); ++ else if (netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ else if (netfs_group && !priv) ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ else ++ WARN_ON_ONCE(1); ++ } ++ + file_update_time(file); + set_bit(NETFS_ICTX_MODIFIED_ATTR, &ictx->flags); + if (ictx->ops->post_modify) +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index db045135406c9..3fe3980902c24 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -181,6 +181,7 @@ + EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ + EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ ++ EM(netfs_modify_and_clear_rm_finfo, "mod-n-clear+") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ + EM(netfs_flush_content, "flush") \ +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch b/queue-6.18/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch new file mode 100644 index 0000000000..41e7e208ae --- /dev/null +++ b/queue-6.18/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch @@ -0,0 +1,44 @@ +From 6574407c6b0f33aaf3bdf9dfdab33ab8ec486979 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:55 +0100 +Subject: netfs: Fix leak of request in netfs_write_begin() error handling + +From: David Howells + +[ Upstream commit 5046a34f0643441f05b0253ea64e1a3af87efe14 ] + +Fix netfs_write_begin() to not leak our ref on the request in the event +that we get an error from netfs_wait_for_read(). + +Fixes: 4090b31422a6 ("netfs: Add a function to consolidate beginning a read") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-19-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 762ff928bc878..085cd392bf5ac 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -686,9 +686,9 @@ int netfs_write_begin(struct netfs_inode *ctx, + + netfs_read_to_pagecache(rreq, NULL); + ret = netfs_wait_for_read(rreq); ++ netfs_put_request(rreq, netfs_rreq_trace_put_return); + if (ret < 0) + goto error; +- netfs_put_request(rreq, netfs_rreq_trace_put_return); + + have_folio: + ret = folio_wait_private_2_killable(folio); +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch b/queue-6.18/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch new file mode 100644 index 0000000000..ebab0fed5a --- /dev/null +++ b/queue-6.18/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch @@ -0,0 +1,128 @@ +From 8a2004ff4a434e39ae09873a87d24e1daa16fe2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:48 +0100 +Subject: netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes + gone + +From: David Howells + +[ Upstream commit 156ac2ec2ee77c44c4eb7439d6d165247ba12247 ] + +If a streaming write is made, this will leave the relevant modified folio +in a not-uptodate, but dirty state with a netfs_folio struct hung off of +folio->private indicating the dirty range. Subsequently truncating the +file such that the dirty data in the folio is removed, but the first part +of the folio theoretically remains will cause the netfs_folio struct to be +discarded... but will leave the dirty flag set. + +If the folio is then read via mmap(), netfs_read_folio() will see that the +page is dirty and jump to netfs_read_gaps() to fill in the missing bits. +netfs_read_gaps(), however, expects there to be a netfs_folio struct +present and can oops because truncate removed it. + +Fix this by calling folio_cancel_dirty() in netfs_invalidate_folio() in the +event that all the dirty data in the folio is erased (as nfs does). + +Also add some tracepoints to log modifications to a dirty page. + +This can be reproduced with something like: + + dd if=/dev/zero of=/xfstest.test/foo bs=1M count=1 + umount /xfstest.test + mount /xfstest.test + xfs_io -c "w 0xbbbf 0xf96c" \ + -c "truncate 0xbbbf" \ + -c "mmap -r 0xb000 0x11000" \ + -c "mr 0xb000 0x11000" \ + /xfstest.test/foo + +with fscaching disabled (otherwise streaming writes are suppressed) and a +change to netfs_perform_write() to disallow streaming writes if the fd is +open O_RDWR: + + if (//(file->f_mode & FMODE_READ) || <--- comment this out + netfs_is_cache_enabled(ctx)) { + +It should be reproducible even without this change, but if prevents the +above trivial xfs_io command from reproducing it. + +Note that the initial dd is important: the file must start out sufficiently +large that the zero-point logic doesn't just clear the gaps because it +knows there's nothing in the file to read yet. Unmounting and mounting is +needed to clear the pagecache (there are other ways to do that that may +also work). + +This was initially reproduced with the generic/522 xfstest on some patches +that remove the FMODE_READ restriction. + +Fixes: 9ebff83e6481 ("netfs: Prep to use folio->private for write grouping and streaming write") +Reported-by: Marc Dionne +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-12-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 6 +++++- + include/trace/events/netfs.h | 4 ++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 486166460e177..eb309bef72608 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -256,6 +256,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; + finfo->dirty_offset = offset; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } + +@@ -264,12 +265,14 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + */ + if (iend >= fend) { + finfo->dirty_len = offset - fstart; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_tail); + return; + } + + /* A partial write was split. The caller has already zeroed + * it, so just absorb the hole. + */ ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_middle); + } + return; + +@@ -277,8 +280,9 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + netfs_put_group(netfs_folio_group(folio)); + folio_detach_private(folio); + folio_clear_uptodate(folio); ++ folio_cancel_dirty(folio); + kfree(finfo); +- return; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_all); + } + EXPORT_SYMBOL(netfs_invalidate_folio); + +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index cbe28211106c5..88d814ba1e697 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -194,6 +194,10 @@ + EM(netfs_folio_trace_copy_to_cache, "mark-copy") \ + EM(netfs_folio_trace_end_copy, "end-copy") \ + EM(netfs_folio_trace_filled_gaps, "filled-gaps") \ ++ EM(netfs_folio_trace_invalidate_all, "inval-all") \ ++ EM(netfs_folio_trace_invalidate_front, "inval-front") \ ++ EM(netfs_folio_trace_invalidate_middle, "inval-mid") \ ++ EM(netfs_folio_trace_invalidate_tail, "inval-tail") \ + EM(netfs_folio_trace_kill, "kill") \ + EM(netfs_folio_trace_kill_cc, "kill-cc") \ + EM(netfs_folio_trace_kill_g, "kill-g") \ +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch b/queue-6.18/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch new file mode 100644 index 0000000000..de0651f4ae --- /dev/null +++ b/queue-6.18/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch @@ -0,0 +1,44 @@ +From c6abaa996c623cccbabf1f557773eae70185b5a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:59 +0100 +Subject: netfs: Fix netfs_read_folio() to wait on writeback + +From: David Howells + +[ Upstream commit ded0c6f1606061148c202825f7e53d711f9f84cf ] + +Fix netfs_read_folio() to wait for an ongoing writeback to complete so that +it can trust the dirty flag and whatever is attached to folio->private +(folio->private may get cleaned up by the collector before it clears the +writeback flag). + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-23-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index ebaabec376326..fab3181c7f869 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -502,6 +502,8 @@ int netfs_read_folio(struct file *file, struct folio *folio) + struct netfs_inode *ctx = netfs_inode(mapping->host); + int ret; + ++ folio_wait_writeback(folio); ++ + if (folio_test_dirty(folio)) + return netfs_read_gaps(file, folio); + +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch b/queue-6.18/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch new file mode 100644 index 0000000000..f835c9b7dd --- /dev/null +++ b/queue-6.18/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch @@ -0,0 +1,44 @@ +From 50b6ae00bdfd3d9e7f060330efd5af771575843b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:41 +0100 +Subject: netfs: Fix netfs_read_to_pagecache() to pause on subreq failure + +From: David Howells + +[ Upstream commit 8a8c0cfdf4658fc5b295b7fc87be56e0d76741f4 ] + +Fix netfs_read_to_pagecache() so that it pauses the generation of new +subrequests if an already-issued subrequest fails. + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-5-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 10b13924ed543..e6157122da3a4 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -299,6 +299,11 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + } + + netfs_issue_read(rreq, subreq); ++ ++ if (test_bit(NETFS_RREQ_PAUSE, &rreq->flags)) ++ netfs_wait_for_paused_read(rreq); ++ if (test_bit(NETFS_RREQ_FAILED, &rreq->flags)) ++ break; + cond_resched(); + } while (size > 0); + +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch b/queue-6.18/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch new file mode 100644 index 0000000000..ba743c03bf --- /dev/null +++ b/queue-6.18/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch @@ -0,0 +1,80 @@ +From 9887644bb857c941b8c592108698b3081bd8daed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:47 +0100 +Subject: netfs: Fix overrun check in netfs_extract_user_iter() + +From: David Howells + +[ Upstream commit 0ef37eef83fad3542ee06db2940433ae1a92b39d ] + +Fix netfs_extract_user_iter() so that if iov_iter_extract_pages() overfills +pages[], then those pages don't get included in the iterator constructed at +the end of the function. If there was an overfill, memory corruption has +already happened. + +Fixes: 85dd2c8ff368 ("netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-11-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/iterator.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c +index 429e4396e1b00..b375567e0520e 100644 +--- a/fs/netfs/iterator.c ++++ b/fs/netfs/iterator.c +@@ -72,21 +72,24 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + break; + } + +- if (ret > count) { +- pr_err("get_pages rc=%zd more than %zu\n", ret, count); ++ if (WARN(ret > count, ++ "%s: extract_pages overrun %zd > %zu bytes\n", ++ __func__, ret, count)) { ++ ret = -EIO; + break; + } + +- count -= ret; +- ret += offset; +- cur_npages = DIV_ROUND_UP(ret, PAGE_SIZE); +- +- if (npages + cur_npages > max_pages) { +- pr_err("Out of bvec array capacity (%u vs %u)\n", +- npages + cur_npages, max_pages); ++ cur_npages = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ if (WARN(cur_npages > max_pages - npages, ++ "%s: extract_pages overrun %u > %u pages\n", ++ __func__, npages + cur_npages, max_pages)) { ++ ret = -EIO; + break; + } + ++ count -= ret; ++ ret += offset; ++ + for (i = 0; i < cur_npages; i++) { + len = ret > PAGE_SIZE ? PAGE_SIZE : ret; + bvec_set_page(bv + npages + i, *pages++, len - offset, offset); +@@ -97,6 +100,11 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + npages += cur_npages; + } + ++ /* Note: Don't try to clean up after EIO. Either we got no pages, so ++ * nothing to clean up, or we got a buffer overrun, memory corruption ++ * and can't trust the stuff in the buffer (a WARN was emitted). ++ */ ++ + if (ret < 0 && (ret == -ENOMEM || npages == 0)) { + for (i = 0; i < npages; i++) + unpin_user_page(bv[i].bv_page); +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-partial-invalidation-of-streaming-write-fo.patch b/queue-6.18/netfs-fix-partial-invalidation-of-streaming-write-fo.patch new file mode 100644 index 0000000000..af50d5d1b2 --- /dev/null +++ b/queue-6.18/netfs-fix-partial-invalidation-of-streaming-write-fo.patch @@ -0,0 +1,49 @@ +From 8e720304be875a726fd05a19334b09f2bd36e1d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:57 +0100 +Subject: netfs: Fix partial invalidation of streaming-write folio + +From: David Howells + +[ Upstream commit 6d91acc7fb85d33ea58fca9b964a32a453937f4b ] + +In netfs_invalidate_folio(), if the region of a partial invalidation +overlaps the front (but not all) of a dirty write cached in a streaming +write page (dirty, but not uptodate, with the dirty region tracked by a +netfs_folio struct), the function modifies the dirty region - but +incorrectly as it moves the region forward by setting the start to the +start, not the end, of the invalidation region. + +Fix this by setting finfo->dirty_offset to the end of the invalidation +region (iend). + +Fixes: cce6bfa6ca0e ("netfs: Fix trimming of streaming-write folios in netfs_inval_folio()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-21-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index eb309bef72608..1109ac3791281 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -255,7 +255,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + goto erase_completely; + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; +- finfo->dirty_offset = offset; ++ finfo->dirty_offset = iend; + trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-potential-deadlock-in-write-through-mode.patch b/queue-6.18/netfs-fix-potential-deadlock-in-write-through-mode.patch new file mode 100644 index 0000000000..ad66d31559 --- /dev/null +++ b/queue-6.18/netfs-fix-potential-deadlock-in-write-through-mode.patch @@ -0,0 +1,119 @@ +From f38aa37cba112337694403b4ee2272d27fb8cc5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:51 +0100 +Subject: netfs: Fix potential deadlock in write-through mode + +From: David Howells + +[ Upstream commit b6a4ae1634b3ad2aaa05222e53d36da532852faf ] + +Fix netfs_advance_writethrough() to always unlock the supplied folio and to +mark it dirty if it isn't yet written to the end. Unfortunately, it can't +be marked for writeback until the folio is done with as that may cause a +deadlock against mmapped reads and writes. + +Even though it has been marked dirty, premature writeback can't occur as +the caller is holding both inode->i_rwsem (which will prevent concurrent +truncation, fallocation, DIO and other writes) and ictx->wb_lock (which +will cause flushing to wait and writeback to skip or wait). + +Note that this may be easier to deal with once the queuing of folios is +split from the generation of subrequests. + +Fixes: 288ace2f57c9 ("netfs: New writeback implementation") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-15-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/write_issue.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index 2db688f941251..9bf05099155dc 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -413,12 +413,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq, + if (streamw) + netfs_issue_write(wreq, cache); + +- /* Flip the page to the writeback state and unlock. If we're called +- * from write-through, then the page has already been put into the wb +- * state. +- */ +- if (wreq->origin == NETFS_WRITEBACK) +- folio_start_writeback(folio); ++ folio_start_writeback(folio); + folio_unlock(folio); + + if (fgroup == NETFS_FOLIO_COPY_TO_CACHE) { +@@ -646,29 +641,41 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c + struct folio *folio, size_t copied, bool to_page_end, + struct folio **writethrough_cache) + { ++ int ret; ++ + _enter("R=%x ic=%zu ws=%u cp=%zu tp=%u", + wreq->debug_id, wreq->buffer.iter.count, wreq->wsize, copied, to_page_end); + +- if (!*writethrough_cache) { +- if (folio_test_dirty(folio)) +- /* Sigh. mmap. */ +- folio_clear_dirty_for_io(folio); ++ /* The folio is locked. */ + ++ if (*writethrough_cache != folio) { ++ if (*writethrough_cache) { ++ /* Did the folio get moved? */ ++ folio_put(*writethrough_cache); ++ *writethrough_cache = NULL; ++ } + /* We can make multiple writes to the folio... */ +- folio_start_writeback(folio); + if (wreq->len == 0) + trace_netfs_folio(folio, netfs_folio_trace_wthru); + else + trace_netfs_folio(folio, netfs_folio_trace_wthru_plus); + *writethrough_cache = folio; ++ folio_get(folio); + } + + wreq->len += copied; +- if (!to_page_end) ++ ++ if (!to_page_end) { ++ folio_mark_dirty(folio); ++ folio_unlock(folio); + return 0; ++ } + ++ ret = netfs_write_folio(wreq, wbc, folio); ++ folio_put(*writethrough_cache); + *writethrough_cache = NULL; +- return netfs_write_folio(wreq, wbc, folio); ++ wreq->submitted = wreq->len; ++ return ret; + } + + /* +@@ -682,8 +689,12 @@ ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_c + + _enter("R=%x", wreq->debug_id); + +- if (writethrough_cache) ++ if (writethrough_cache) { ++ folio_lock(writethrough_cache); + netfs_write_folio(wreq, wbc, writethrough_cache); ++ folio_put(writethrough_cache); ++ wreq->submitted = wreq->len; ++ } + + netfs_end_issue_write(wreq); + +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch b/queue-6.18/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch new file mode 100644 index 0000000000..27656b488a --- /dev/null +++ b/queue-6.18/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch @@ -0,0 +1,104 @@ +From d6ecf587c73ad9166d5cc8b41b9afdd7b8aee1aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:56 +0100 +Subject: netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages() + +From: David Howells + +[ Upstream commit dbe556972100fabb8e5a1b3d2163831ff07b1e8e ] + +netfs_unlock_abandoned_read_pages(rreq) accesses the index of the folios it +is wanting to unlock and compares that to rreq->no_unlock_folio so that it +doesn't unlock a folio being read for netfs_perform_write() or +netfs_write_begin(). + +However, given that netfs_unlock_abandoned_read_pages() is called _after_ +NETFS_RREQ_IN_PROGRESS is cleared, the one folio that it's not allowed to +dereference is the one specified by ->no_unlock_folio as ownership +immediately reverts to the caller. + +Fix this by storing the folio pointer instead and using that rather than +the index. Also fix netfs_unlock_read_folio() where the same applies. + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-20-dhowells@redhat.com +cc: Paulo Alcantara +cc: Viacheslav Dubeyko +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 4 ++-- + fs/netfs/read_collect.c | 2 +- + fs/netfs/read_retry.c | 2 +- + include/linux/netfs.h | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 085cd392bf5ac..ebaabec376326 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -669,7 +669,7 @@ int netfs_write_begin(struct netfs_inode *ctx, + ret = PTR_ERR(rreq); + goto error; + } +- rreq->no_unlock_folio = folio->index; ++ rreq->no_unlock_folio = folio; + __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); + + ret = netfs_begin_cache_read(rreq, ctx); +@@ -735,7 +735,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio, + goto error; + } + +- rreq->no_unlock_folio = folio->index; ++ rreq->no_unlock_folio = folio; + __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); + ret = netfs_begin_cache_read(rreq, ctx); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index d2d902f466271..4c7312a4c8597 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -83,7 +83,7 @@ static void netfs_unlock_read_folio(struct netfs_io_request *rreq, + } + + just_unlock: +- if (folio->index == rreq->no_unlock_folio && ++ if (folio == rreq->no_unlock_folio && + test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) { + _debug("no unlock"); + } else { +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index 68fc869513ef1..999177426141a 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -288,7 +288,7 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq) + struct folio *folio = folioq_folio(p, slot); + + if (folio && !folioq_is_marked2(p, slot)) { +- if (folio->index == rreq->no_unlock_folio && ++ if (folio == rreq->no_unlock_folio && + test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, + &rreq->flags)) { + _debug("no unlock"); +diff --git a/include/linux/netfs.h b/include/linux/netfs.h +index ba17ac5bf356a..62a528f90666b 100644 +--- a/include/linux/netfs.h ++++ b/include/linux/netfs.h +@@ -252,7 +252,7 @@ struct netfs_io_request { + unsigned long long collected_to; /* Point we've collected to */ + unsigned long long cleaned_to; /* Position we've cleaned folios to */ + unsigned long long abandon_to; /* Position to abandon folios to */ +- pgoff_t no_unlock_folio; /* Don't unlock this folio after read */ ++ const struct folio *no_unlock_folio; /* Don't unlock this folio after read */ + unsigned int direct_bv_count; /* Number of elements in direct_bv[] */ + unsigned int debug_id; + unsigned int rsize; /* Maximum read size (0 for none) */ +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch b/queue-6.18/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch new file mode 100644 index 0000000000..b42ba23095 --- /dev/null +++ b/queue-6.18/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch @@ -0,0 +1,93 @@ +From b93283d0ebdb499a16c918bc9c5631c0338e1e32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:52 +0100 +Subject: netfs: Fix read-gaps to remove netfs_folio from filled folio + +From: David Howells + +[ Upstream commit a41168aef634356a9b87ec44349e3c82835700a5 ] + +Fix netfs_read_gaps() to remove the netfs_folio record from the folio +record before marking the folio uptodate if it successfully fills the gaps +around the dirty data in a streaming write folio (dirty, but not uptodate). + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0x138b1 0x8b15d * + write 0x507ee 0x10df7 0x927c0 + write 0x19993 0x10e04 0x927c0 * + mapwrite 0x66214 0x1a253 0x927c0 + copy_range 0xb704 0x89b9 0x24429 0x79380 + write 0x2402b 0x144a2 0x90660 * + mapwrite 0x204d5 0x140a0 0x927c0 * + copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 * + read 0 0x9157c 0x9157c + +on cifs with the default cache option. + +It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in +netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-16-dhowells@redhat.com +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index e6157122da3a4..3531c19eea97a 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -394,6 +394,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + { + struct netfs_io_request *rreq; + struct address_space *mapping = folio->mapping; ++ struct netfs_group *group = netfs_folio_group(folio); + struct netfs_folio *finfo = netfs_folio_info(folio); + struct netfs_inode *ctx = netfs_inode(mapping->host); + struct folio *sink = NULL; +@@ -460,6 +461,12 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + + ret = netfs_wait_for_read(rreq); + if (ret >= 0) { ++ if (group) ++ folio_change_private(folio, group); ++ else ++ folio_detach_private(folio); ++ kfree(finfo); ++ trace_netfs_folio(folio, netfs_folio_trace_filled_gaps); + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } +@@ -495,10 +502,8 @@ int netfs_read_folio(struct file *file, struct folio *folio) + struct netfs_inode *ctx = netfs_inode(mapping->host); + int ret; + +- if (folio_test_dirty(folio)) { +- trace_netfs_folio(folio, netfs_folio_trace_read_gaps); ++ if (folio_test_dirty(folio)) + return netfs_read_gaps(file, folio); +- } + + _enter("%lx", folio->index); + +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-streaming-write-being-overwritten.patch b/queue-6.18/netfs-fix-streaming-write-being-overwritten.patch new file mode 100644 index 0000000000..e0c321b58a --- /dev/null +++ b/queue-6.18/netfs-fix-streaming-write-being-overwritten.patch @@ -0,0 +1,176 @@ +From 055c7341b29670958ea813683147e7d2a190ad7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:50 +0100 +Subject: netfs: Fix streaming write being overwritten + +From: David Howells + +[ Upstream commit 7b4dcf1b9455a6e52ac7478b4057dbe10359576d ] + +In order to avoid reading whilst writing, netfslib will allow "streaming +writes" in which dirty data is stored directly into folios without reading +them first. Such folios are marked dirty but may not be marked uptodate. +If a folio is entirely written by a streaming write, uptodate will be set, +otherwise it will have a netfs_folio struct attached to ->private recording +the dirty region. + +In the event that a partially written streaming write page is to be +overwritten entirely by a single write(), netfs_perform_write() will try to +copy over it, but doesn't discard the netfs_folio if it succeeds; further, +it doesn't correctly handle a partial copy that overwrites some of the +dirty data. + +Fix this by the following: + + (1) If the folio is successfully overwritten, free the netfs_folio struct + before marking the page uptodate. + + (2) If the copy to the folio partially fails, but short of the dirty data, + just ignore the copy. + + (3) If the copy partially fails and overwrites some of the dirty data, + accept the copy, update the netfs_folio struct to record the new data. + If the folio is now filled, free the netfs_folio and set uptodate, + otherwise return a partial write. + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0 0x927c0 + write 0x63fb8 0x53c8 0 + copy_range 0xb704 0x19b9 0x24429 0x79380 + write 0x2402b 0x144a2 0x90660 * + write 0x204d5 0x140a0 0x927c0 * + copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 * + read 0x00000 0x20000 0x9157c + read 0x20000 0x20000 0x9157c + read 0x40000 0x20000 0x9157c + read 0x60000 0x20000 0x9157c + read 0x7e1a0 0xcfb9 0x9157c + +on cifs with the default cache option. + +It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in +netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-14-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 47 ++++++++++++++++++++++++++---------- + include/trace/events/netfs.h | 3 +++ + 2 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 1fa13c2629a73..99736895e964f 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -247,18 +247,38 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); +- if (unlikely(copied == 0)) ++ if (likely(copied == part)) { ++ if (finfo) { ++ trace = netfs_whole_folio_modify_filled; ++ goto folio_now_filled; ++ } ++ __netfs_set_group(folio, netfs_group); ++ folio_mark_uptodate(folio); ++ trace = netfs_whole_folio_modify; ++ goto copied; ++ } ++ if (copied == 0) + goto copy_failed; +- if (unlikely(copied < part)) { ++ if (!finfo || copied <= finfo->dirty_offset) { + maybe_trouble = true; + iov_iter_revert(iter, copied); + copied = 0; + folio_unlock(folio); + goto retry; + } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; ++ ++ /* We overwrote some existing dirty data, so we have to ++ * accept the partial write. ++ */ ++ finfo->dirty_len += finfo->dirty_offset; ++ if (finfo->dirty_len == flen) { ++ trace = netfs_whole_folio_modify_filled_efault; ++ goto folio_now_filled; ++ } ++ if (copied > finfo->dirty_len) ++ finfo->dirty_len = copied; ++ finfo->dirty_offset = 0; ++ trace = netfs_whole_folio_modify_efault; + goto copied; + } + +@@ -328,16 +348,10 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto copy_failed; + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); +- folio_mark_uptodate(folio); +- kfree(finfo); + trace = netfs_streaming_cont_filled_page; +- } else { +- trace = netfs_streaming_write_cont; ++ goto folio_now_filled; + } ++ trace = netfs_streaming_write_cont; + goto copied; + } + +@@ -351,6 +365,13 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + ++ folio_now_filled: ++ if (finfo->netfs_group) ++ folio_change_private(folio, finfo->netfs_group); ++ else ++ folio_detach_private(folio); ++ folio_mark_uptodate(folio); ++ kfree(finfo); + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index 88d814ba1e697..db045135406c9 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -177,6 +177,9 @@ + EM(netfs_folio_is_uptodate, "mod-uptodate") \ + EM(netfs_just_prefetch, "mod-prefetch") \ + EM(netfs_whole_folio_modify, "mod-whole-f") \ ++ EM(netfs_whole_folio_modify_efault, "mod-whole-f!") \ ++ EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ ++ EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch b/queue-6.18/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch new file mode 100644 index 0000000000..85e0c57bbf --- /dev/null +++ b/queue-6.18/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch @@ -0,0 +1,169 @@ +From 86dcd8cec76edf6ea9489c96f76820a177faf886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:44 +0100 +Subject: netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call + +From: Viacheslav Dubeyko + +[ Upstream commit dc7832d05deb4d632e8035e3299e31a3528fa0d0 ] + +The multiple runs of generic/013 test-case is capable +to reproduce a kernel BUG at mm/filemap.c:1504 with +probability of 30%. + +while true; do + sudo ./check generic/013 +done + +[ 9849.452376] page: refcount:3 mapcount:0 mapping:00000000e58ff252 index:0x10781 pfn:0x1c322 +[ 9849.452412] memcg:ffff8881a1915800 +[ 9849.452417] aops:ceph_aops ino:1000058db9e dentry name(?):"f9XXXXXX" +[ 9849.452432] flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff) +[ 9849.452441] raw: 0017ffffc0000000 0000000000000000 dead000000000122 ffff88816110d248 +[ 9849.452445] raw: 0000000000010781 0000000000000000 00000003ffffffff ffff8881a1915800 +[ 9849.452447] page dumped because: VM_BUG_ON_FOLIO(!folio_test_locked(folio)) +[ 9849.452474] ------------[ cut here ]------------ +[ 9849.452476] kernel BUG at mm/filemap.c:1504! +[ 9849.478635] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +[ 9849.481772] CPU: 2 UID: 0 PID: 84223 Comm: fsstress Not tainted 7.0.0-rc1+ #18 PREEMPT(full) +[ 9849.482881] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/1 +0/2025 +[ 9849.484539] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.485076] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc +cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.493818] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.495740] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.498678] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.500559] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.501097] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.502108] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.502516] FS: 00007e36cbe94740(0000) GS:ffff88824a899000(0000) knlGS:0000000000000000 +[ 9849.502996] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.503810] CR2: 000000c0002b0000 CR3: 000000011bbf6004 CR4: 0000000000772ef0 +[ 9849.504459] PKRU: 55555554 +[ 9849.504626] Call Trace: +[ 9849.505242] +[ 9849.505379] netfs_write_begin+0x7c8/0x10a0 +[ 9849.505877] ? __kasan_check_read+0x11/0x20 +[ 9849.506384] ? __pfx_netfs_write_begin+0x10/0x10 +[ 9849.507178] ceph_write_begin+0x8c/0x1c0 +[ 9849.507934] generic_perform_write+0x391/0x8f0 +[ 9849.508503] ? __pfx_generic_perform_write+0x10/0x10 +[ 9849.509062] ? file_update_time_flags+0x19a/0x4b0 +[ 9849.509581] ? ceph_get_caps+0x63/0xf0 +[ 9849.510259] ? ceph_get_caps+0x63/0xf0 +[ 9849.510530] ceph_write_iter+0xe79/0x1ae0 +[ 9849.511282] ? __pfx_ceph_write_iter+0x10/0x10 +[ 9849.511839] ? lock_acquire+0x1ad/0x310 +[ 9849.512334] ? ksys_write+0xf9/0x230 +[ 9849.512582] ? lock_is_held_type+0xaa/0x140 +[ 9849.513128] vfs_write+0x512/0x1110 +[ 9849.513634] ? __fget_files+0x33/0x350 +[ 9849.513893] ? __pfx_vfs_write+0x10/0x10 +[ 9849.514143] ? mutex_lock_nested+0x1b/0x30 +[ 9849.514394] ksys_write+0xf9/0x230 +[ 9849.514621] ? __pfx_ksys_write+0x10/0x10 +[ 9849.514887] ? do_syscall_64+0x25e/0x1520 +[ 9849.515122] ? __kasan_check_read+0x11/0x20 +[ 9849.515366] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.515655] __x64_sys_write+0x72/0xd0 +[ 9849.515885] ? trace_hardirqs_on+0x24/0x1c0 +[ 9849.516130] x64_sys_call+0x22f/0x2390 +[ 9849.516341] do_syscall_64+0x12b/0x1520 +[ 9849.516545] ? do_syscall_64+0x27c/0x1520 +[ 9849.516783] ? do_syscall_64+0x27c/0x1520 +[ 9849.517003] ? lock_release+0x318/0x480 +[ 9849.517220] ? __x64_sys_io_getevents+0x143/0x2d0 +[ 9849.517479] ? percpu_ref_put_many.constprop.0+0x8f/0x210 +[ 9849.517779] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.518073] ? do_syscall_64+0x25e/0x1520 +[ 9849.518291] ? __kasan_check_read+0x11/0x20 +[ 9849.518519] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.518799] ? do_syscall_64+0x27c/0x1520 +[ 9849.519024] ? local_clock_noinstr+0xf/0x120 +[ 9849.519262] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.519544] ? do_syscall_64+0x25e/0x1520 +[ 9849.519781] ? __kasan_check_read+0x11/0x20 +[ 9849.520008] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520273] ? do_syscall_64+0x27c/0x1520 +[ 9849.520491] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520767] ? irqentry_exit+0x10c/0x6c0 +[ 9849.520984] ? trace_hardirqs_off+0x86/0x1b0 +[ 9849.521224] ? exc_page_fault+0xab/0x130 +[ 9849.521472] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.521766] RIP: 0033:0x7e36cbd14907 +[ 9849.521989] Code: 10 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 9849.523057] RSP: 002b:00007ffff2d2a968 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 9849.523484] RAX: ffffffffffffffda RBX: 000000000000e549 RCX: 00007e36cbd14907 +[ 9849.523885] RDX: 000000000000e549 RSI: 00005bd797ec6370 RDI: 0000000000000004 +[ 9849.524277] RBP: 0000000000000004 R08: 0000000000000047 R09: 00005bd797ec6370 +[ 9849.524652] R10: 0000000000000078 R11: 0000000000000246 R12: 0000000000000049 +[ 9849.525062] R13: 0000000010781a37 R14: 00005bd797ec6370 R15: 0000000000000000 +[ 9849.525447] +[ 9849.525574] Modules linked in: intel_rapl_msr intel_rapl_common intel_uncore_frequency_common intel_pmc_core pmt_telemetry pmt_discovery pmt_class intel_pmc_ssram_telemetry intel_vsec kvm_intel joydev kvm irqbypass ghash_clmulni_intel aesni_intel input_leds rapl mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 bochs qemu_fw_cfg i2c_smbus pata_acpi sch_fq_codel rbd msr parport_pc ppdev lp parport efi_pstore +[ 9849.529150] ---[ end trace 0000000000000000 ]--- +[ 9849.529502] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.530813] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.534986] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.536198] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.537718] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.539321] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.540862] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.542438] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.543996] FS: 00007e36cbe94740(0000) GS:ffff88824b899000(0000) knlGS:0000000000000000 +[ 9849.545854] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.547092] CR2: 00007e36cb3ff000 CR3: 000000011bbf6006 CR4: 0000000000772ef0 +[ 9849.548679] PKRU: 55555554 + +The race sequence: +1. Read completes -> netfs_read_collection() runs +2. netfs_wake_rreq_flag(rreq, NETFS_RREQ_IN_PROGRESS, ...) +3. netfs_wait_for_read() returns -EFAULT to netfs_write_begin() +4. The netfs_unlock_abandoned_read_pages() unlocks the folio +5. netfs_write_begin() calls folio_unlock(folio) -> VM_BUG_ON_FOLIO() + +The key reason of the issue that netfs_unlock_abandoned_read_pages() +doesn't check the flag NETFS_RREQ_NO_UNLOCK_FOLIO and executes +folio_unlock() unconditionally. This patch implements in +netfs_unlock_abandoned_read_pages() logic similar to +netfs_unlock_read_folio(). + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-8-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +cc: Ceph Development +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/read_retry.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index cca9ac43c0773..68fc869513ef1 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -288,8 +288,15 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq) + struct folio *folio = folioq_folio(p, slot); + + if (folio && !folioq_is_marked2(p, slot)) { +- trace_netfs_folio(folio, netfs_folio_trace_abandon); +- folio_unlock(folio); ++ if (folio->index == rreq->no_unlock_folio && ++ test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, ++ &rreq->flags)) { ++ _debug("no unlock"); ++ } else { ++ trace_netfs_folio(folio, ++ netfs_folio_trace_abandon); ++ folio_unlock(folio); ++ } + } + } + } +-- +2.53.0 + diff --git a/queue-6.18/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch b/queue-6.18/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch new file mode 100644 index 0000000000..e61724018b --- /dev/null +++ b/queue-6.18/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch @@ -0,0 +1,80 @@ +From be3668c607673b3cc3ebba25d16cd4eeaf770cf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:53 +0100 +Subject: netfs: Fix write streaming disablement if fd open O_RDWR + +From: David Howells + +[ Upstream commit 70a7b9193bbbfceaab5974de66834c64ccc875dd ] + +In netfs_perform_write(), "write streaming" (the caching of dirty data in +dirty but !uptodate folios) is performed to avoid the need to read data +that is just going to get immediately overwritten. However, this is/will +be disabled in three circumstances: if the fd is open O_RDWR, if fscache is +in use (as we need to round out the blocks for DIO) or if content +encryption is enabled (again for rounding out purposes). + +The idea behind disabling it if the fd is open O_RDWR is that we'd need to +flush the write-streaming page before we could read the data, particularly +through mmap. But netfs now fills in the gaps if ->read_folio() is called +on the page, so that is unnecessary. Further, this doesn't actually work +if a separate fd is open for reading. + +Fix this by removing the check for O_RDWR, thereby allowing streaming +writes even when we might read. + +This caused a number of problems with the generic/522 xfstest, but those +are now fixed. + +Fixes: c38f4e96e605 ("netfs: Provide func to copy data to pagecache for buffered write") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-17-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 99736895e964f..60215a7723574 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -204,11 +204,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + /* Decide how we should modify a folio. We might be attempting +- * to do write-streaming, in which case we don't want to a +- * local RMW cycle if we can avoid it. If we're doing local +- * caching or content crypto, we award that priority over +- * avoiding RMW. If the file is open readably, then we also +- * assume that we may want to read what we wrote. ++ * to do write-streaming, as we don't want to a local RMW cycle ++ * if we can avoid it. If we're doing local caching or content ++ * crypto, we award that priority over avoiding RMW. If the ++ * file is open readably, then we let ->read_folio() fill in ++ * the gaps. + */ + finfo = netfs_folio_info(folio); + group = netfs_folio_group(folio); +@@ -284,12 +284,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + + /* We don't want to do a streaming write on a file that loses + * caching service temporarily because the backing store got +- * culled and we don't really want to get a streaming write on +- * a file that's open for reading as ->read_folio() then has to +- * be able to flush it. ++ * culled. + */ +- if ((file->f_mode & FMODE_READ) || +- netfs_is_cache_enabled(ctx)) { ++ if (netfs_is_cache_enabled(ctx)) { + if (finfo) { + netfs_stat(&netfs_n_wh_wstream_conflict); + goto flush_content; +-- +2.53.0 + diff --git a/queue-6.18/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch b/queue-6.18/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch new file mode 100644 index 0000000000..8a427134c9 --- /dev/null +++ b/queue-6.18/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch @@ -0,0 +1,116 @@ +From 4c03ce695c3b5e6866ced0c7562325273864a555 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:19:27 -0500 +Subject: NFS: Use nlmclnt_shutdown_rpc_clnt() to safely shut down NLM + +From: Chuck Lever + +[ Upstream commit 840621fd2ff23ada8b9262d90477e75232566e6b ] + +A race condition exists in shutdown_store() when writing to the sysfs +"shutdown" file concurrently with nlm_shutdown_hosts_net(). Without +synchronization, the following sequence can occur: + + 1. shutdown_store() reads server->nlm_host (non-NULL) + 2. nlm_shutdown_hosts_net() acquires nlm_host_mutex, calls + rpc_shutdown_client(), sets h_rpcclnt to NULL, and potentially + frees the host via nlm_gc_hosts() + 3. shutdown_store() dereferences the now-stale or freed host + +Introduce nlmclnt_shutdown_rpc_clnt(), which acquires nlm_host_mutex +before accessing h_rpcclnt. This synchronizes with +nlm_shutdown_hosts_net() and ensures the rpc_clnt pointer remains +valid during the shutdown operation. + +This change also improves API layering: NFS client code no longer +needs to include the internal lockd header to access nlm_host fields. +The new helper resides in bind.h alongside other public lockd +interfaces. + +Reported-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 29 +++++++++++++++++++++++++++++ + fs/nfs/sysfs.c | 4 ++-- + include/linux/lockd/bind.h | 1 + + 3 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 5e6877c37f730..87c88a8f99026 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -306,6 +306,35 @@ void nlmclnt_release_host(struct nlm_host *host) + } + } + ++/* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ ++static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) ++{ ++ return true; ++} ++ ++/** ++ * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations ++ * @host: nlm_host to shut down ++ * ++ * Cancels outstanding RPC tasks and marks the client as shut down. ++ * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent ++ * races between shutdown and host destruction. Safe to call if h_rpcclnt ++ * is NULL or already shut down. ++ */ ++void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) ++{ ++ struct rpc_clnt *clnt; ++ ++ mutex_lock(&nlm_host_mutex); ++ clnt = host->h_rpcclnt; ++ if (clnt) { ++ clnt->cl_shutdown = 1; ++ rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); ++ } ++ mutex_unlock(&nlm_host_mutex); ++} ++EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); ++ + /** + * nlmsvc_lookup_host - Find an NLM host handle matching a remote client + * @rqstp: incoming NLM request +diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c +index ea6e6168092b2..008b3decde24d 100644 +--- a/fs/nfs/sysfs.c ++++ b/fs/nfs/sysfs.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + + #include "internal.h" + #include "nfs4_fs.h" +@@ -285,7 +285,7 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr, + shutdown_client(server->client_acl); + + if (server->nlm_host) +- shutdown_client(server->nlm_host->h_rpcclnt); ++ nlmclnt_shutdown_rpc_clnt(server->nlm_host); + out: + shutdown_nfs_client(server->nfs_client); + return count; +diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h +index c53c81242e727..40c124f932252 100644 +--- a/include/linux/lockd/bind.h ++++ b/include/linux/lockd/bind.h +@@ -58,6 +58,7 @@ struct nlmclnt_initdata { + extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); + extern void nlmclnt_done(struct nlm_host *host); + extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); ++extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); + + /* + * NLM client operations provide a means to modify RPC processing of NLM +-- +2.53.0 + diff --git a/queue-6.18/nfsd-fix-infinite-loop-in-layout-state-revocation.patch b/queue-6.18/nfsd-fix-infinite-loop-in-layout-state-revocation.patch new file mode 100644 index 0000000000..63a29860da --- /dev/null +++ b/queue-6.18/nfsd-fix-infinite-loop-in-layout-state-revocation.patch @@ -0,0 +1,46 @@ +From b298f4b08961d9a1a3c7395fbcdf90a54c4cf926 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 14:52:59 -0400 +Subject: NFSD: Fix infinite loop in layout state revocation + +From: Chuck Lever + +[ Upstream commit 4f8ef58c10bfe5f86a643c7c8331b37e69e3dae1 ] + +find_one_sb_stid() skips stids whose sc_status is non-zero, but the +SC_TYPE_LAYOUT case in nfsd4_revoke_states() never sets sc_status +before calling nfsd4_close_layout(). The retry loop therefore finds +the same layout stid on every iteration, hanging the revoker +indefinitely. + +Fixes: 1e33e1414bec ("nfsd: allow layout state to be admin-revoked.") +Reported-by: Dai Ngo +Reviewed-by: Jeff Layton +Tested-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index cb8096e94f518..a9e95df2fdb68 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1848,6 +1848,13 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) + break; + case SC_TYPE_LAYOUT: + ls = layoutstateid(stid); ++ spin_lock(&clp->cl_lock); ++ if (stid->sc_status == 0) { ++ stid->sc_status |= ++ SC_STATUS_ADMIN_REVOKED; ++ atomic_inc(&clp->cl_admin_revoked); ++ } ++ spin_unlock(&clp->cl_lock); + nfsd4_close_layout(ls); + break; + } +-- +2.53.0 + diff --git a/queue-6.18/nouveau-pci-quiesce-gpu-on-shutdown.patch b/queue-6.18/nouveau-pci-quiesce-gpu-on-shutdown.patch new file mode 100644 index 0000000000..6704c43adc --- /dev/null +++ b/queue-6.18/nouveau-pci-quiesce-gpu-on-shutdown.patch @@ -0,0 +1,204 @@ +From 1111689445f8071097d5493966be6ebec9d3b44f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 19:36:44 +0800 +Subject: nouveau: pci: quiesce GPU on shutdown + +From: Li Chen + +[ Upstream commit 310326bb7df4bba094a3fc60364c641c547fd923 ] + +Kexec reboot does not reset PCI devices. +Invoking the full DRM/TTM teardown from ->shutdown can trigger WARNs when +userspace still holds DRM file descriptors. + +Quiesce the GPU through the suspend path and then power down the PCI +function so the next kernel can re-initialize the device from a consistent +state. + +WARNING: drivers/gpu/drm/drm_mode_config.c:578 at drm_mode_config_cleanup+0x2e7/0x300, CPU#2: kexec/1300 +Call Trace: + + ? srso_return_thunk+0x5/0x5f + ? enable_work+0x3a/0x100 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +nouveau 0000:26:00.0: [drm] drm_WARN_ON(!list_empty(&fb->filp_head)) +WARNING: drivers/gpu/drm/drm_framebuffer.c:833 at drm_framebuffer_free+0x73/0xa0, CPU#2: kexec/1300 +Call Trace: + + drm_mode_config_cleanup+0x248/0x300 + ? __pfx___drm_printfn_dbg+0x10/0x10 + ? drm_mode_config_cleanup+0x1dc/0x300 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +WARNING: include/drm/ttm/ttm_resource.h:406 at nouveau_ttm_fini+0x257/0x270 [nouveau], CPU#2: kexec/1300 +Call Trace: + + nouveau_drm_device_fini+0x93/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Signed-off-by: Li Chen +Reviewed-by: Dave Airlie +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/20260121113646.111561-1-me@linux.beauty +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index b760586b1727e..fbaa0d06b5e2f 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -1079,6 +1079,37 @@ nouveau_pmops_resume(struct device *dev) + return ret; + } + ++static void ++nouveau_drm_shutdown(struct pci_dev *pdev) ++{ ++ struct nouveau_drm *drm = pci_get_drvdata(pdev); ++ int ret; ++ ++ if (!drm) ++ return; ++ ++ if (drm->dev->switch_power_state == DRM_SWITCH_POWER_OFF || ++ drm->dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) ++ return; ++ ++ ret = nouveau_do_suspend(drm, false); ++ if (ret) ++ NV_ERROR(drm, "shutdown suspend failed with: %d\n", ret); ++ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ /* ++ * This is just to give the pci power transition time to settle ++ * before an immediate kexec jump. it’s mirroring the existing ++ * nouveau_pmops_suspend() behavior, which already does ++ * udelay(200) right after pci_set_power_state(..., pci_d3hot). In ++ * ->shutdown() we’re allowed to sleep, so I used usleep_range() ++ * instead of a busy-wait udelay(). ++ */ ++ usleep_range(200, 400); ++} ++ + static int + nouveau_pmops_freeze(struct device *dev) + { +@@ -1408,6 +1439,7 @@ nouveau_drm_pci_driver = { + .id_table = nouveau_drm_pci_table, + .probe = nouveau_drm_probe, + .remove = nouveau_drm_remove, ++ .shutdown = nouveau_drm_shutdown, + .driver.pm = &nouveau_pm_ops, + }; + +-- +2.53.0 + diff --git a/queue-6.18/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch b/queue-6.18/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch new file mode 100644 index 0000000000..3543faa7a3 --- /dev/null +++ b/queue-6.18/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch @@ -0,0 +1,43 @@ +From 0a5986f89793b2466eeed75bb22cb9a3cc575cf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 19:23:01 +0800 +Subject: nsfs: fix wrong error code returned for pidns ioctls + +From: Zhihao Cheng + +[ Upstream commit 725ecd80688bf3c57ca9205431f2c06174ff0756 ] + +When executing NS_GET_PID_FROM_PIDNS (or similar pidns ioctls), if the +target task cannot be found in the corresponding pid_ns, the error code +should be ESRCH instead of ENOTTY. + +This bug was introduced when the extensible ioctl handling was added. +Without proper return, ret would be overwritten by the default case in +the extensible ioctl switch statement. + +Fixes: a1d220d9dafa8 ("nsfs: iterate through mount namespaces") +Signed-off-by: Zhihao Cheng +Link: https://patch.msgid.link/20260507112301.1042757-1-chengzhihao1@huawei.com +Reviewed-by: Yang Erkun +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/nsfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nsfs.c b/fs/nsfs.c +index f22c2a636e8f3..e2f9a725883c7 100644 +--- a/fs/nsfs.c ++++ b/fs/nsfs.c +@@ -261,7 +261,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, + else + tsk = find_task_by_pid_ns(arg, pid_ns); + if (!tsk) +- break; ++ return ret; + + switch (ioctl) { + case NS_GET_PID_FROM_PIDNS: +-- +2.53.0 + diff --git a/queue-6.18/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-6.18/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..8d09ca4b55 --- /dev/null +++ b/queue-6.18/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From f56b62dd646fe808f61c2dc4d708da61bf149c8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index 050b3709e0204..1a1ffe93ba10c 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1482,6 +1482,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-6.18/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch b/queue-6.18/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch new file mode 100644 index 0000000000..84a86711a3 --- /dev/null +++ b/queue-6.18/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch @@ -0,0 +1,56 @@ +From d1c18e7d63fc7e0e7b9fa8ed75bc046451d6b041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:57:57 +0200 +Subject: ntfs3: fix OOB write in attr_wof_frame_info() + +From: 0xkato <0xkkato@gmail.com> + +[ Upstream commit 859d777646b56dd878b136392f3d03fb8153b559 ] + +In attr_wof_frame_info(), the offset-table read range for a nonresident +WofCompressedData stream is: + + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ... + ntfs_read_run(sbi, run, addr, from, to - from); + +A crafted image sets WofCompressedData.nres.data_size to 0xfff while the +file is large enough to request frame 1024 (offset 0x400000). This gives +from=0x1000, to=0xfff. The unsigned (to - from) wraps to 0xffffffffffffffff +and ntfs_read_write_run() overflows the single-page offs_folio via memcpy. + +Triggered by pread() on a mounted NTFS image. Depending on adjacent +memory layout at the time of the overflow, KASAN reports this as +slab-out-of-bounds, use-after-free, or slab-use-after-free all at +ntfs_read_write_run(). Secondary corruption/panic paths were also observed. + +Reject the read when the offset-table page is outside the stream. + +Signed-off-by: 0xkato <0xkkato@gmail.com> +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index 5a7675112e7b8..35ca636aecced 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1472,6 +1472,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr, + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ++ if (from >= wof_size) { ++ _ntfs_bad_inode(&ni->vfs_inode); ++ err = -EINVAL; ++ goto out1; ++ } ++ + err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME, + ARRAY_SIZE(WOF_NAME), run, + from, to); +-- +2.53.0 + diff --git a/queue-6.18/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-6.18/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..c778d8b87e --- /dev/null +++ b/queue-6.18/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From 090a2bba5c4bcc62258b2c446d5682b3fcf3cd2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index 205baa791f998..52e27f9385b2a 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -433,6 +433,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-6.18/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-6.18/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..111ab41886 --- /dev/null +++ b/queue-6.18/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 6af023ddc7e4b9478d5647147a931292aed3937c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index bf78faf1a4ffa..689f5883570b8 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3965,3 +3965,4 @@ module_exit(nvme_fc_exit_module); + + MODULE_DESCRIPTION("NVMe host FC transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 190a4cfa8a5ee..b069a00d19cc5 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2432,3 +2432,4 @@ module_exit(nvme_rdma_cleanup_module); + + MODULE_DESCRIPTION("NVMe host RDMA transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 9a96df1a511c0..303898e904c70 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -3070,3 +3070,4 @@ module_exit(nvme_tcp_cleanup_module); + + MODULE_DESCRIPTION("NVMe host TCP transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-6.18/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-6.18/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..9c279cb376 --- /dev/null +++ b/queue-6.18/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From 7368776b6a9c72b122316c3ac92e5f7245576c70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 5e36a5926fe03..51fcc5c6bb38e 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3851,6 +3851,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-6.18/nvme-core-fix-parameter-name-in-comment.patch b/queue-6.18/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..6c2cb8341f --- /dev/null +++ b/queue-6.18/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From fda4f97e1126db85352c7ae004fcf860d9421470 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 9a0071bd791c8..610b6b6458bfd 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3017,7 +3017,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-6.18/nvme-fix-bio-leak-on-mapping-failure.patch b/queue-6.18/nvme-fix-bio-leak-on-mapping-failure.patch new file mode 100644 index 0000000000..da71d3fc3e --- /dev/null +++ b/queue-6.18/nvme-fix-bio-leak-on-mapping-failure.patch @@ -0,0 +1,48 @@ +From c2d8f36a5fb719484c80977fb0eee8d87d2277cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 06:16:02 -0700 +Subject: nvme: fix bio leak on mapping failure + +From: Keith Busch + +[ Upstream commit 2279cd9c61a330e5de4d6eb0bc422820dd6fdf36 ] + +The local bio is always NULL, so we'd leak the bio if the integrity +mapping failed. Just get it directly from the request. + +Fixes: d0d1d522316e91f ("blk-map: provide the bdev to bio if one exists") +Reviewed-by: Sagi Grimberg +Reviewed-by: John Garry +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/ioctl.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c +index c212fa952c0f4..5bbaf257fd6c5 100644 +--- a/drivers/nvme/host/ioctl.c ++++ b/drivers/nvme/host/ioctl.c +@@ -122,7 +122,6 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + bool supports_metadata = bdev && blk_get_integrity(bdev->bd_disk); + struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; + bool has_metadata = meta_buffer && meta_len; +- struct bio *bio = NULL; + int ret; + + if (!nvme_ctrl_sgl_supported(ctrl)) +@@ -154,8 +153,8 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + return ret; + + out_unmap: +- if (bio) +- blk_rq_unmap_user(bio); ++ if (req->bio) ++ blk_rq_unmap_user(req->bio); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch b/queue-6.18/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch new file mode 100644 index 0000000000..8de0328691 --- /dev/null +++ b/queue-6.18/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch @@ -0,0 +1,110 @@ +From 0f32c57bd7b460b991fa28d260a8b8ef1b42fb96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:08:48 +0530 +Subject: nvme-loop: do not cancel I/O and admin tagset during ctrl + reset/shutdown + +From: Nilay Shroff + +[ Upstream commit 886f35201591ded7958e16fe3750871d3ca0bcdf ] + +Cancelling the I/O and admin tagsets during nvme-loop controller reset +or shutdown is unnecessary. The subsequent destruction of the I/O and +admin queues already waits for all in-flight target operations to +complete. + +Cancelling the tagsets first also opens a race window. After a request +tag has been cancelled, a late completion from the target may still +arrive before the queues are destroyed. In that case the completion path +may access a request whose tag has already been cancelled or freed, +which can lead to a kernel crash. Please see below the kernel crash +encountered while running blktests nvme/040: + +run blktests nvme/040 at 2026-03-08 06:34:27 +loop0: detected capacity change from 0 to 2097152 +nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +nvme nvme6: creating 96 I/O queues. +nvme nvme6: new ctrl: "blktests-subsystem-1" +nvme_log_error: 1 callbacks suppressed +block nvme6n1: no usable path - requeuing I/O +nvme6c6n1: Read(0x2) @ LBA 2096384, 128 blocks, Host Aborted Command (sct 0x3 / sc 0x71) +blk_print_req_error: 1 callbacks suppressed +I/O error, dev nvme6c6n1, sector 2096384 op 0x0:(READ) flags 0x2880700 phys_seg 1 prio class 2 +block nvme6n1: no usable path - requeuing I/O +Kernel attempted to read user page (236) - exploit attempt? (uid: 0) +BUG: Kernel NULL pointer dereference on read at 0x00000236 +Faulting instruction address: 0xc000000000961274 +Oops: Kernel access of bad area, sig: 11 [#1] +LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries +Modules linked in: nvme_loop nvme_fabrics loop nvmet null_blk rpadlpar_io rpaphp xsk_diag bonding rfkill nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink pseries_rng dax_pmem vmx_crypto drm drm_panel_orientation_quirks xfs mlx5_core nvme bnx2x sd_mod nd_pmem nd_btt nvme_core sg papr_scm tls libnvdimm ibmvscsi ibmveth scsi_transport_srp nvme_keyring nvme_auth mdio hkdf pseries_wdt dm_mirror dm_region_hash dm_log dm_mod fuse [last unloaded: loop] +CPU: 25 UID: 0 PID: 0 Comm: swapper/25 Kdump: loaded Not tainted 7.0.0-rc3+ #14 PREEMPT +Hardware name: IBM,9043-MRX Power11 (architected) 0x820200 0xf000007 of:IBM,FW1120.00 (RF1120_128) hv:phyp pSeries +NIP: c000000000961274 LR: c008000009af1808 CTR: c00000000096124c +REGS: c0000007ffc0f910 TRAP: 0300 Not tainted (7.0.0-rc3+) +MSR: 8000000000009033 CR: 22222222 XER: 00000000 +CFAR: c008000009af232c DAR: 0000000000000236 DSISR: 40000000 IRQMASK: 0 +GPR00: c008000009af17fc c0000007ffc0fbb0 c000000001c78100 c0000000be05cc00 +GPR04: 0000000000000001 0000000000000000 0000000000000007 0000000000000000 +GPR08: 0000000000000000 0000000000000000 0000000000000002 c008000009af2318 +GPR12: c00000000096124c c0000007ffdab880 0000000000000000 0000000000000000 +GPR16: 0000000000000010 0000000000000000 0000000000000004 0000000000000000 +GPR20: 0000000000000001 c000000002ca2b00 0000000100043bb2 000000000000000a +GPR24: 000000000000000a 0000000000000000 0000000000000000 0000000000000000 +GPR28: c000000084021d40 c000000084021d50 c0000000be05cd60 c0000000be05cc00 +NIP [c000000000961274] blk_mq_complete_request_remote+0x28/0x2d4 +LR [c008000009af1808] nvme_loop_queue_response+0x110/0x290 [nvme_loop] +Call Trace: + 0xc00000000502c640 (unreliable) + nvme_loop_queue_response+0x104/0x290 [nvme_loop] + __nvmet_req_complete+0x80/0x498 [nvmet] + nvmet_req_complete+0x24/0xf8 [nvmet] + nvmet_bio_done+0x58/0xcc [nvmet] + bio_endio+0x250/0x390 + blk_update_request+0x2e8/0x68c + blk_mq_end_request+0x30/0x5c + lo_complete_rq+0x94/0x110 [loop] + blk_complete_reqs+0x78/0x98 + handle_softirqs+0x148/0x454 + do_softirq_own_stack+0x3c/0x50 + __irq_exit_rcu+0x18c/0x1b4 + irq_exit+0x1c/0x34 + do_IRQ+0x114/0x278 + hardware_interrupt_common_virt+0x28c/0x290 + +Since the queue teardown path already guarantees that all target-side +operations have completed, cancelling the tagsets is redundant and +unsafe. So avoid cancelling the I/O and admin tagsets during controller +reset and shutdown. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Nilay Shroff +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/loop.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index f85a8441bcc6e..46bebd766f5c5 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -419,7 +419,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + { + if (ctrl->ctrl.queue_count > 1) { + nvme_quiesce_io_queues(&ctrl->ctrl); +- nvme_cancel_tagset(&ctrl->ctrl); + nvme_loop_destroy_io_queues(ctrl); + } + +@@ -427,7 +426,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + if (nvme_ctrl_state(&ctrl->ctrl) == NVME_CTRL_LIVE) + nvme_disable_ctrl(&ctrl->ctrl, true); + +- nvme_cancel_admin_tagset(&ctrl->ctrl); + nvme_loop_destroy_admin_queue(ctrl); + } + +-- +2.53.0 + diff --git a/queue-6.18/nvme-multipath-put-module-reference-when-delayed-rem.patch b/queue-6.18/nvme-multipath-put-module-reference-when-delayed-rem.patch new file mode 100644 index 0000000000..36b8a5a874 --- /dev/null +++ b/queue-6.18/nvme-multipath-put-module-reference-when-delayed-rem.patch @@ -0,0 +1,41 @@ +From d932892502153c90dca75e9d54ea3ea7a58af189 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 15:53:58 +0000 +Subject: nvme-multipath: put module reference when delayed removal work is + canceled + +From: John Garry + +[ Upstream commit 3f150f0f010f234f34a67897344f18e68fe803f7 ] + +The delayed disk removal work is canceled when a NS (re)appears. However, +we do not put the module reference grabbed in nvme_mpath_remove_disk(), so +fix that. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Nilay Shroff +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: John Garry +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 610b6b6458bfd..883615e545137 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4056,7 +4056,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info) + mutex_unlock(&ctrl->subsys->lock); + + #ifdef CONFIG_NVME_MULTIPATH +- cancel_delayed_work(&head->remove_work); ++ if (cancel_delayed_work(&head->remove_work)) ++ module_put(THIS_MODULE); + #endif + return 0; + +-- +2.53.0 + diff --git a/queue-6.18/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch b/queue-6.18/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch new file mode 100644 index 0000000000..58a2215ac1 --- /dev/null +++ b/queue-6.18/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch @@ -0,0 +1,90 @@ +From ceba05bf2ff3c53d55fe6374cc37566f7297d292 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 16:11:16 +0800 +Subject: nvme-pci: fix use-after-free in nvme_free_host_mem() + +From: Chia-Lin Kao (AceLan) + +[ Upstream commit b35a13036755c5803168a7cb93bc66035c3e65b8 ] + +nvme_free_host_mem() frees dev->hmb_sgt via dma_free_noncontiguous() +but never clears the pointer afterward. This leads to a use-after-free +if nvme_free_host_mem() is called twice in the same error path. + +This can happen during nvme_probe() when nvme_setup_host_mem() succeeds +in allocating the HMB (setting dev->hmb_sgt) but nvme_set_host_mem() +fails with an I/O error: + + nvme_setup_host_mem() + nvme_alloc_host_mem_single() -> sets dev->hmb_sgt + nvme_set_host_mem() -> fails with -EIO + nvme_free_host_mem() -> frees hmb_sgt, but does NOT NULL it + return error + + nvme_probe() error path: + nvme_free_host_mem() -> dev->hmb_sgt is stale, use-after-free + +The second call dereferences the freed sgt, causing a NULL pointer +dereference in iommu_dma_free_noncontiguous() when it accesses +sgt->sgl->dma_address (the backing memory has been freed and zeroed). + +This is reproducible on Thunderbolt-attached NVMe devices (e.g., OWC +Envoy Express behind a Dell WD22TB4 dock) where the device intermittently +returns I/O errors during HMB setup due to PCIe link instability. + + BUG: kernel NULL pointer dereference, address: 0000000000000010 + RIP: 0010:iommu_dma_free_noncontiguous+0x22/0x80 + Call Trace: + + dma_free_noncontiguous+0x3b/0x130 + nvme_free_host_mem+0x30/0xf0 [nvme] + nvme_probe.cold+0xcc/0x275 [nvme] + local_pci_probe+0x43/0xa0 + pci_device_probe+0xeea/0x290 + really_probe+0xf9/0x3b0 + __driver_probe_device+0x8b/0x170 + driver_probe_device+0x24/0xd0 + __driver_attach_async_helper+0x6b/0x110 + async_run_entry_fn+0x37/0x170 + process_one_work+0x1ac/0x3d0 + worker_thread+0x1b8/0x360 + kthread+0xf7/0x130 + ret_from_fork+0x2d8/0x3a0 + ret_from_fork_asm+0x1a/0x30 + + +Fix this by setting dev->hmb_sgt to NULL after freeing it, so the +second call takes the multi-descriptor path which safely handles the +already-cleaned-up state. + +Fixes: 63a5c7a4b4c4 ("nvme-pci: use dma_alloc_noncontigous if possible") +Signed-off-by: Chia-Lin Kao (AceLan) +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 2e32242bed67c..5e36a5926fe03 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2320,11 +2320,13 @@ static void nvme_free_host_mem_multi(struct nvme_dev *dev) + + static void nvme_free_host_mem(struct nvme_dev *dev) + { +- if (dev->hmb_sgt) ++ if (dev->hmb_sgt) { + dma_free_noncontiguous(dev->dev, dev->host_mem_size, + dev->hmb_sgt, DMA_BIDIRECTIONAL); +- else ++ dev->hmb_sgt = NULL; ++ } else { + nvme_free_host_mem_multi(dev); ++ } + + dma_free_coherent(dev->dev, dev->host_mem_descs_size, + dev->host_mem_descs, dev->host_mem_descs_dma); +-- +2.53.0 + diff --git a/queue-6.18/nvme-tcp-teardown-circular-locking-fixes.patch b/queue-6.18/nvme-tcp-teardown-circular-locking-fixes.patch new file mode 100644 index 0000000000..594cb836b6 --- /dev/null +++ b/queue-6.18/nvme-tcp-teardown-circular-locking-fixes.patch @@ -0,0 +1,304 @@ +From 2a267f2e074594633e90da7f8d87beb30113d12b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:16:28 -0700 +Subject: nvme-tcp: teardown circular locking fixes + +From: Chaitanya Kulkarni + +[ Upstream commit 26bb12b9caafa2e62d638104bf2732f610cdbb0b ] + +When a controller reset is triggered via sysfs (by writing to +/sys/class/nvme//reset_controller), the reset work tears down +and re-establishes all queues. The socket release using fput() defers +the actual cleanup to task_work delayed_fput workqueue. This deferred +cleanup can race with the subsequent queue re-allocation during reset, +potentially leading to use-after-free or resource conflicts. + +Replace fput() with __fput_sync() to ensure synchronous socket release, +guaranteeing that all socket resources are fully cleaned up before the +function returns. This prevents races during controller reset where +new queue setup may begin before the old socket is fully released. + +* Call chain during reset: + nvme_reset_ctrl_work() + -> nvme_tcp_teardown_ctrl() + -> nvme_tcp_teardown_io_queues() + -> nvme_tcp_free_io_queues() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_teardown_admin_queue() + -> nvme_tcp_free_admin_queue() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_setup_ctrl() <-- race with deferred fput + +memalloc_noreclaim_save() sets PF_MEMALLOC which is intended for tasks +performing memory reclaim work that need reserve access. While PF_MEMALLOC +prevents the task from entering direct reclaim (causing __need_reclaim() to +return false), it does not strip __GFP_IO from gfp flags. The allocator can +therefore still trigger writeback I/O when __GFP_IO remains set, which is +unsafe when the caller holds block layer locks. + +Switch to memalloc_noio_save() which sets PF_MEMALLOC_NOIO. This causes +current_gfp_context() to strip __GFP_IO|__GFP_FS from every allocation in +the scope, making it safe to allocate memory while holding elevator_lock and +set->srcu. + +* The issue can be reproduced using blktests: + + nvme_trtype=tcp ./check nvme/005 +blktests (master) # nvme_trtype=tcp ./check nvme/005 +nvme/005 (tr=tcp) (reset local loopback target) [failed] + runtime 0.725s ... 0.798s + something found in dmesg: + [ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 + + [...] + ... + (See '/root/blktests/results/nodev_tr_tcp/nvme/005.dmesg' for the entire message) +blktests (master) # cat /root/blktests/results/nodev_tr_tcp/nvme/005.dmesg +[ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 +[ 108.526983] loop0: detected capacity change from 0 to 2097152 +[ 108.555606] nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +[ 108.572531] nvmet_tcp: enabling port 0 (127.0.0.1:4420) +[ 108.613061] nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.616832] nvme nvme0: creating 48 I/O queues. +[ 108.630791] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.661892] nvme nvme0: new ctrl: NQN "blktests-subsystem-1", addr 127.0.0.1:4420, hostnqn: nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349 +[ 108.746639] nvmet: Created nvm controller 2 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.748466] nvme nvme0: creating 48 I/O queues. +[ 108.802984] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.829983] nvme nvme0: Removing ctrl: NQN "blktests-subsystem-1" +[ 108.854288] block nvme0n1: no available path - failing I/O +[ 108.854344] block nvme0n1: no available path - failing I/O +[ 108.854373] Buffer I/O error on dev nvme0n1, logical block 1, async page read + +[ 108.891693] ====================================================== +[ 108.895912] WARNING: possible circular locking dependency detected +[ 108.900184] 6.17.0nvme+ #3 Tainted: G N +[ 108.903913] ------------------------------------------------------ +[ 108.908171] nvme/2734 is trying to acquire lock: +[ 108.911957] ffff88810210e610 (set->srcu){.+.+}-{0:0}, at: __synchronize_srcu+0x17/0x170 +[ 108.917587] + but task is already holding lock: +[ 108.921570] ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 108.927361] + which lock already depends on the new lock. + +[ 108.933018] + the existing dependency chain (in reverse order) is: +[ 108.938223] + -> #4 (&q->elevator_lock){+.+.}-{4:4}: +[ 108.942988] __mutex_lock+0xa2/0x1150 +[ 108.945873] elevator_change+0xa8/0x1c0 +[ 108.948925] elv_iosched_store+0xdf/0x140 +[ 108.952043] kernfs_fop_write_iter+0x16a/0x220 +[ 108.955367] vfs_write+0x378/0x520 +[ 108.957598] ksys_write+0x67/0xe0 +[ 108.959721] do_syscall_64+0x76/0xbb0 +[ 108.962052] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 108.965145] + -> #3 (&q->q_usage_counter(io)){++++}-{0:0}: +[ 108.968923] blk_alloc_queue+0x30e/0x350 +[ 108.972117] blk_mq_alloc_queue+0x61/0xd0 +[ 108.974677] scsi_alloc_sdev+0x2a0/0x3e0 +[ 108.977092] scsi_probe_and_add_lun+0x1bd/0x430 +[ 108.979921] __scsi_add_device+0x109/0x120 +[ 108.982504] ata_scsi_scan_host+0x97/0x1c0 +[ 108.984365] async_run_entry_fn+0x2d/0x130 +[ 108.986109] process_one_work+0x20e/0x630 +[ 108.987830] worker_thread+0x184/0x330 +[ 108.989473] kthread+0x10a/0x250 +[ 108.990852] ret_from_fork+0x297/0x300 +[ 108.992491] ret_from_fork_asm+0x1a/0x30 +[ 108.994159] + -> #2 (fs_reclaim){+.+.}-{0:0}: +[ 108.996320] fs_reclaim_acquire+0x99/0xd0 +[ 108.998058] kmem_cache_alloc_node_noprof+0x4e/0x3c0 +[ 109.000123] __alloc_skb+0x15f/0x190 +[ 109.002195] tcp_send_active_reset+0x3f/0x1e0 +[ 109.004038] tcp_disconnect+0x50b/0x720 +[ 109.005695] __tcp_close+0x2b8/0x4b0 +[ 109.007227] tcp_close+0x20/0x80 +[ 109.008663] inet_release+0x31/0x60 +[ 109.010175] __sock_release+0x3a/0xc0 +[ 109.011778] sock_close+0x14/0x20 +[ 109.013263] __fput+0xee/0x2c0 +[ 109.014673] delayed_fput+0x31/0x50 +[ 109.016183] process_one_work+0x20e/0x630 +[ 109.017897] worker_thread+0x184/0x330 +[ 109.019543] kthread+0x10a/0x250 +[ 109.020929] ret_from_fork+0x297/0x300 +[ 109.022565] ret_from_fork_asm+0x1a/0x30 +[ 109.024194] + -> #1 (sk_lock-AF_INET-NVME){+.+.}-{0:0}: +[ 109.026634] lock_sock_nested+0x2e/0x70 +[ 109.028251] tcp_sendmsg+0x1a/0x40 +[ 109.029783] sock_sendmsg+0xed/0x110 +[ 109.031321] nvme_tcp_try_send_cmd_pdu+0x13e/0x260 [nvme_tcp] +[ 109.034263] nvme_tcp_try_send+0xb3/0x330 [nvme_tcp] +[ 109.036375] nvme_tcp_queue_rq+0x342/0x3d0 [nvme_tcp] +[ 109.038528] blk_mq_dispatch_rq_list+0x297/0x800 +[ 109.040448] __blk_mq_sched_dispatch_requests+0x3db/0x5f0 +[ 109.042677] blk_mq_sched_dispatch_requests+0x29/0x70 +[ 109.044787] blk_mq_run_work_fn+0x76/0x1b0 +[ 109.046535] process_one_work+0x20e/0x630 +[ 109.048245] worker_thread+0x184/0x330 +[ 109.049890] kthread+0x10a/0x250 +[ 109.051331] ret_from_fork+0x297/0x300 +[ 109.053024] ret_from_fork_asm+0x1a/0x30 +[ 109.054740] + -> #0 (set->srcu){.+.+}-{0:0}: +[ 109.056850] __lock_acquire+0x1468/0x2210 +[ 109.058614] lock_sync+0xa5/0x110 +[ 109.060048] __synchronize_srcu+0x49/0x170 +[ 109.061802] elevator_switch+0xc9/0x330 +[ 109.063950] elevator_change+0x128/0x1c0 +[ 109.065675] elevator_set_none+0x4c/0x90 +[ 109.067316] blk_unregister_queue+0xa8/0x110 +[ 109.069165] __del_gendisk+0x14e/0x3c0 +[ 109.070824] del_gendisk+0x75/0xa0 +[ 109.072328] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.074365] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.076652] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.078775] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.081009] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.083082] kernfs_fop_write_iter+0x16a/0x220 +[ 109.085009] vfs_write+0x378/0x520 +[ 109.086539] ksys_write+0x67/0xe0 +[ 109.087982] do_syscall_64+0x76/0xbb0 +[ 109.089577] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.091665] + other info that might help us debug this: + +[ 109.095478] Chain exists of: + set->srcu --> &q->q_usage_counter(io) --> &q->elevator_lock + +[ 109.099544] Possible unsafe locking scenario: + +[ 109.101708] CPU0 CPU1 +[ 109.103402] ---- ---- +[ 109.105103] lock(&q->elevator_lock); +[ 109.106530] lock(&q->q_usage_counter(io)); +[ 109.109022] lock(&q->elevator_lock); +[ 109.111391] sync(set->srcu); +[ 109.112586] + *** DEADLOCK *** + +[ 109.114772] 5 locks held by nvme/2734: +[ 109.116189] #0: ffff888101925410 (sb_writers#4){.+.+}-{0:0}, at: ksys_write+0x67/0xe0 +[ 109.119143] #1: ffff88817a914e88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x10f/0x220 +[ 109.123141] #2: ffff8881046313f8 (kn->active#185){++++}-{0:0}, at: sysfs_remove_file_self+0x26/0x50 +[ 109.126543] #3: ffff88810470e1d0 (&set->update_nr_hwq_lock){++++}-{4:4}, at: del_gendisk+0x6d/0xa0 +[ 109.129891] #4: ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 109.133149] + stack backtrace: +[ 109.134817] CPU: 6 UID: 0 PID: 2734 Comm: nvme Tainted: G N 6.17.0nvme+ #3 PREEMPT(voluntary) +[ 109.134819] Tainted: [N]=TEST +[ 109.134820] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 +[ 109.134821] Call Trace: +[ 109.134823] +[ 109.134824] dump_stack_lvl+0x75/0xb0 +[ 109.134828] print_circular_bug+0x26a/0x330 +[ 109.134831] check_noncircular+0x12f/0x150 +[ 109.134834] __lock_acquire+0x1468/0x2210 +[ 109.134837] ? __synchronize_srcu+0x17/0x170 +[ 109.134838] lock_sync+0xa5/0x110 +[ 109.134840] ? __synchronize_srcu+0x17/0x170 +[ 109.134842] __synchronize_srcu+0x49/0x170 +[ 109.134843] ? mark_held_locks+0x49/0x80 +[ 109.134845] ? _raw_spin_unlock_irqrestore+0x2d/0x60 +[ 109.134847] ? kvm_clock_get_cycles+0x14/0x30 +[ 109.134853] ? ktime_get_mono_fast_ns+0x36/0xb0 +[ 109.134858] elevator_switch+0xc9/0x330 +[ 109.134860] elevator_change+0x128/0x1c0 +[ 109.134862] ? kernfs_put.part.0+0x86/0x290 +[ 109.134864] elevator_set_none+0x4c/0x90 +[ 109.134866] blk_unregister_queue+0xa8/0x110 +[ 109.134868] __del_gendisk+0x14e/0x3c0 +[ 109.134870] del_gendisk+0x75/0xa0 +[ 109.134872] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.134879] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.134887] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.134893] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.134899] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.134905] kernfs_fop_write_iter+0x16a/0x220 +[ 109.134908] vfs_write+0x378/0x520 +[ 109.134911] ksys_write+0x67/0xe0 +[ 109.134913] do_syscall_64+0x76/0xbb0 +[ 109.134915] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.134916] RIP: 0033:0x7fd68a737317 +[ 109.134917] Code: 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 109.134919] RSP: 002b:00007ffded1546d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 109.134920] RAX: ffffffffffffffda RBX: 000000000054f7e0 RCX: 00007fd68a737317 +[ 109.134921] RDX: 0000000000000001 RSI: 00007fd68a855719 RDI: 0000000000000003 +[ 109.134921] RBP: 0000000000000003 R08: 0000000030407850 R09: 00007fd68a7cd4e0 +[ 109.134922] R10: 00007fd68a65b130 R11: 0000000000000246 R12: 00007fd68a855719 +[ 109.134923] R13: 00000000304074c0 R14: 00000000304074c0 R15: 0000000030408660 +[ 109.134926] +[ 109.962756] Key type psk unregistered + +Reviewed-by: Christoph Hellwig +Reviewed-by: Sagi Grimberg +Reviewed-by: Hannes Reinecke +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 303898e904c70..04222e6bd6d84 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1437,18 +1437,32 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) + { + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; +- unsigned int noreclaim_flag; ++ unsigned int noio_flag; + + if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) + return; + + page_frag_cache_drain(&queue->pf_cache); + +- noreclaim_flag = memalloc_noreclaim_save(); +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /** ++ * Prevent memory reclaim from triggering block I/O during socket ++ * teardown. The socket release path fput -> tcp_close -> ++ * tcp_disconnect -> tcp_send_active_reset may allocate memory, and ++ * allowing reclaim to issue I/O could deadlock if we're being called ++ * from block device teardown (e.g., del_gendisk -> elevator cleanup) ++ * which holds locks that the I/O completion path needs. ++ */ ++ noio_flag = memalloc_noio_save(); ++ ++ /** ++ * Release the socket synchronously. During reset in ++ * nvme_reset_ctrl_work(), queue teardown is immediately followed by ++ * re-allocation. fput() defers socket cleanup to delayed_fput_work ++ * in workqueue context, which can race with new queue setup. ++ */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; +- memalloc_noreclaim_restore(noreclaim_flag); ++ memalloc_noio_restore(noio_flag); + + kfree(queue->pdu); + mutex_destroy(&queue->send_mutex); +@@ -1900,8 +1914,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, + err_rcv_pdu: + kfree(queue->pdu); + err_sock: +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /* Use sync variant - see nvme_tcp_free_queue() for explanation */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; + err_destroy_mutex: + mutex_destroy(&queue->send_mutex); +-- +2.53.0 + diff --git a/queue-6.18/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch b/queue-6.18/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch new file mode 100644 index 0000000000..5c3e3582d0 --- /dev/null +++ b/queue-6.18/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch @@ -0,0 +1,48 @@ +From 03360eab465adc5f8f802d404872fb98f3d61838 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:56:58 -0400 +Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error + path + +From: Shivam Kumar + +[ Upstream commit 4606467a75cfc16721937272ed29462a750b60c8 ] + +In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, +nvmet_req_uninit() is called unconditionally. However, if the command +arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() +had returned false and percpu_ref_tryget_live() was never executed. The +unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a +refcount underflow, leading to a WARNING in +percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and +eventually a permanent workqueue deadlock. + +Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling +nvmet_req_uninit(), matching the existing pattern in +nvmet_tcp_execute_request(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Shivam Kumar +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 97d8c1d3545b0..d90f8b55b5934 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1344,7 +1344,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + queue->idx, cmd->req.cmd->common.command_id, + queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), + le32_to_cpu(cmd->exp_ddgst)); +- nvmet_req_uninit(&cmd->req); ++ if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) ++ nvmet_req_uninit(&cmd->req); + nvmet_tcp_free_cmd_buffers(cmd); + nvmet_tcp_fatal_error(queue); + ret = -EPROTO; +-- +2.53.0 + diff --git a/queue-6.18/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch b/queue-6.18/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch new file mode 100644 index 0000000000..57a141ac04 --- /dev/null +++ b/queue-6.18/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch @@ -0,0 +1,48 @@ +From 38ba20c16ddc22ef235a822991bf298a32c35e14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 10:48:09 +1000 +Subject: nvmet-tcp: Don't clear tls_key when freeing sq + +From: Alistair Francis + +[ Upstream commit 5fc422951c962cc01e654950fc043ebd8fadd865 ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +A previous attempt to fix this involed not calling nvmet_auth_sq_free() +on successful connections, but that results in memory leaks. Instead we +should not clear `tls_key` in nvmet_auth_sq_free(), as that was +incorrectly wiping the tls keys which are used for the session. + +This patch ensures we correctly free the ephemeral session key on +connection, yet we don't free the TLS key unless closing the connection. + +Reviewed-by: Chris Leech +Reviewed-by: Hannes Reinecke +Signed-off-by: Alistair Francis +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/auth.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c +index 300d5e032f6d4..51184388da08d 100644 +--- a/drivers/nvme/target/auth.c ++++ b/drivers/nvme/target/auth.c +@@ -239,9 +239,6 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq) + void nvmet_auth_sq_free(struct nvmet_sq *sq) + { + cancel_delayed_work(&sq->auth_expired_work); +-#ifdef CONFIG_NVME_TARGET_TCP_TLS +- sq->tls_key = NULL; +-#endif + kfree(sq->dhchap_c1); + sq->dhchap_c1 = NULL; + kfree(sq->dhchap_c2); +-- +2.53.0 + diff --git a/queue-6.18/nvmet-tcp-don-t-free-sq-on-authentication-success.patch b/queue-6.18/nvmet-tcp-don-t-free-sq-on-authentication-success.patch new file mode 100644 index 0000000000..dd6817a20d --- /dev/null +++ b/queue-6.18/nvmet-tcp-don-t-free-sq-on-authentication-success.patch @@ -0,0 +1,59 @@ +From 0986e11f368cb296d5bd382c3fdb45da5df2e168 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 15:17:53 +1000 +Subject: nvmet-tcp: Don't free SQ on authentication success + +From: Alistair Francis + +[ Upstream commit 2e6eb6b277f593b98f151ea8eff1beb558bbea3b ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +This patch ensures we don't free the TLS key on success as we might need +it again in the future. + +Signed-off-by: Alistair Francis +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Wilfred Mallawa +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/fabrics-cmd-auth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c +index 5946681cb0e32..96c85579150dd 100644 +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -396,9 +396,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) + goto complete; + } + /* Final states, clear up variables */ +- nvmet_auth_sq_free(req->sq); +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { ++ nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); ++ } + + complete: + nvmet_req_complete(req, status); +@@ -574,9 +575,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) + status = nvmet_copy_to_sgl(req, 0, d, al); + kfree(d); + done: +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) +- nvmet_auth_sq_free(req->sq); +- else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { + nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); + } +-- +2.53.0 + diff --git a/queue-6.18/objtool-support-clang-rax-drap-sequence.patch b/queue-6.18/objtool-support-clang-rax-drap-sequence.patch new file mode 100644 index 0000000000..e81ec54893 --- /dev/null +++ b/queue-6.18/objtool-support-clang-rax-drap-sequence.patch @@ -0,0 +1,113 @@ +From 32d7f91a14fec6b11967ec3a110f759218499a61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 17:47:56 -0700 +Subject: objtool: Support Clang RAX DRAP sequence + +From: Josh Poimboeuf + +[ Upstream commit 96f3b16a9de552538b810f773645d43f3b661b50 ] + +Recent Clang can use RAX as a temporary register for the DRAP stack +alignment sequence. Add support for that. + +Fixes the following warning: + + vmlinux.o: error: objtool: vmw_host_printf+0xd: unknown CFA base reg 0 + +Closes: https://lore.kernel.org/cefefdd1-7b82-406d-8ff4-e4b167e45ee6@app.fastmail.com +Reported-by: Arnd Bergmann +Signed-off-by: Josh Poimboeuf +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/3f33dc720b83dc6d3a2b7094f75a5c90a0b1cbc5.1773708458.git.jpoimboe@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/orc_types.h | 1 + + arch/x86/kernel/unwind_orc.c | 8 ++++++++ + tools/arch/x86/include/asm/orc_types.h | 1 + + tools/objtool/arch/x86/decode.c | 3 +++ + tools/objtool/arch/x86/orc.c | 5 +++++ + 5 files changed, 18 insertions(+) + +diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h +index e0125afa53fb9..b3cc7970fa548 100644 +--- a/arch/x86/include/asm/orc_types.h ++++ b/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c +index 977ee75e047c8..8b40f99623643 100644 +--- a/arch/x86/kernel/unwind_orc.c ++++ b/arch/x86/kernel/unwind_orc.c +@@ -563,6 +563,14 @@ bool unwind_next_frame(struct unwind_state *state) + } + break; + ++ case ORC_REG_AX: ++ if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) { ++ orc_warn_current("missing AX value at %pB\n", ++ (void *)state->ip); ++ goto err; ++ } ++ break; ++ + default: + orc_warn("unknown SP base reg %d at %pB\n", + orc->sp_reg, (void *)state->ip); +diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h +index e0125afa53fb9..b3cc7970fa548 100644 +--- a/tools/arch/x86/include/asm/orc_types.h ++++ b/tools/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c +index fdaddc636e977..ef5f154338f14 100644 +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -826,6 +826,9 @@ int arch_decode_hint_reg(u8 sp_reg, int *base) + case ORC_REG_DX: + *base = CFI_DX; + break; ++ case ORC_REG_AX: ++ *base = CFI_AX; ++ break; + default: + return -1; + } +diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c +index 7176b9ec5b058..5b66b18f4ac74 100644 +--- a/tools/objtool/arch/x86/orc.c ++++ b/tools/objtool/arch/x86/orc.c +@@ -71,6 +71,9 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct + case CFI_DX: + orc->sp_reg = ORC_REG_DX; + break; ++ case CFI_AX: ++ orc->sp_reg = ORC_REG_AX; ++ break; + default: + ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); + return -1; +@@ -139,6 +142,8 @@ static const char *reg_name(unsigned int reg) + return "bp(ind)"; + case ORC_REG_SP_INDIRECT: + return "sp(ind)"; ++ case ORC_REG_AX: ++ return "ax"; + default: + return "?"; + } +-- +2.53.0 + diff --git a/queue-6.18/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch b/queue-6.18/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch new file mode 100644 index 0000000000..4b3eb1b996 --- /dev/null +++ b/queue-6.18/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch @@ -0,0 +1,48 @@ +From 4940232eab6e3c7efac74350f65f5c1865f0f81a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 02:08:06 +0000 +Subject: orangefs: add usercopy whitelist to orangefs_op_cache + +From: Ziyi Guo + +[ Upstream commit f855f4ab123b2b9c93465288c03fbb07a5903bb3 ] + +orangefs_op_cache is created with kmem_cache_create(), which provides +no usercopy whitelist. orangefs_devreq_read() copies the tag and upcall +fields directly from slab objects to userspace via copy_to_user(). With +CONFIG_HARDENED_USERCOPY enabled, this triggers usercopy_abort(). + +Switch to kmem_cache_create_usercopy() with a whitelist covering the +tag and upcall fields, matching the pattern already used by +orangefs_inode_cache in super.c. + +Signed-off-by: Ziyi Guo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/orangefs-cache.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c +index e75e173a91862..0bdb99e897447 100644 +--- a/fs/orangefs/orangefs-cache.c ++++ b/fs/orangefs/orangefs-cache.c +@@ -19,10 +19,14 @@ static struct kmem_cache *op_cache; + + int op_cache_initialize(void) + { +- op_cache = kmem_cache_create("orangefs_op_cache", ++ op_cache = kmem_cache_create_usercopy("orangefs_op_cache", + sizeof(struct orangefs_kernel_op_s), + 0, + 0, ++ offsetof(struct orangefs_kernel_op_s, tag), ++ offsetof(struct orangefs_kernel_op_s, upcall) + ++ sizeof(struct orangefs_upcall_s) - ++ offsetof(struct orangefs_kernel_op_s, tag), + NULL); + + if (!op_cache) { +-- +2.53.0 + diff --git a/queue-6.18/orangefs-validate-getxattr-response-length.patch b/queue-6.18/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..73cbd12138 --- /dev/null +++ b/queue-6.18/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From 0b105294c2789c9194cfab93f4fd27baa23d2652 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index eee3c5ed1bbbb..2366770c2b750 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-6.18/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch b/queue-6.18/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch new file mode 100644 index 0000000000..9f5d5c7ab0 --- /dev/null +++ b/queue-6.18/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch @@ -0,0 +1,78 @@ +From 75a5fbf5a5d8bd22d89e94eee1518a33995bbc36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 18:07:25 -0400 +Subject: orangefs_readahead: don't overflow the bufmap slot. + +From: Mike Marshall + +[ Upstream commit 415e507cdefc510c01de8ab6644163327ee9a5d0 ] + +generic/340 showed that this caller of wait_for_direct_io was +sometimes asking for more than a bufmap slot could hold. This splits +the calls up if needed. + +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/inode.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index a01400cd41fdf..5e7d65e2d34c0 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -224,6 +224,8 @@ static void orangefs_readahead(struct readahead_control *rac) + loff_t new_start = readahead_pos(rac); + int ret; + size_t new_len = 0; ++ size_t this_size; ++ size_t remaining; + + loff_t bytes_remaining = inode->i_size - readahead_pos(rac); + loff_t pages_remaining = bytes_remaining / PAGE_SIZE; +@@ -239,17 +241,33 @@ static void orangefs_readahead(struct readahead_control *rac) + offset = readahead_pos(rac); + i_pages = &rac->mapping->i_pages; + +- iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); ++ iov_iter_xarray(&iter, ITER_DEST, i_pages, ++ offset, readahead_length(rac)); + +- /* read in the pages. */ +- if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, +- &offset, &iter, readahead_length(rac), +- inode->i_size, NULL, NULL, rac->file)) < 0) +- gossip_debug(GOSSIP_FILE_DEBUG, +- "%s: wait_for_direct_io failed. \n", __func__); +- else +- ret = 0; ++ remaining = readahead_length(rac); ++ while (remaining) { ++ if (remaining > 4194304) ++ this_size = 4194304; ++ else ++ this_size = remaining; ++ ++ /* read in the pages. */ ++ if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, ++ &offset, &iter, this_size, ++ inode->i_size, NULL, NULL, rac->file)) < 0) { ++ gossip_debug(GOSSIP_FILE_DEBUG, ++ "%s: wait_for_direct_io failed. :%d: \n", ++ __func__, ret); ++ goto cleanup; ++ } else { ++ ret = 0; ++ } ++ ++ remaining -= this_size; ++ offset += this_size; ++ } + ++cleanup: + /* clean up. */ + while ((folio = readahead_folio(rac))) { + if (!ret) +-- +2.53.0 + diff --git a/queue-6.18/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-6.18/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..b064ba8edd --- /dev/null +++ b/queue-6.18/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From 7b392324243c86a4b478b39dc6cdb1f819302791 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index f59baa9129709..d80346d567049 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -79,7 +79,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index 50fb3eb595fe6..9eea9c80cfaad 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -42,6 +42,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -73,7 +82,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -166,7 +176,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -188,7 +199,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -222,6 +234,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -285,7 +307,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 89f5a4290b6e2..ce82373c7eb6e 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -72,12 +72,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-6.18/pci-avoid-flr-for-amd-npu-device.patch b/queue-6.18/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..e3ed3b7c4f --- /dev/null +++ b/queue-6.18/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From 6ab787354739565cf2052cb285642699c424be56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index d32a47e81fcf3..54f61e6231a0f 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5576,6 +5576,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * Mediatek MT7922 802.11ax PCI Express Wireless Network Adapter +@@ -5588,6 +5589,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MEDIATEK, 0x0616, quirk_no_flr); +-- +2.53.0 + diff --git a/queue-6.18/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch b/queue-6.18/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch new file mode 100644 index 0000000000..43482a545f --- /dev/null +++ b/queue-6.18/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch @@ -0,0 +1,42 @@ +From 6a706f47c8888e8d4a1bd1ee766808e03edf007e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 14:52:11 -0500 +Subject: PCI/DPC: Hold pci_dev reference during error recovery + +From: Sizhe Liu + +[ Upstream commit a1ed752bc7cb77b740cee671567d9508ae74becd ] + +The AER and EDR error handling paths hold a reference on the pci_dev during +recovery. Hold a reference during the DPC recovery path as well. + +Signed-off-by: Sizhe Liu +[bhelgaas: split to separate patch] +Signed-off-by: Bjorn Helgaas +https://patch.msgid.link/20260214081130.1878424-1-liusizhe5@huawei.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/dpc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index 7605ddd9f0ba8..2b779bd1d861b 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -373,11 +373,13 @@ static irqreturn_t dpc_handler(int irq, void *context) + return IRQ_HANDLED; + } + ++ pci_dev_get(pdev); + dpc_process_error(pdev); + + /* We configure DPC so it only triggers on ERR_FATAL */ + pcie_do_recovery(pdev, pci_channel_io_frozen, dpc_reset_link); + ++ pci_dev_put(pdev); + return IRQ_HANDLED; + } + +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch b/queue-6.18/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch new file mode 100644 index 0000000000..264c98aad6 --- /dev/null +++ b/queue-6.18/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch @@ -0,0 +1,52 @@ +From ba23b730c6cc756a5894a98335d37da3abddc78c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:01:42 +0530 +Subject: PCI: dwc: Proceed with system suspend even if the endpoint doesn't + respond with PME_TO_Ack message + +From: Manivannan Sadhasivam + +[ Upstream commit eed390775470ff0db32cce37a681f3acc2b941c3 ] + +PCIe spec r7.0, sec 5.3.3.2.1, recommends proceeding with L2/L3 sequence +even if one or devices do not respond with PME_TO_Ack message after 10ms +timeout. + +So just print a warning if the timeout happens and proceed with the system +suspend. + +Reported-by: Neil Armstrong +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Tested-by: Neil Armstrong # on SM8650-HDK +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260217113142.9140-1-manivannan.sadhasivam@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 48e4a887bb1bb..16411364ddcc0 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1186,9 +1186,13 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) + PCIE_PME_TO_L2_TIMEOUT_US/10, + PCIE_PME_TO_L2_TIMEOUT_US, false, pci); + if (ret) { +- /* Only log message when LTSSM isn't in DETECT or POLL */ +- dev_err(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val); +- return ret; ++ /* ++ * Failure is non-fatal since spec r7.0, sec 5.3.3.2.1, ++ * recommends proceeding with L2/L3 sequence even if one or more ++ * devices do not respond with PME_TO_Ack after 10ms timeout. ++ */ ++ dev_warn(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val); ++ ret = 0; + } + + /* +-- +2.53.0 + diff --git a/queue-6.18/pci-prevent-assignment-to-unsupported-bridge-windows.patch b/queue-6.18/pci-prevent-assignment-to-unsupported-bridge-windows.patch new file mode 100644 index 0000000000..fad307e515 --- /dev/null +++ b/queue-6.18/pci-prevent-assignment-to-unsupported-bridge-windows.patch @@ -0,0 +1,76 @@ +From dcb68083f584b3bcc867a7c672d19c3a305893a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:53:32 +0000 +Subject: PCI: Prevent assignment to unsupported bridge windows + +From: Ahmed Naseef + +[ Upstream commit 92427ab4378faa168d6953d0f8574b8fc1edcc14 ] + +Previously, pci_read_bridge_io() and pci_read_bridge_mmio_pref() +unconditionally set resource type flags (IORESOURCE_IO or IORESOURCE_MEM | +IORESOURCE_PREFETCH) when reading bridge window registers. For windows that +are not implemented in hardware, this may cause the allocator to assign +space for a window that doesn't exist. + +For example, the EcoNET EN7528 SoC Root Port doesn't support the +prefetchable window, but since a downstream device had a prefetchable BAR, +the allocator mistakenly assigned a prefetchable window: + + pci 0001:00:01.0: [14c3:0811] type 01 class 0x060400 PCIe Root Port + pci 0001:00:01.0: PCI bridge to [bus 01-ff] + pci 0001:00:01.0: bridge window [mem 0x28000000-0x280fffff]: assigned + pci 0001:00:01.0: bridge window [mem 0x28100000-0x282fffff pref]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28100000-0x281fffff 64bit pref]: assigned + +pci_read_bridge_windows() already detects unsupported windows by testing +register writability and sets dev->io_window/pref_window accordingly. + +Check dev->io_window/pref_window so we don't set the resource flags for +unsupported windows, which prevents the allocator from assigning space to +them. + +After this commit, the prefetchable BAR is correctly allocated from the +non-prefetchable window: + + pci 0001:00:01.0: bridge window [mem 0x28000000-0x281fffff]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28000000-0x280fffff 64bit pref]: assigned + +Suggested-by: Bjorn Helgaas +Link: https://lore.kernel.org/all/20260113210259.GA715789@bhelgaas/ +Signed-off-by: Ahmed Naseef +Signed-off-by: Caleb James DeLisle +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260312165332.569772-4-cjd@cjdns.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 4e4e38e626912..c5f061923a504 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -396,6 +396,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; + ++ if (!dev->io_window) ++ return; ++ + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; + if (dev->io_window_1k) { +@@ -466,6 +469,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, + pci_bus_addr_t base, limit; + struct pci_bus_region region; + ++ if (!dev->pref_window) ++ return; ++ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-6.18/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..5cedbb5a18 --- /dev/null +++ b/queue-6.18/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From 8df33a44737c314e4b52e8b3d4aa2118f17f3c90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index fdbf440fb3819..3297893446648 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -44,6 +44,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1429,6 +1430,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-6.18/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-6.18/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..2ca5274986 --- /dev/null +++ b/queue-6.18/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 298ec5e7c4ab3045b503612288c7d024b0d7d9a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/pci/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c +index baa242b140993..c3a90088765ea 100644 +--- a/drivers/pci/vgaarb.c ++++ b/drivers/pci/vgaarb.c +@@ -1134,6 +1134,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1165,7 +1166,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-6.18/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-6.18/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..a2f646d0b9 --- /dev/null +++ b/queue-6.18/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From 54c45cd64ba43f37c27f3fd051efd3ddc2c6112d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 9f026bf6390e2..8e67fc19b6395 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -493,6 +493,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-6.18/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch b/queue-6.18/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch new file mode 100644 index 0000000000..8bee6baa06 --- /dev/null +++ b/queue-6.18/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch @@ -0,0 +1,48 @@ +From 852b2b5dd936090aab565c4a8f94ea3098a5d709 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:13 +0000 +Subject: perf/amd/ibs: Limit ldlat->l3missonly dependency to Zen5 + +From: Ravi Bangoria + +[ Upstream commit 898138efc99096c3ee836fea439ba6da3cfafa4d ] + +The ldlat dependency on l3missonly is specific to Zen 5; newer generations +are not affected. This quirk is documented as an erratum in the following +Revision Guide. + + Erratum: 1606 IBS (Instruction Based Sampling) OP Load Latency Filtering + May Capture Unwanted Samples When L3Miss Filtering is Disabled + + Revision Guide for AMD Family 1Ah Models 00h-0Fh Processors, + Pub. 58251 Rev. 1.30 July 2025 + https://bugzilla.kernel.org/attachment.cgi?id=309193 + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-3-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 56918cd91115c..9f026bf6390e2 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -359,7 +359,10 @@ static int perf_ibs_init(struct perf_event *event) + ldlat >>= 7; + + config |= (ldlat - 1) << 59; +- config |= IBS_OP_L3MISSONLY | IBS_OP_LDLAT_EN; ++ ++ config |= IBS_OP_LDLAT_EN; ++ if (cpu_feature_enabled(X86_FEATURE_ZEN5)) ++ config |= IBS_OP_L3MISSONLY; + } + + /* +-- +2.53.0 + diff --git a/queue-6.18/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch b/queue-6.18/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch new file mode 100644 index 0000000000..cf3188120d --- /dev/null +++ b/queue-6.18/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch @@ -0,0 +1,46 @@ +From e191f4ff9d3efaa60f7eb287d001530fc0b0b9ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:40:32 +0530 +Subject: phy: phy-mtk-tphy: Update names and format of kernel-doc comments + +From: Vinod Koul + +[ Upstream commit 8d869bc943cfe5db08f5aff355b1d8d3abeda865 ] + +mtk_phy_pdata documentation does not use correct tag for struct, while at +it fix one of member wrongly documented. + +Warning: drivers/phy/mediatek/phy-mtk-tphy.c:289 cannot understand function prototype: 'struct mtk_phy_pdata' +Warning: drivers/phy/mediatek/phy-mtk-tphy.c:296 struct member 'slew_ref_clock_mhz' not described in 'mtk_phy_pdata' + +Link: https://patch.msgid.link/20260223071032.408425-1-vkoul@kernel.org +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/mediatek/phy-mtk-tphy.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c +index f6504e0ecd1a7..acf5065295072 100644 +--- a/drivers/phy/mediatek/phy-mtk-tphy.c ++++ b/drivers/phy/mediatek/phy-mtk-tphy.c +@@ -276,14 +276,14 @@ enum mtk_phy_version { + }; + + /** +- * mtk_phy_pdata - SoC specific platform data ++ * struct mtk_phy_pdata - SoC specific platform data + * @avoid_rx_sen_degradation: Avoid TX Sensitivity level degradation (MT6795/8173 only) + * @sw_pll_48m_to_26m: Workaround for V3 IP (MT8195) - switch the 48MHz PLL from + * fractional mode to integer to output 26MHz for U2PHY + * @sw_efuse_supported: Switches off eFuse auto-load from PHY and applies values + * read from different nvmem (usually different eFuse array) + * that is pointed at in the device tree node for this PHY +- * @slew_ref_clk_mhz: Default reference clock (in MHz) for slew rate calibration ++ * @slew_ref_clock_mhz: Default reference clock (in MHz) for slew rate calibration + * @slew_rate_coefficient: Coefficient for slew rate calibration + * @version: PHY IP Version + */ +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-6.18/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..a7b584c0be --- /dev/null +++ b/queue-6.18/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From b55ba1749f7ffb62395fd7ceca97001828c25887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 2dac5c71eb008..1b09697f8830e 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1276,6 +1276,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-realtek-fix-return-value-and-silence-log-for.patch b/queue-6.18/pinctrl-realtek-fix-return-value-and-silence-log-for.patch new file mode 100644 index 0000000000..5510ad284b --- /dev/null +++ b/queue-6.18/pinctrl-realtek-fix-return-value-and-silence-log-for.patch @@ -0,0 +1,47 @@ +From 90de2b08b032feb1d179e97c0572d8f5dcc41919 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:52:32 +0800 +Subject: pinctrl: realtek: Fix return value and silence log for unsupported + configs + +From: Tzuyi Chang + +[ Upstream commit 6a6b238c66dc69cd784baf03b170c50f7e5f24d9 ] + +Treating unsupported configurations as errors causes upper layers (like the +GPIO subsystem) to interpret optional features as hard failures, aborting +operations or printing unnecessary error logs. + +For example, during gpiod_get(), the GPIO framework attempts to set +PIN_CONFIG_PERSIST_STATE. Since this driver does not support it, false +error reports are generated in dmesg. + +Fix this by returning -ENOTSUPP and demoting the log level to dev_dbg. + +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Tzuyi Chang +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 4c876d1f6ad59..9633d3deaa6f3 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -456,8 +456,8 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + break; + + default: +- dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param); +- return -EINVAL; ++ dev_dbg(data->dev, "unsupported pinconf: %d\n", (u32)param); ++ return -ENOTSUPP; + } + + ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val); +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch b/queue-6.18/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch new file mode 100644 index 0000000000..4fd21a2ac3 --- /dev/null +++ b/queue-6.18/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch @@ -0,0 +1,52 @@ +From 9c793aa617331075e2682bb4e286286d221645fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:40:39 +0530 +Subject: platform/x86: hp-wmi: Add support for Omen 16-wf1xxx (8C77) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Krishna Chomal + +[ Upstream commit 344bf523d441d44c75c429ea6cdcfa8f12efde4d ] + +The HP Omen 16-wf1xxx (board ID: 8C77) has the same WMI interface as +other Victus S boards, but requires quirks for correctly switching +thermal profile. + +Add the DMI board name to victus_s_thermal_profile_boards[] table and +map it to omen_v1_thermal_params. + +Testing on board 8C77 confirmed that platform profile is registered +successfully and fan RPMs are readable and controllable. + +Tested-by: Thomas Arici +Reported-by: Thomas Arici +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221300 +Signed-off-by: Krishna Chomal +Link: https://patch.msgid.link/20260410191039.125659-5-krishna.chomal108@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 550d4b39a92af..2b0adb97d3d2e 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -178,6 +178,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") }, + .driver_data = (void *)&omen_v1_thermal_params, + }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C77") }, ++ .driver_data = (void *)&omen_v1_thermal_params, ++ }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, + .driver_data = (void *)&omen_v1_thermal_params, +-- +2.53.0 + diff --git a/queue-6.18/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-6.18/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..ac699f0ce2 --- /dev/null +++ b/queue-6.18/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From c1293c43ee3deb27dde95d1862cbe3f2a8154039 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 6fe526222f7f4..343ad4ab4082c 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-6.18/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch b/queue-6.18/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch new file mode 100644 index 0000000000..eca8d67a13 --- /dev/null +++ b/queue-6.18/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch @@ -0,0 +1,80 @@ +From deb8a9a024b425ae13b562c300f71be40697af7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 23:44:26 +0530 +Subject: powerpc/64s: Fix _HPAGE_CHG_MASK to include _PAGE_SPECIAL bit + +From: Ritesh Harjani (IBM) + +[ Upstream commit 68b1fa0ed5c84769e4e60d58f6a5af37e7273b51 ] + +commit af38538801c6a ("mm/memory: factor out common code from vm_normal_page_*()"), +added a VM_WARN_ON_ONCE for huge zero pfn. + +This can lead to the following call stack. + + ------------[ cut here ]------------ + WARNING: mm/memory.c:735 at vm_normal_page_pmd+0xf0/0x140, CPU#19: hmm-tests/3366 + NIP [c00000000078d0c0] vm_normal_page_pmd+0xf0/0x140 + LR [c00000000078d060] vm_normal_page_pmd+0x90/0x140 + Call Trace: + [c00000016f56f850] [c00000000078d060] vm_normal_page_pmd+0x90/0x140 (unreliable) + [c00000016f56f8a0] [c0000000008a9e30] change_huge_pmd+0x7c0/0x870 + [c00000016f56f930] [c0000000007b2bc4] change_protection+0x17a4/0x1e10 + [c00000016f56fba0] [c0000000007b3440] mprotect_fixup+0x210/0x4c0 + [c00000016f56fc30] [c0000000007b3c3c] do_mprotect_pkey+0x54c/0x780 + [c00000016f56fdb0] [c0000000007b3ed8] sys_mprotect+0x68/0x90 + [c00000016f56fdf0] [c00000000003ae40] system_call_exception+0x190/0x500 + [c00000016f56fe50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec + +This happens when we call mprotect -> change_huge_pmd() +mprotect() + change_pmd_range() + pmd_modify(oldpmd, newprot) # this clears _PAGE_SPECIAL for zero huge pmd + pmdv = pmd_val(pmd); + pmdv &= _HPAGE_CHG_MASK; # -> gets cleared here + return pmd_set_protbits(__pmd(pmdv), newprot); + can_change_pmd_writable(vma, vmf->address, pmd) + vm_normal_page_pmd(vma, addr, pmd) + __vm_normal_page() + VM_WARN_ON(is_zero_pfn(pfn) || is_huge_zero_pfn(pfn)); # this get hits as _PAGE_SPECIAL for zero huge pmd was cleared. + +It can be easily reproduced with the following testcase: + p = mmap(NULL, 2 * hpage_pmd_size, PROT_READ, MAP_PRIVATE | + MAP_ANONYMOUS, -1, 0); + madvise((void *)p, 2 * hpage_pmd_size, MADV_HUGEPAGE); + aligned = (char*)(((unsigned long)p + hpage_pmd_size - 1) & + ~(hpage_pmd_size - 1)); + (void)(*(volatile char*)aligned); // read fault, installs huge zero PMD + mprotect((void *)aligned, hpage_pmd_size, PROT_READ | PROT_WRITE); + +This patch adds _PAGE_SPECIAL to _HPAGE_CHG_MASK similar to +_PAGE_CHG_MASK, as we don't want to clear this bit when calling +pmd_modify() while changing protection bits. + +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/7416f5cdbcfeaad947860fcac488b483f1287172.1773078178.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/book3s/64/pgtable.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h +index aac8ce30cd3b3..8d1a3875b7b40 100644 +--- a/arch/powerpc/include/asm/book3s/64/pgtable.h ++++ b/arch/powerpc/include/asm/book3s/64/pgtable.h +@@ -107,8 +107,8 @@ + * in here, on radix we expect them to be zero. + */ + #define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \ +- _PAGE_ACCESSED | H_PAGE_THP_HUGE | _PAGE_PTE | \ +- _PAGE_SOFT_DIRTY) ++ _PAGE_ACCESSED | H_PAGE_THP_HUGE | _PAGE_SPECIAL | \ ++ _PAGE_PTE | _PAGE_SOFT_DIRTY) + /* + * user access blocked by key + */ +-- +2.53.0 + diff --git a/queue-6.18/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch b/queue-6.18/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch new file mode 100644 index 0000000000..b7da70c086 --- /dev/null +++ b/queue-6.18/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch @@ -0,0 +1,48 @@ +From d08042d6f401581dae1f5c153be32b0671a5fcc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Nov 2025 19:55:44 +0530 +Subject: powerpc: 82xx: fix uninitialized pointers with free attribute + +From: Ally Heev + +[ Upstream commit acd1e47db03d4b528fd5efb8565dd0de1c79f62a ] + +Uninitialized pointers with `__free` attribute can cause undefined +behavior as the memory allocated to the pointer is freed automatically +when the pointer goes out of scope. + +powerpc/km82xx doesn't have any bugs related to this as of now, but, +it is better to initialize and assign pointers with `__free` attribute +in one statement to ensure proper scope-based cleanup + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/all/aPiG_F5EBQUjZqsl@stanley.mountain/ +Signed-off-by: Ally Heev +Fixes: 4aa5cc1e0012 ("powerpc-km82xx.c: replace of_node_put() with __free") +Reviewed-by: Christophe Leroy (CS GROUP) +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251116-aheev-uninitialized-free-attr-km82xx-v2-1-4307e2b5300d@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/platforms/82xx/km82xx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c +index 99f0f0f418767..4ad223525e893 100644 +--- a/arch/powerpc/platforms/82xx/km82xx.c ++++ b/arch/powerpc/platforms/82xx/km82xx.c +@@ -27,8 +27,8 @@ + + static void __init km82xx_pic_init(void) + { +- struct device_node *np __free(device_node); +- np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); ++ struct device_node *np __free(device_node) = of_find_compatible_node(NULL, ++ NULL, "fsl,pq2-pic"); + + if (!np) { + pr_err("PIC init: can not find cpm-pic node\n"); +-- +2.53.0 + diff --git a/queue-6.18/powerpc-fix-dead-default-for-guest_state_buffer_test.patch b/queue-6.18/powerpc-fix-dead-default-for-guest_state_buffer_test.patch new file mode 100644 index 0000000000..f749af56a4 --- /dev/null +++ b/queue-6.18/powerpc-fix-dead-default-for-guest_state_buffer_test.patch @@ -0,0 +1,54 @@ +From 6a8eddda527776733da4055ecd485b49adae45b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 17:15:45 +0100 +Subject: powerpc: fix dead default for GUEST_STATE_BUFFER_TEST + +From: Julian Braha + +[ Upstream commit aef656a0e6c01796190bb5bd2bdba1c644ed7811 ] + +The GUEST_STATE_BUFFER_TEST config option should default +to KUNIT_ALL_TESTS so that if all tests are enabled then +it is included, but currently the 'default KUNIT_ALL_TESTS' +statement is shadowed by 'def_tristate n', +meaning that this second default statement is currently dead code. + +It looks to me like the commit +6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +intended to set the default to KUNIT_ALL_TESTS, but mistakenly +missed the def_tristate. + +This dead code was found by kconfirm, a static analysis tool for Kconfig. + +Fixes: 6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +Signed-off-by: Julian Braha +Tested-by: Gautam Menghani +Reviewed-by: Amit Machhiwal +Reviewed-by: Harsh Prateek Bora +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260405161545.161006-1-julianbraha@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/Kconfig.debug | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug +index f15e5920080ba..e8718bc13eeb1 100644 +--- a/arch/powerpc/Kconfig.debug ++++ b/arch/powerpc/Kconfig.debug +@@ -83,11 +83,10 @@ config MSI_BITMAP_SELFTEST + depends on DEBUG_KERNEL + + config GUEST_STATE_BUFFER_TEST +- def_tristate n ++ def_tristate KUNIT_ALL_TESTS + prompt "Enable Guest State Buffer unit tests" + depends on KUNIT + depends on KVM_BOOK3S_HV_POSSIBLE +- default KUNIT_ALL_TESTS + help + The Guest State Buffer is a data format specified in the PAPR. + It is by hcalls to communicate the state of L2 guests between +-- +2.53.0 + diff --git a/queue-6.18/powerpc-time-remove-redundant-preempt_disable-enable.patch b/queue-6.18/powerpc-time-remove-redundant-preempt_disable-enable.patch new file mode 100644 index 0000000000..25bc0177dd --- /dev/null +++ b/queue-6.18/powerpc-time-remove-redundant-preempt_disable-enable.patch @@ -0,0 +1,98 @@ +From 08a5473a07f14e88f82c1958b0f1e7beb2912d7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:13 +0530 +Subject: powerpc/time: Remove redundant preempt_disable|enable() calls from + arch_irq_work_raise() + +From: Sayali Patil + +[ Upstream commit 31467b23823ffec1f6fff407f8e3ca9af8b7491a ] + +A kernel panic is observed when handling machine check exceptions from +real mode. + + BUG: Unable to handle kernel data access on read at 0xc00000006be21300 + Oops: Kernel access of bad area, sig: 11 [#1] + MSR: 8000000000001003 CR: 88222248 XER: 00000005 + CFAR: c00000000003ffc4 DAR: c00000006be21300 DSISR: 40000000 IRQMASK: 0 + NIP [c000000000029e40] arch_irq_work_raise+0x10/0x70 + LR [c00000000003ffc8] machine_check_queue_event+0xa8/0x150 + Call Trace: + [c0000000179d3c70] [c00000000003ff64] machine_check_queue_event+0x44/0x150 + [c0000000179d3d30] [c0000000000084e0] machine_check_early_common+0x1f0/0x2c0 + +The crash occurs because arch_irq_work_raise() calls preempt_disable() +from machine check exception (MCE) handlers running in real mode. In +this context, accessing the preempt_count can fault, leading to the panic. + +The preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +was originally added by commit 0fe1ac48bef0 ("powerpc/perf_event: Fix +oops due to perf_event_do_pending call") to avoid races while raising +irq work from exception context. + +Later, commit 471ba0e686cb ("irq_work: Do not raise an IPI when +queueing work on the local CPU") added preemption protection in +irq_work_queue() path, while commit 20b876918c06 ("irq_work: Use per +cpu atomics instead of regular atomics") added equivalent +protection in irq_work_queue_on() before reaching arch_irq_work_raise(): + + irq_work_queue() / irq_work_queue_on() + -> preempt_disable() + -> __irq_work_queue_local() + -> irq_work_raise() + -> arch_irq_work_raise() + +As a result, callers other than mce_irq_work_raise() already execute +with preemption disabled, making the additional +preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +redundant. + +The arch_irq_work_raise() function executes in NMI context when called +from MCE handler. Hence we will not be preempted or scheduled out since +we are in NMI context with MSR[EE]=0. Therefore, it is safe to remove +the preempt_disable()/preempt_enable() calls from here. + +Remove it to avoid accessing preempt_count from real mode context. + +Fixes: cc15ff327569 ("powerpc/mce: Avoid using irq_work_queue() in realmode") +Suggested-by: Mahesh Salgaonkar +Acked-by: Shrikanth Hegde +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Sayali Patil +[Maddy: Fixed the commit title] +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260513081413.222490-1-sayalip@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/time.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index 4bbeb8644d3da..b4472288e0d43 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -458,6 +458,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); + + #endif /* 32 vs 64 bit */ + ++/* ++ * Must be called with preemption disabled since it updates ++ * per-CPU irq_work state and programs the local CPU decrementer. ++ */ + void arch_irq_work_raise(void) + { + /* +@@ -471,10 +475,8 @@ void arch_irq_work_raise(void) + * which could get tangled up if we're messing with the same state + * here. + */ +- preempt_disable(); + set_irq_work_pending_flag(); + set_dec(1); +- preempt_enable(); + } + + static void set_dec_or_work(u64 val) +-- +2.53.0 + diff --git a/queue-6.18/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-6.18/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..d1aee1f1c9 --- /dev/null +++ b/queue-6.18/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From 9d84838f9cdef51b566ff9a7f4ffbbb584d70cd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 507d216256c0d..98a75e2b5e2ae 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3006,12 +3006,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-6.18/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch b/queue-6.18/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch new file mode 100644 index 0000000000..67727cf824 --- /dev/null +++ b/queue-6.18/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch @@ -0,0 +1,69 @@ +From c3e02f8c4fdd25f72ee076caebff7d9790ac165a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 21:51:55 +0300 +Subject: pstore: fix ftrace dump, when ECC is enabled + +From: Andrey Skvortsov + +[ Upstream commit 4ef6255cc56343bc90d82420b49dab1b11dee414 ] + +total_size is sum of record->size and record->ecc_notice_size (ECC: No +errors detected). When ECC is not used, then there is no problem. +When ECC is enabled, then ftrace dump is decoded incorrectly after +restart. + +First this affects starting offset calculation, that breaks +reading of all ftrace records. + + CPU:66 ts:51646260179894273 3818ffff80008002 fe00ffff800080f0 0x3818ffff80008002 <- 0xfe00ffff800080f0 + CPU:66 ts:56589664458375169 3818ffff80008002 ff02ffff800080f0 0x3818ffff80008002 <- 0xff02ffff800080f0 + CPU:67 ts:13194139533313 afe4ffff80008002 1ffff800080f0 0xafe4ffff80008002 <- 0x1ffff800080f0 + CPU:67 ts:13194139533313 b7d0ffff80008001 100ffff80008002 0xb7d0ffff80008001 <- 0x100ffff80008002 + CPU:67 ts:51646260179894273 8de0ffff80008001 202ffff80008002 0x8de0ffff80008001 <- 0x202ffff80008002 + +Second ECC notice message is printed like ftrace record and as a +result couple of last records are completely wrong. + +For example, when the starting offset is fixed: + + CPU:0 ts:113 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:0 ts:114 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:100 ts:28259048229270629 6f4e203a4343450a 2073726f72726520 0x6f4e203a4343450a <- 0x2073726f72726520 + +Signed-off-by: Andrey Skvortsov +Tested-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260215185156.317394-1-andrej.skvortzov@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/inode.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index b4e55c90f8dc2..9c2d5e5f31d65 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -74,9 +74,9 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) + if (!data) + return NULL; + +- data->off = ps->total_size % REC_SIZE; ++ data->off = ps->record->size % REC_SIZE; + data->off += *pos * REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return_ptr(data); +@@ -94,7 +94,7 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos) + + (*pos)++; + data->off += REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return data; +-- +2.53.0 + diff --git a/queue-6.18/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-6.18/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..07fed2f012 --- /dev/null +++ b/queue-6.18/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 510b53865792b39bb6e573ac2181dce0dbf8c0c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index 2abba7552605c..e3bc442256922 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-6.18/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-6.18/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..e3915f08cd --- /dev/null +++ b/queue-6.18/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From 87f723052036b122b56afea27342328cbab2cf8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 8c8688f99f0ab..be7c7b71a1843 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -28,7 +28,6 @@ + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + #define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -80,7 +79,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -151,9 +150,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -161,6 +162,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-6.18/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch b/queue-6.18/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch new file mode 100644 index 0000000000..b45bc77df3 --- /dev/null +++ b/queue-6.18/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch @@ -0,0 +1,70 @@ +From 66fdcc7191a20c1e46355b9d98c981a5823a79e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 06:36:59 +0100 +Subject: ring-buffer: Enforce read ordering of trace_buffer cpumask and + buffers + +From: Vincent Donnefort + +[ Upstream commit 20ad8b0888be392eb2c4c3654805eb8594952373 ] + +On CPU hotplug, if it is the first time a trace_buffer sees a CPU, a +ring_buffer_per_cpu will be allocated and its corresponding bit toggled +in the cpumask. Many readers check this cpumask to know if they can +safely read the ring_buffer_per_cpu but they are doing so without memory +ordering and may observe the cpumask bit set while having NULL buffer +pointer. + +Enforce the memory read ordering by sending an IPI to all online CPUs. +The hotplug path is a slow-path anyway and it saves us from adding read +barriers in numerous call sites. + +Link: https://patch.msgid.link/20260401053659.3458961-1-vdonnefort@google.com +Signed-off-by: Vincent Donnefort +Suggested-by: Steven Rostedt (Google) +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/ring_buffer.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index a31fb4b7a52ea..97be62be3fdec 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -7442,6 +7442,12 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu) + return 0; + } + ++static void rb_cpu_sync(void *data) ++{ ++ /* Not really needed, but documents what is happening */ ++ smp_rmb(); ++} ++ + /* + * We only allocate new buffers, never free them if the CPU goes down. + * If we were to free the buffer, then the user would lose any trace that was in +@@ -7480,7 +7486,18 @@ int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node) + cpu); + return -ENOMEM; + } +- smp_wmb(); ++ ++ /* ++ * Ensure trace_buffer readers observe the newly allocated ++ * ring_buffer_per_cpu before they check the cpumask. Instead of using a ++ * read barrier for all readers, send an IPI. ++ */ ++ if (unlikely(system_state == SYSTEM_RUNNING)) { ++ on_each_cpu(rb_cpu_sync, NULL, 1); ++ /* Not really needed, but documents what is happening */ ++ smp_wmb(); ++ } ++ + cpumask_set_cpu(cpu, buffer->cpumask); + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch b/queue-6.18/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch new file mode 100644 index 0000000000..8cb0818194 --- /dev/null +++ b/queue-6.18/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch @@ -0,0 +1,45 @@ +From 81354a4a4c5b6bf9161003ebc161ba1308e82a24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 09:11:39 +0000 +Subject: riscv: errata: Fix bitwise vs logical AND in MIPS errata patching + +From: Michael Neuling + +[ Upstream commit 4d2b03699460b8fd5df34408a03a84a1a7ff8aa1 ] + +The condition checking whether a specific errata needs patching uses +logical AND (&&) instead of bitwise AND (&). Since logical AND only +checks that both operands are non-zero, this causes all errata patches +to be applied whenever any single errata is detected, rather than only +applying the matching one. + +The SiFive errata implementation correctly uses bitwise AND for the same +check. + +Fixes: 0b0ca959d206 ("riscv: errata: Fix the PAUSE Opcode for MIPS P8700") +Signed-off-by: Michael Neuling +Assisted-by: Cursor:claude-4.6-opus-high-thinking +Link: https://patch.msgid.link/20260409091143.1348853-2-mikey@neuling.org +[pjw@kernel.org: fixed checkpatch warning] +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/errata/mips/errata.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c +index e984a8152208c..2c3dc2259e93e 100644 +--- a/arch/riscv/errata/mips/errata.c ++++ b/arch/riscv/errata/mips/errata.c +@@ -57,7 +57,7 @@ void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + } + + tmp = (1U << alt->patch_id); +- if (cpu_req_errata && tmp) { ++ if (cpu_req_errata & tmp) { + mutex_lock(&text_mutex); + patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt), + alt->alt_len); +-- +2.53.0 + diff --git a/queue-6.18/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch b/queue-6.18/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch new file mode 100644 index 0000000000..1c51db2e7c --- /dev/null +++ b/queue-6.18/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch @@ -0,0 +1,87 @@ +From b4c87f741a15214380f52384a7e87820808c3440 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 00:52:12 -0500 +Subject: riscv: mm: Fixup no5lvl failure when vaddr is invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Guo Ren (Alibaba DAMO Academy) + +[ Upstream commit db909bd7986c10da074917af3dae83a60fa65093 ] + +Unlike no4lvl, no5lvl still continues to detect satp, which +requires va=pa mapping. When pa=0x800000000000, no5lvl +would fail in Sv48 mode due to an illegal VA value of +0x800000000000. + +So, prevent detecting the satp flow for no5lvl, when +vaddr is invalid. Add the is_vaddr_valid() function for +checking. + +Fixes: 26e7aacb83df ("riscv: Allow to downgrade paging mode from the command line") +Cc: Alexandre Ghiti +Cc: Björn Töpel +Signed-off-by: Guo Ren (Alibaba DAMO Academy) +Tested-by: Fangyu Yu +Link: https://patch.msgid.link/20260125055212.433163-1-guoren@kernel.org +[pjw@kernel.org: cleaned up commit message] +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/mm/init.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index d85efe74a4b69..ee40ca01ac663 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -852,6 +852,27 @@ static void __init set_mmap_rnd_bits_max(void) + mmap_rnd_bits_max = MMAP_VA_BITS - PAGE_SHIFT - 3; + } + ++static bool __init is_vaddr_valid(unsigned long va) ++{ ++ unsigned long up = 0; ++ ++ switch (satp_mode) { ++ case SATP_MODE_39: ++ up = 1UL << 38; ++ break; ++ case SATP_MODE_48: ++ up = 1UL << 47; ++ break; ++ case SATP_MODE_57: ++ up = 1UL << 56; ++ break; ++ default: ++ return false; ++ } ++ ++ return (va < up) || (va >= (ULONG_MAX - up + 1)); ++} ++ + /* + * There is a simple way to determine if 4-level is supported by the + * underlying hardware: establish 1:1 mapping in 4-level page table mode +@@ -893,6 +914,9 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + set_satp_mode_pmd + PMD_SIZE, + PMD_SIZE, PAGE_KERNEL_EXEC); + retry: ++ if (!is_vaddr_valid(set_satp_mode_pmd)) ++ goto out; ++ + create_pgd_mapping(early_pg_dir, + set_satp_mode_pmd, + pgtable_l5_enabled ? +@@ -915,6 +939,7 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + disable_pgtable_l4(); + } + ++out: + memset(early_pg_dir, 0, PAGE_SIZE); + memset(early_p4d, 0, PAGE_SIZE); + memset(early_pud, 0, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-6.18/rtc-max77686-convert-to-i2c_new_ancillary_device.patch b/queue-6.18/rtc-max77686-convert-to-i2c_new_ancillary_device.patch new file mode 100644 index 0000000000..54b8721a8a --- /dev/null +++ b/queue-6.18/rtc-max77686-convert-to-i2c_new_ancillary_device.patch @@ -0,0 +1,67 @@ +From 088d13b8127b4911653c0c074448a18a7b321c86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 10:52:58 +0200 +Subject: rtc: max77686: convert to i2c_new_ancillary_device + +From: Svyatoslav Ryhel + +[ Upstream commit 0d65a9d93d870ef3d13642f88d0e6d562790c96d ] + +Convert RTC I2C device creation from devm_i2c_new_dummy_device() to +i2c_new_ancillary_device() to enable the use of a device tree-specified +RTC address instead of a hardcoded value. If the device tree does not +provide an address, use hardcoded values as a fallback. + +This addresses an issue with the MAX77663 PMIC, which can have the RTC at +different I2C positions (either 0x48, like the MAX77714, or 0x68, like +the MAX77620). The MAX77620 value is used as the default. The I2C position +of the MAX77663 is factory-set and cannot be detected from the chip +itself. + +Signed-off-by: Svyatoslav Ryhel +Link: https://patch.msgid.link/20260312085258.11431-6-clamor95@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-max77686.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c +index 69ea3ce75b5a5..3cdfd78a07ccc 100644 +--- a/drivers/rtc/rtc-max77686.c ++++ b/drivers/rtc/rtc-max77686.c +@@ -686,6 +686,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) + return ret; + } + ++static void max77686_rtc_release_dev(void *client) ++{ ++ i2c_unregister_device(client); ++} ++ + static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) + { + struct device *parent = info->dev->parent; +@@ -713,12 +718,17 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) + goto add_rtc_irq; + } + +- client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter, +- info->drv_data->rtc_i2c_addr); ++ client = i2c_new_ancillary_device(parent_i2c, "rtc", ++ info->drv_data->rtc_i2c_addr); + if (IS_ERR(client)) + return dev_err_probe(info->dev, PTR_ERR(client), + "Failed to allocate I2C device for RTC\n"); + ++ ret = devm_add_action_or_reset(info->dev, max77686_rtc_release_dev, ++ client); ++ if (ret) ++ return ret; ++ + info->rtc_regmap = devm_regmap_init_i2c(client, + info->drv_data->regmap_config); + if (IS_ERR(info->rtc_regmap)) +-- +2.53.0 + diff --git a/queue-6.18/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch b/queue-6.18/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch new file mode 100644 index 0000000000..48fdd31c49 --- /dev/null +++ b/queue-6.18/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch @@ -0,0 +1,50 @@ +From ebb68712899e7a23b7e46f0c0ee4c6ded1383000 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:47:40 +0530 +Subject: rtc: ti-k3: Add support to resume from IO DDR low power mode + +From: Akashdeep Kaur + +[ Upstream commit 0e9b12ee74c57617bb362deb3c82e35fe49694b5 ] + +Restore the RTC HW context which may be lost when system enters +certain low power mode (IO+DDR mode). +Check if the RTC registers are locked which would indicate loss of +context (reset) and restore the context as needed. + +Signed-off-by: Akashdeep Kaur +Reviewed-by: Vignesh Raghavendra +Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-ti-k3.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c +index ec759d8f7023c..e801f5b9d7574 100644 +--- a/drivers/rtc/rtc-ti-k3.c ++++ b/drivers/rtc/rtc-ti-k3.c +@@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) + static int __maybe_unused ti_k3_rtc_resume(struct device *dev) + { + struct ti_k3_rtc *priv = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (k3rtc_check_unlocked(priv)) { ++ /* RTC locked implies low power mode exit where RTC loses context */ ++ ret = k3rtc_configure(dev); ++ if (ret) ++ return ret; ++ } + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); +- return 0; ++ return ret; + } + + static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); +-- +2.53.0 + diff --git a/queue-6.18/rtla-handle-pthread_create-failure-properly.patch b/queue-6.18/rtla-handle-pthread_create-failure-properly.patch new file mode 100644 index 0000000000..a48e62b3b8 --- /dev/null +++ b/queue-6.18/rtla-handle-pthread_create-failure-properly.patch @@ -0,0 +1,46 @@ +From c31653999920a7a5d81cea9b22295d79daa52ff9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:22 -0300 +Subject: rtla: Handle pthread_create() failure properly + +From: Wander Lairson Costa + +[ Upstream commit d847188bb92b14518a04d7542e44928a22060847 ] + +Add proper error handling when pthread_create() fails to create the +timerlat user-space dispatcher thread. Previously, the code only logged +an error message but continued execution, which could lead to undefined +behavior when the tool later expects the thread to be running. + +When pthread_create() returns an error, the function now jumps to the +out_trace error path to properly clean up resources and exit. This +ensures consistent error handling and prevents the tool from running +in an invalid state without the required user-space thread. + +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-10-wander@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/common.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c +index b197037fc58b3..53eede96e1ceb 100644 +--- a/tools/tracing/rtla/src/common.c ++++ b/tools/tracing/rtla/src/common.c +@@ -191,8 +191,10 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[]) + params->user.cgroup_name = params->cgroup_name; + + retval = pthread_create(&user_thread, NULL, timerlat_u_dispatcher, ¶ms->user); +- if (retval) ++ if (retval) { + err_msg("Error creating timerlat user-space threads\n"); ++ goto out_trace; ++ } + } + + retval = ops->enable(tool); +-- +2.53.0 + diff --git a/queue-6.18/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch b/queue-6.18/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch new file mode 100644 index 0000000000..51063c7600 --- /dev/null +++ b/queue-6.18/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch @@ -0,0 +1,73 @@ +From 9334a4400761f036bc78464effaaf2f07fe4015e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:10:06 +0100 +Subject: s390/bpf: Do not increment tailcall count when prog is NULL + +From: Ilya Leoshkevich + +[ Upstream commit e4094d56c5592dd90aa619f9480265b0689ed3d9 ] + +Currently tail calling a non-existent prog results in tailcall count +increment. This is what the interpreter is doing, but this is clearly +wrong, so replace load-and-increment and compare-and-jump with load +and compare-and-jump, conditionally followed by increment and store. + +Reported-by: Hari Bathini +Signed-off-by: Ilya Leoshkevich +Link: https://lore.kernel.org/r/20260217161058.101346-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index d7cdd907ac797..99e5684b2291c 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -1872,20 +1872,21 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + jit->prg); + + /* +- * if (tail_call_cnt++ >= MAX_TAIL_CALL_CNT) ++ * if (tail_call_cnt >= MAX_TAIL_CALL_CNT) + * goto out; ++ * ++ * tail_call_cnt is read into %w0, which needs to be preserved ++ * until it's incremented and flushed. + */ + + off = jit->frame_off + + offsetof(struct prog_frame, tail_call_cnt); +- /* lhi %w0,1 */ +- EMIT4_IMM(0xa7080000, REG_W0, 1); +- /* laal %w1,%w0,off(%r15) */ +- EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); +- /* clij %w1,MAX_TAIL_CALL_CNT-1,0x2,out */ ++ /* ly %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0058, REG_W0, REG_0, REG_15, off); ++ /* clij %w0,MAX_TAIL_CALL_CNT,0xa,out */ + patch_2_clij = jit->prg; +- EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT - 1, +- 2, jit->prg); ++ EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W0, MAX_TAIL_CALL_CNT, ++ 0xa, jit->prg); + + /* + * prog = array->ptrs[index]; +@@ -1904,6 +1905,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + patch_3_brc = jit->prg; + EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); + ++ /* tail_call_cnt++; */ ++ /* ahi %w0,1 */ ++ EMIT4_IMM(0xa70a0000, REG_W0, 1); ++ /* sty %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, REG_0, REG_15, off); ++ + /* + * Restore registers before calling function + */ +-- +2.53.0 + diff --git a/queue-6.18/sched-eevdf-clear-buddies-for-preempt_short.patch b/queue-6.18/sched-eevdf-clear-buddies-for-preempt_short.patch new file mode 100644 index 0000000000..dc7c8665c0 --- /dev/null +++ b/queue-6.18/sched-eevdf-clear-buddies-for-preempt_short.patch @@ -0,0 +1,66 @@ +From 25bbfcf64ea3aaed8e03b477ed41b8ad0e96ca5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 15:23:21 +0200 +Subject: sched/eevdf: Clear buddies for preempt_short + +From: Vincent Guittot + +[ Upstream commit 78cde54ea5f03398f1cf6656de2472068f6da966 ] + +next buddy should not prevent shorter slice preemption. Don't take buddy +into account when checking if shorter slice entity can preempt and clear it +if the entity with a shorter slice can preempt current. + +Test on snapdragon rb5: +hackbench -T -p -l 16000000 -g 2 1> /dev/null & +hackbench runs in cgroup /test-A +cyclictest -t 1 -i 2777 -D 63 --policy=fair --mlock -h 20000 -q +cyclictest runs in cgroup /test-B + + tip/sched/core tip/sched/core +this patch +cyclictest slice (ms) (default)2.8 8 8 +hackbench slice (ms) (default)2.8 20 20 +Total Samples | 22679 22595 22686 +Average (us) | 84 94(-12%) 59( 37%) +Median (P50) (us) | 56 56( 0%) 56( 0%) +90th Percentile (us) | 64 65(- 2%) 63( 3%) +99th Percentile (us) | 1047 1273(-22%) 74( 94%) +99.9th Percentile (us) | 2431 4751(-95%) 663( 86%) +Maximum (us) | 4694 8655(-84%) 3934( 55%) + +Signed-off-by: Vincent Guittot +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260410132321.2897789-1-vincent.guittot@linaro.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 6e75ec86d6e13..7e8a22d4033d1 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1024,7 +1024,7 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + /* + * Picking the ->next buddy will affect latency but not fairness. + */ +- if (sched_feat(PICK_BUDDY) && ++ if (sched_feat(PICK_BUDDY) && protect && + cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) { + /* ->next will never be delayed */ + WARN_ON_ONCE(cfs_rq->next->sched_delayed); +@@ -8987,8 +8987,10 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + return; + + preempt: +- if (preempt_action == PREEMPT_WAKEUP_SHORT) ++ if (preempt_action == PREEMPT_WAKEUP_SHORT) { + cancel_protect_slice(se); ++ clear_buddies(cfs_rq, se); ++ } + + resched_curr_lazy(rq); + } +-- +2.53.0 + diff --git a/queue-6.18/sched-fair-make-hrtick-resched-hard.patch b/queue-6.18/sched-fair-make-hrtick-resched-hard.patch new file mode 100644 index 0000000000..8b4eb5650a --- /dev/null +++ b/queue-6.18/sched-fair-make-hrtick-resched-hard.patch @@ -0,0 +1,40 @@ +From 90854b045a98af8aab4343011a2d17498e43e530 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:27 +0100 +Subject: sched/fair: Make hrtick resched hard + +From: Peter Zijlstra (Intel) + +[ Upstream commit 5d88e424ec1b3ea7f552bd14d932f510146c45c7 ] + +Since the tick causes hard preemption, the hrtick should too. + +Letting the hrtick do lazy preemption completely defeats the purpose, since +it will then still be delayed until a old tick and be dependent on +CONFIG_HZ. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163428.933894105@kernel.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 7e0e2044d840b..6e75ec86d6e13 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -5639,7 +5639,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + * validating it and just reschedule. + */ + if (queued) { +- resched_curr_lazy(rq_of(cfs_rq)); ++ resched_curr(rq_of(cfs_rq)); + return; + } + #endif +-- +2.53.0 + diff --git a/queue-6.18/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch b/queue-6.18/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch new file mode 100644 index 0000000000..2cdbeb79c7 --- /dev/null +++ b/queue-6.18/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch @@ -0,0 +1,101 @@ +From 118acd69671baf6c81b23369f03df2fa04013e0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 19:59:29 +0800 +Subject: sched: Fix incorrect schedstats for rt and dl thread + +From: Dengjun Su + +[ Upstream commit c0e1832ba6dad7057acf3f485a87e0adccc23141 ] + +For RT and DL thread, only 'set_next_task_(rt/dl)' will call +'update_stats_wait_end_(rt/dl)' to update schedstats information. +However, during the migration process, +'update_stats_wait_start_(rt/dl)' will be called twice, which +will cause the values of wait_max and wait_sum to be incorrect. +The specific output as follows: +$ cat /proc/6046/task/6046/sched | grep wait +wait_start : 0.000000 +wait_max : 496717.080029 +wait_sum : 7921540.776553 + +A complete schedstats information update flow of migrate should be +__update_stats_wait_start() [enter queue A, stage 1] -> +__update_stats_wait_end() [leave queue A, stage 2] -> +__update_stats_wait_start() [enter queue B, stage 3] -> +__update_stats_wait_end() [start running on queue B, stage 4] + + Stage 1: prev_wait_start is 0, and in the end, wait_start records the + time of entering the queue. + Stage 2: task_on_rq_migrating(p) is true, and wait_start is updated to + the waiting time on queue A. + Stage 3: prev_wait_start is the waiting time on queue A, wait_start is + the time of entering queue B, and wait_start is expected to be greater + than prev_wait_start. Under this condition, wait_start is updated to + (the moment of entering queue B) - (the waiting time on queue A). + Stage 4: the final wait time = (time when starting to run on queue B) + - (time of entering queue B) + (waiting time on queue A) = waiting + time on queue B + waiting time on queue A. + +The current problem is that stage 2 does not call __update_stats_wait_end +to update wait_start, which causes the final computed wait time = waiting +time on queue B + the moment of entering queue A, leading to incorrect +wait_max and wait_sum. + +Add 'update_stats_wait_end_(rt/dl)' in 'update_stats_dequeue_(rt/dl)' to +update schedstats information when dequeue_task. + +Signed-off-by: Dengjun Su +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260204115959.3183567-1-dengjun.su@mediatek.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 4 ++++ + kernel/sched/rt.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index d5052f238adf7..25230e29ff161 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -2109,10 +2109,14 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, + int flags) + { + struct task_struct *p = dl_task_of(dl_se); ++ struct rq *rq = rq_of_dl_rq(dl_rq); + + if (!schedstat_enabled()) + return; + ++ if (p != rq->curr) ++ update_stats_wait_end_dl(dl_rq, dl_se); ++ + if ((flags & DEQUEUE_SLEEP)) { + unsigned int state; + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 3e81b9d83d14d..4bf8f96ed2939 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1302,13 +1302,18 @@ update_stats_dequeue_rt(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, + int flags) + { + struct task_struct *p = NULL; ++ struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!schedstat_enabled()) + return; + +- if (rt_entity_is_task(rt_se)) ++ if (rt_entity_is_task(rt_se)) { + p = rt_task_of(rt_se); + ++ if (p != rq->curr) ++ update_stats_wait_end_rt(rt_rq, rt_se); ++ } ++ + if ((flags & DEQUEUE_SLEEP) && p) { + unsigned int state; + +-- +2.53.0 + diff --git a/queue-6.18/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-6.18/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..7394d648b6 --- /dev/null +++ b/queue-6.18/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From fba19b2ca998a452fa18364a59ebab7d28fa57e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-6.18/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch b/queue-6.18/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch new file mode 100644 index 0000000000..1fe15ddf91 --- /dev/null +++ b/queue-6.18/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch @@ -0,0 +1,83 @@ +From d54d92c58c06990697064ad2dbb357d2657ee9ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:59:27 -0700 +Subject: scsi: lpfc: Add PCI ID support for LPe42100 series adapters + +From: Justin Tee + +[ Upstream commit 49b9f31e52b2125125318cb60fe9f5e7fa9c6755 ] + +Update supported pci_device_id table to include the values for the G8 ASIC +Device ID utilized by LPe42100 series of adapters. The default reporting +string will be "LPe42100". + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260331205928.119833-10-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_hw.h | 3 ++- + drivers/scsi/lpfc/lpfc_ids.h | 4 +++- + drivers/scsi/lpfc/lpfc_init.c | 3 +++ + 3 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h +index 3bc0efa7453e3..9c5f1f94a3434 100644 +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * ++ * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * +@@ -1748,6 +1748,7 @@ struct lpfc_fdmi_reg_portattr { + #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 + #define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 + #define PCI_DEVICE_ID_LANCER_G7P_FC 0xf500 ++#define PCI_DEVICE_ID_LANCER_G8_FC 0xd300 + #define PCI_DEVICE_ID_SAT_SMB 0xf011 + #define PCI_DEVICE_ID_SAT_MID 0xf015 + #define PCI_DEVICE_ID_RFLY 0xf095 +diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h +index 0b1616e93cf47..a0a6e2d379b86 100644 +--- a/drivers/scsi/lpfc/lpfc_ids.h ++++ b/drivers/scsi/lpfc/lpfc_ids.h +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * ++ * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * +@@ -118,6 +118,8 @@ const struct pci_device_id lpfc_id_table[] = { + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7P_FC, + PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G8_FC, ++ PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index adc0beaf5468f..d83b9c66b6979 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -2752,6 +2752,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) + case PCI_DEVICE_ID_LANCER_G7P_FC: + m = (typeof(m)){"LPe38000", "PCIe", "Fibre Channel Adapter"}; + break; ++ case PCI_DEVICE_ID_LANCER_G8_FC: ++ m = (typeof(m)){"LPe42100", "PCIe", "Fibre Channel Adapter"}; ++ break; + case PCI_DEVICE_ID_SKYHAWK: + case PCI_DEVICE_ID_SKYHAWK_VF: + oneConnect = 1; +-- +2.53.0 + diff --git a/queue-6.18/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch b/queue-6.18/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch new file mode 100644 index 0000000000..197f760d96 --- /dev/null +++ b/queue-6.18/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch @@ -0,0 +1,117 @@ +From 3e44f329877a29c718ab86f2ba128d83ca93f3ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:03 -0800 +Subject: scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in + lpfc_sli_abort_ring() + +From: Justin Tee + +[ Upstream commit 2da10bcaa58a389ca60f8e788180e0dca00739bc ] + +When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is +cleared but the phba->txcmplq_cnt is not reset to zero. This can +sometimes result in a phba->txcmplq_cnt that never reaches zero, which +hangs the cleanup process. + +Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also +ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_sli.c | 66 +++++++++++++----------------------- + 1 file changed, 24 insertions(+), 42 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 7b765719f4f6b..04451f14d50e4 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -4571,59 +4571,41 @@ void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { + LIST_HEAD(tx_completions); +- LIST_HEAD(txcmplq_completions); ++ spinlock_t *plock; /* for transmit queue access */ + struct lpfc_iocbq *iocb, *next_iocb; + int offline; + +- if (pring->ringno == LPFC_ELS_RING) { ++ if (phba->sli_rev >= LPFC_SLI_REV4) ++ plock = &pring->ring_lock; ++ else ++ plock = &phba->hbalock; ++ ++ if (pring->ringno == LPFC_ELS_RING) + lpfc_fabric_abort_hba(phba); +- } ++ + offline = pci_channel_offline(phba->pcidev); + +- /* Error everything on txq and txcmplq +- * First do the txq. +- */ +- if (phba->sli_rev >= LPFC_SLI_REV4) { +- spin_lock_irq(&pring->ring_lock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; ++ /* Cancel everything on txq */ ++ spin_lock_irq(plock); ++ list_splice_init(&pring->txq, &tx_completions); ++ pring->txq_cnt = 0; + +- if (offline) { +- list_splice_init(&pring->txcmplq, +- &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&pring->ring_lock); ++ if (offline) { ++ /* Cancel everything on txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; ++ list_splice_init(&pring->txcmplq, &tx_completions); ++ pring->txcmplq_cnt = 0; + } else { +- spin_lock_irq(&phba->hbalock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; +- +- if (offline) { +- list_splice_init(&pring->txcmplq, &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&phba->hbalock); ++ /* Issue ABTS for everything on the txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + } ++ spin_unlock_irq(plock); + +- if (offline) { +- /* Cancel all the IOCBs from the completions list */ +- lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, +- IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); +- } else { +- /* Make sure HBA is alive */ ++ if (!offline) + lpfc_issue_hb_tmo(phba); +- } ++ + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); +-- +2.53.0 + diff --git a/queue-6.18/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch b/queue-6.18/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch new file mode 100644 index 0000000000..261708da9c --- /dev/null +++ b/queue-6.18/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch @@ -0,0 +1,40 @@ +From 67cbbf3d676dd32b032b0091a69b74354e17478f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:01 -0800 +Subject: scsi: lpfc: Remove unnecessary ndlp kref get in + lpfc_check_nlp_post_devloss + +From: Justin Tee + +[ Upstream commit f6bfb8d149336661bb80e62980da9a45b920403c ] + +When NLP_IN_RECOV_POST_DEV_LOSS is set, the initial node reference +remains held while recovery is in progress. Taking a reference when +NLP_IN_RECOV_POST_DEV_LOSS is cleared results in an additional reference +being held. This causes an extra reference when cleaning up lpfc_vport +instances. Thus, remove the extraneous ndlp kref get in +lpfc_check_nlp_post_devloss. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-7-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_hbadisc.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 717ae56c8e4bd..822a1c7d5e9d2 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -425,7 +425,6 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, + { + if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) { + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); +- lpfc_nlp_get(ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, + "8438 Devloss timeout reversed on DID x%x " + "refcnt %d ndlp %p flag x%lx " +-- +2.53.0 + diff --git a/queue-6.18/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-6.18/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..0a442023cf --- /dev/null +++ b/queue-6.18/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 87111a9380943a2373ce8919957c4b0bd88ce668 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 68c837146b9ea..08e982b92fcd3 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1131,6 +1131,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1141,22 +1161,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-6.18/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch b/queue-6.18/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch new file mode 100644 index 0000000000..dfc6b3efe6 --- /dev/null +++ b/queue-6.18/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch @@ -0,0 +1,38 @@ +From 19b468d228845ce6a55f7f6bf2d552453bed776b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 13:41:34 -0500 +Subject: scsi: ufs: core: Disable timestamp for Kioxia THGJFJT0E25BAIP + +From: Aaron Kling + +[ Upstream commit e423f1c7195645e18945fba0bd8f0a32e39286e7 ] + +Kioxia has another product that does not support the qTimestamp +attribute. + +Signed-off-by: Aaron Kling +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260403-thgjfjt0e25baip-no-timestamp-v1-1-1ddb34225133@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/core/ufshcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 5371f173e28b9..580096be6e75c 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -311,6 +311,9 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGLF2G9D8KBADG", + .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE }, ++ { .wmanufacturerid = UFS_VENDOR_TOSHIBA, ++ .model = "THGJFJT0E25BAIP", ++ .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGJFJT1E45BATP", + .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, +-- +2.53.0 + diff --git a/queue-6.18/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch b/queue-6.18/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch new file mode 100644 index 0000000000..338289eac6 --- /dev/null +++ b/queue-6.18/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch @@ -0,0 +1,35 @@ +From 24891bd395db8e06ee3ff47a07e820ade8867002 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 10:58:15 +0200 +Subject: scsi: ufs: ufs-pci: Add support for Intel Nova Lake + +From: Adrian Hunter + +[ Upstream commit 096cd6b7adf21791827a045d464242d93a6fd54e ] + +Add PCI ID to support Intel Nova Lake, same as Intel Meteor Lake (MTL). + +Signed-off-by: Adrian Hunter +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260309085815.55216-1-adrian.hunter@intel.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/ufshcd-pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c +index 5f65dfad1a71a..63f6b36b912fc 100644 +--- a/drivers/ufs/host/ufshcd-pci.c ++++ b/drivers/ufs/host/ufshcd-pci.c +@@ -695,6 +695,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { + { PCI_VDEVICE(INTEL, 0x7747), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0xE447), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4D47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, ++ { PCI_VDEVICE(INTEL, 0xD335), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { } /* terminate list */ + }; + +-- +2.53.0 + diff --git a/queue-6.18/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-6.18/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..676699bb93 --- /dev/null +++ b/queue-6.18/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From e743d104375b3e55ed1619c22139169a203c7945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index 2b0a90581e2f1..aef603ae06fe0 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -1201,6 +1201,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-6.18/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch b/queue-6.18/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch new file mode 100644 index 0000000000..84a9960819 --- /dev/null +++ b/queue-6.18/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch @@ -0,0 +1,61 @@ +From 7dfc3971b3a6b239c1488da9f8e75f763ef3f89c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 18:19:40 +0800 +Subject: selftests: ublk: cap nthreads to kernel's actual nr_hw_queues + +From: Ming Lei + +[ Upstream commit 87d0740b7c4cc847be1b6f307ab6d8547cb1a726 ] + +dev->nthreads is derived from the user-requested queue count before the +ADD command, but the kernel may reduce nr_hw_queues (capped to +nr_cpu_ids). When the VM has fewer CPUs than requested queues, the +daemon creates more handler threads than there are kernel queues. + +In non-batch mode, the extra threads access uninitialized queues +(q_depth=0), submit zero io_uring SQEs, and block forever in +io_cqring_wait. In batch mode, the extra threads cause similar hangs +during device removal. + +In both cases, the stuck threads prevent the daemon from closing the +char device, holding the last ublk_device reference and causing +ublk_ctrl_del_dev() to hang in wait_event_interruptible(). + +Fix by capping dev->nthreads to the kernel-returned nr_hw_queues after +the ADD command completes. per_io_tasks mode is excluded because threads +interleave across all queues, so nthreads > nr_hw_queues is valid. + +Fixes: abe54c160346 ("selftests: ublk: kublk: decouple ublk_queues from ublk server threads") +Signed-off-by: Ming Lei +Link: https://patch.msgid.link/20260513101941.1373998-1-tom.leiming@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/ublk/kublk.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c +index cbd23444c8a98..ac47979349a4b 100644 +--- a/tools/testing/selftests/ublk/kublk.c ++++ b/tools/testing/selftests/ublk/kublk.c +@@ -1220,6 +1220,17 @@ static int __cmd_dev_add(const struct dev_ctx *ctx) + goto fail; + } + ++ /* ++ * The kernel may reduce nr_hw_queues (e.g. capped to nr_cpu_ids). ++ * Cap nthreads to the actual queue count to avoid creating extra ++ * handler threads that will hang during device removal. ++ * ++ * per_io_tasks mode is excluded: threads interleave across all ++ * queues so nthreads > nr_hw_queues is valid and intentional. ++ */ ++ if (!ctx->per_io_tasks && dev->nthreads > info->nr_hw_queues) ++ dev->nthreads = info->nr_hw_queues; ++ + ret = ublk_start_daemon(ctx, dev); + ublk_dbg(UBLK_DBG_DEV, "%s: daemon exit %d\n", __func__, ret); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-6.18/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-6.18/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..2406770a52 --- /dev/null +++ b/queue-6.18/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 592f3ade133733f0ffa7702fda391204be049291 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index 8058b839b26ce..6b0b4a36e5f0a 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -139,6 +139,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + const struct qcom_geni_device_data *dev_data; +@@ -242,7 +243,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1357,11 +1358,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) { + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series new file mode 100644 index 0000000000..97369ac8de --- /dev/null +++ b/queue-6.18/series @@ -0,0 +1,428 @@ +hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch +hid-uclogic-fix-regression-of-input-name-assignment.patch +riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch +riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch +alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch +btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-x_tables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch +test_kprobes-clear-kprobes-between-test-runs.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch +net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch +net-shaper-reject-reparenting-of-existing-nodes.patch +idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch +ice-fix-setting-rss-vsi-hash-for-e830.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +net-lan966x-avoid-unregistering-netdev-on-register-f.patch +net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch +nfsd-fix-infinite-loop-in-layout-state-revocation.patch +fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch +fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch +fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch +irqchip-ath79-cpu-remove-unused-function.patch +ublk-reject-max_sectors-smaller-than-page_sectors-in.patch +nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch +irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch +nvme-fix-bio-leak-on-mapping-failure.patch +nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch +tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch +powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch +powerpc-fix-dead-default-for-guest_state_buffer_test.patch +netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch +netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch +netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch +netfs-fix-overrun-check-in-netfs_extract_user_iter.patch +netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch +netfs-defer-the-emission-of-trace_netfs_folio.patch +netfs-fix-streaming-write-being-overwritten.patch +netfs-fix-potential-deadlock-in-write-through-mode.patch +netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch +netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch +netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch +netfs-fix-leak-of-request-in-netfs_write_begin-error.patch +netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch +netfs-fix-partial-invalidation-of-streaming-write-fo.patch +netfs-fix-folio-private-handling-in-netfs_perform_wr.patch +netfs-fix-netfs_read_folio-to-wait-on-writeback.patch +netfs-afs-fix-write-skipping-in-dir-link-writepages.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +net-shaper-flip-the-polarity-of-the-valid-flag.patch +net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch +net-shaper-reject-duplicate-leaves-in-group-request.patch +net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch +net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch +net-shaper-reject-handle-ids-exceeding-internal-bit-.patch +net-shaper-enforce-singleton-netdev-scope-with-id-0.patch +net-shaper-reject-queue-scope-handle-with-missing-id.patch +block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch +block-recompute-nr_integrity_segments-in-blk_insert_.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch +accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch +net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch +x86-mce-restore-mca-polling-interval-halving.patch +powerpc-time-remove-redundant-preempt_disable-enable.patch +net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +net-phy-dp83tc811-add-reading-of-abilities.patch +gcc-plugins-always-define-const_cast_gimple-and-cons.patch +x86-xen-fix-xen_e820_swap_entry_with_ram.patch +alsa-scarlett2-add-missing-error-check-when-initiali.patch +hwmon-lm90-stop-work-before-releasing-hwmon-device.patch +hwmon-lm90-add-lock-protection-to-lm90_alert.patch +asoc-amd-acp-add-asus-hn7306ea-quirk-for-legacy-sdw-.patch +srcu-use-irq_work-to-start-gp-in-tiny-srcu.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +nvmet-tcp-don-t-free-sq-on-authentication-success.patch +nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch +pstore-fix-ftrace-dump-when-ecc-is-enabled.patch +exfat-fix-s_maxbytes.patch +blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch +io_uring-cancel-validate-opcode-for-ioring_async_can.patch +erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch +exfat-fix-incorrect-directory-checksum-after-rename-.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-cgbc-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch +sched-fair-make-hrtick-resched-hard.patch +perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +objtool-support-clang-rax-drap-sequence.patch +sched-eevdf-clear-buddies-for-preempt_short.patch +s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch +net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +wifi-mac80211-set-band-information-only-for-non-mld-.patch +wifi-ath12k-set-up-mlo-after-ssr.patch +wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +wifi-ath12k-fix-the-assignment-of-logical-link-index.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch +tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch +hinic3-add-msg_send_lock-for-message-sending-concurr.patch +wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch +ipv4-validate-ipv4_devconf-attributes-properly.patch +powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch +wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch +wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch +wifi-mt76-mt7925-skip-scan-process-during-suspend.patch +wifi-mac80211-properly-handle-error-in-ieee80211_add.patch +bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch +wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch +wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch +wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch +wifi-mt76-flush-pending-tx-before-channel-switch.patch +wifi-mt76-abort-roc-on-chanctx-changes.patch +wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch +wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch +wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch +wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch +wifi-iwlwifi-restrict-top-reset-to-some-devices.patch +wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch +wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch +wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch +net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch +wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-mlx5e-xsk-increase-size-for-chunk_size-param.patch +wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch +wifi-brcmfmac-of-defer-probe-for-mac-address.patch +wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch +net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch +ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch +bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch +bluetooth-btmtk-add-mt7902-mcu-support.patch +bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-wangxun-reorder-timer-and-work-sync-cancellation.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch +bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch +bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch +bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch +drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch +drm-panel-edp-add-cmn-n116bcl-eak-c2.patch +drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch +nouveau-pci-quiesce-gpu-on-shutdown.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch +drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch +drm-amd-display-fix-dcn401_optimize_bandwidth.patch +pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch +dm-vdo-indexer-validate-saved-zone-count.patch +dm-vdo-slab-depot-validate-old-zone-count-on-load.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch +pci-avoid-flr-for-amd-npu-device.patch +drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch +drm-amdgpu-check-for-multiplication-overflow-in-chec.patch +alsa-usb-audio-add-studio-1824-support.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-ipu-bridge-add-ov5675-sensor-config.patch +media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch +media-i2c-imx258-add-missing-mutex-protection-for-fo.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch +drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch +drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch +drm-imx-parallel-display-add-drm_display_helper-for-.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +pci-dpc-hold-pci_dev-reference-during-error-recovery.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch +iommu-iova-add-null-check-in-iova_magazine_free.patch +drm-amdgpu-fix-amdgpu_userq_evict.patch +drm-amd-display-remove-duplicate-format-modifier.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch +drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +drm-prime-limit-scatter-list-size-with-dedicated-dma.patch +drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch +drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch +drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch +media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch +drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-renesas-vsp1-initialize-format-on-all-pads.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +drm-gem-dma-set-vm_dontdump-for-mmap.patch +pci-prevent-assignment-to-unsupported-bridge-windows.patch +iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch +iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch +alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +alsa-asihpi-detect-truncated-control-names.patch +alsa-usb-audio-add-quirks-for-arturia-af16rig.patch +dm-integrity-fix-mismatched-queue-limits.patch +alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch +alsa-hda-realtek-add-support-for-asus-2026-commercia.patch +drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch +drm-amd-display-merge-pipes-for-validate.patch +drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch +hwmon-gpd-fan-add-gpd-win-5.patch +hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch +hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch +drm-gpu-msm-forbid-mem-reclaim-from-reset.patch +asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +iommu-amd-invalidate-irt-cache-for-dma-aliases.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch +alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch +hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch +alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch +alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-validate-outarg-offset-and-size-in-notify-store.patch +fuse-mark-dax-inode-releases-as-blocking.patch +rtla-handle-pthread_create-failure-properly.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch +firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch +memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch +firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch +arm64-tegra-fix-snps-blen-properties.patch +firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch +drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +ima-define-and-use-a-digest_size-field-in-the-ima_al.patch +cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch +cxl-region-fix-use-after-free-from-auto-assembly-fai.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch +orangefs-validate-getxattr-response-length.patch +orangefs_readahead-don-t-overflow-the-bufmap-slot.patch +ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +hid-logitech-hidpp-check-bounds-when-deleting-force-.patch +hid-logitech-hidpp-fix-race-condition-when-accessing.patch +hid-playstation-validate-num_touch_reports-in-dualsh.patch +bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch +pinctrl-realtek-fix-return-value-and-silence-log-for.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +ipmi-ssif_bmc-cancel-response-timer-on-remove.patch +i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch +i3c-master-move-bus_init-error-suppression.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +thunderbolt-disable-clx-on-titan-ridge-based-devices.patch +usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch +tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch +nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch +leds-core-implement-fallback-to-software-node-name-f.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +ntfs3-fix-oob-write-in-attr_wof_frame_info.patch +platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch +scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch +scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch +scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch +um-avoid-struct-sigcontext-redefinition-with-musl.patch +um-fix-address-of-cmsg_data-rvalue-in-stub.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch +scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch +coda_flag_children-fix-a-uaf.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch +um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch +smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch +smb-server-stop-sending-fake-security-descriptors.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +smb-client-compress-fix-counting-in-lz77-match-findi.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch +iio-abi-fix-current_trigger-description.patch +iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch +bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch +drm-amdgpu-fix-cper-ring-header-parsing.patch +9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch +alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch +drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch +drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch +drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch +io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch +io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch +asoc-qcom-x1e80100-limit-speaker-volumes.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +rtc-max77686-convert-to-i2c_new_ancillary_device.patch +rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch +dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch +mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch +nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +nvme-multipath-put-module-reference-when-delayed-rem.patch +btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch +asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch +rculist-add-list_splice_rcu-for-private-lists.patch +btrfs-replace-assert-with-proper-error-handling-in-s.patch +btrfs-apply-first-key-check-for-readahead-when-possi.patch +btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch +nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch +btrfs-check-return-value-of-btrfs_partially_delete_r.patch +nvme-tcp-teardown-circular-locking-fixes.patch +btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch +md-raid5-fix-uaf-on-io-across-the-reshape-position.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-6.18/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch b/queue-6.18/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch new file mode 100644 index 0000000000..ad3cd61cda --- /dev/null +++ b/queue-6.18/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch @@ -0,0 +1,37 @@ +From 94d52bb56203587f4923f17df0377ba1a6ed630f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:07 -0300 +Subject: smb: client: compress: fix bad encoding on last LZ77 flag + +From: Enzo Matsumiya + +[ Upstream commit a13e942a03feea211c67a97bc6a57f82aa56e4b6 ] + +End-of-stream flag could lead to UB because of int promotion +(overwriting signed bit). + +Fix it by changing operand from '1' to '1UL'. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index 96e8a8057a772..cdd6b53766b0a 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -221,7 +221,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + } + + flag <<= (32 - flag_count); +- flag |= (1 << (32 - flag_count)) - 1; ++ flag |= (1UL << (32 - flag_count)) - 1; + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-- +2.53.0 + diff --git a/queue-6.18/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch b/queue-6.18/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch new file mode 100644 index 0000000000..1200d5621d --- /dev/null +++ b/queue-6.18/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch @@ -0,0 +1,131 @@ +From d722b6fe0ca32b1ca4e735f0bcc41275f240d033 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:06 -0300 +Subject: smb: client: compress: fix buffer overrun in lz77_compress() + +From: Enzo Matsumiya + +[ Upstream commit 4c221711b23745e2fb961ee517e9ed96ce76f9cb ] + +@dst buffer is allocated with same size as @src, which, for good +compression cases, works fine. + +However, when compression goes bad (e.g. random bytes payloads), the +compressed size can increase significantly, and even by stopping the +main loop at 7/8 of @slen, writing leftover literals could write past +the end of @dst because of LZ77 metadata. + +To fix this, add lz77_compressed_alloc_size() helper to compute the +correct allocation size for @dst, accounting for metadata and worst +cast scenario (all literals). + +While this is overprovisioning memory, it's not only correct, but also +allows lz77_compress() main loop to run without ever checking @dst +limits (i.e. a perf improvement). + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress.c | 6 +----- + fs/smb/client/compress/lz77.c | 14 ++++---------- + fs/smb/client/compress/lz77.h | 28 ++++++++++++++++++++++++++++ + 3 files changed, 33 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c +index db709f5cd2e1f..d00f56f6c4ef3 100644 +--- a/fs/smb/client/compress.c ++++ b/fs/smb/client/compress.c +@@ -314,11 +314,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s + goto err_free; + } + +- /* +- * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8 +- * of @slen. +- */ +- dlen = slen; ++ dlen = lz77_compressed_alloc_size(slen); + dst = kvzalloc(dlen, GFP_KERNEL); + if (!dst) { + ret = -ENOMEM; +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index cdd6b53766b0a..c1e7fada6e61c 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -137,6 +137,10 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + long flag = 0; + u64 *htable; + ++ /* This is probably a bug, so throw a warning. */ ++ if (WARN_ON_ONCE(*dlen < lz77_compressed_alloc_size(slen))) ++ return -EINVAL; ++ + srcp = src; + end = src + slen; + dstp = dst; +@@ -180,15 +184,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + continue; + } + +- /* +- * Bail out if @dstp reached >= 7/8 of @slen -- already compressed badly, not worth +- * going further. +- */ +- if (unlikely(dstp - dst >= slen - (slen >> 3))) { +- *dlen = slen; +- goto out; +- } +- + dstp = lz77_write_match(dstp, &nib, dist, len); + srcp += len; + +@@ -225,7 +220,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-out: + kvfree(htable); + + if (*dlen < slen) +diff --git a/fs/smb/client/compress/lz77.h b/fs/smb/client/compress/lz77.h +index cdcb191b48a23..2603eab9e071c 100644 +--- a/fs/smb/client/compress/lz77.h ++++ b/fs/smb/client/compress/lz77.h +@@ -11,5 +11,33 @@ + + #include + ++/** ++ * lz77_compressed_alloc_size() - Compute compressed buffer size. ++ * @size: uncompressed (src) size ++ * ++ * Compute allocation size for the compressed buffer based on uncompressed size. ++ * Accounts for metadata and overprovision for the worst case scenario. ++ * ++ * LZ77 metadata is a 4-byte flag that is written: ++ * - on dst begin (pos 0) ++ * - every 32 literals or matches ++ * - on end-of-stream (possibly, if last write was another flag) ++ * ++ * Worst case scenario is an all-literal compression, which means: ++ * metadata bytes = 4 + ((@size / 32) * 4) + 4, or, simplified, (@size >> 3) + 8 ++ * ++ * The worst case scenario rarely happens, but such overprovisioning also allows lz77_compress() ++ * main loop to run without ever bound checking dst, which is a huge perf improvement, while also ++ * being safe when compression goes bad. ++ * ++ * Return: required (*) allocation size for compressed buffer. ++ * ++ * (*) checked once in the beginning of lz77_compress() ++ */ ++static __always_inline u32 lz77_compressed_alloc_size(const u32 size) ++{ ++ return size + (size >> 3) + 8; ++} ++ + int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen); + #endif /* _SMB_COMPRESS_LZ77_H */ +-- +2.53.0 + diff --git a/queue-6.18/smb-client-compress-fix-counting-in-lz77-match-findi.patch b/queue-6.18/smb-client-compress-fix-counting-in-lz77-match-findi.patch new file mode 100644 index 0000000000..0637c17edf --- /dev/null +++ b/queue-6.18/smb-client-compress-fix-counting-in-lz77-match-findi.patch @@ -0,0 +1,78 @@ +From 76b72f74e1254bb8eb8db3119f04f2e343566c7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:08 -0300 +Subject: smb: client: compress: fix counting in LZ77 match finding + +From: Enzo Matsumiya + +[ Upstream commit 20d4f9efe008be1b673f43d38d3d99fb1fd4cd68 ] + +- lz77_match_len() increments @cur before checking for equality, + leading to off-by-one match len in some cases. + + Fix by moving pointers increment to inside the loop. + Also rename @wnd arg to @match (more accurate name). +- both lz77_match_len() and lz77_compress() checked for + "buf + step < end" when the correct is "<=" for such cases. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index c1e7fada6e61c..61cdf1c146127 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -48,17 +48,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v) + put_unaligned_le32(v, ptr); + } + +-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end) ++static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end) + { + const void *start = cur; + u64 diff; + + /* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */ + do { +- diff = lz77_read64(cur) ^ lz77_read64(wnd); ++ diff = lz77_read64(cur) ^ lz77_read64(match); + if (!diff) { + cur += LZ77_STEP_SIZE; +- wnd += LZ77_STEP_SIZE; ++ match += LZ77_STEP_SIZE; + + continue; + } +@@ -67,10 +67,13 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons + cur += count_trailing_zeros(diff) >> 3; + + return (cur - start); +- } while (likely(cur + LZ77_STEP_SIZE < end)); ++ } while (likely(cur + LZ77_STEP_SIZE <= end)); + +- while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++)) +- ; ++ /* Fallback to byte-by-byte comparison for last <8 bytes. */ ++ while (cur < end && lz77_read8(cur) == lz77_read8(match)) { ++ cur++; ++ match++; ++ } + + return (cur - start); + } +@@ -195,7 +198,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + flag_pos = dstp; + dstp += 4; + } +- } while (likely(srcp + LZ77_STEP_SIZE < end)); ++ } while (likely(srcp + LZ77_STEP_SIZE <= end)); + + while (srcp < end) { + u32 c = umin(end - srcp, 32 - flag_count); +-- +2.53.0 + diff --git a/queue-6.18/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-6.18/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..5ecf9ba886 --- /dev/null +++ b/queue-6.18/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From a0d2d2662d203102f3b115f2c43883dbc8b49ea9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index eed3a71171c0b..b7479a5ca2b76 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -4977,6 +4977,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + goto free_dw; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + dw->len = len; +-- +2.53.0 + diff --git a/queue-6.18/smb-server-stop-sending-fake-security-descriptors.patch b/queue-6.18/smb-server-stop-sending-fake-security-descriptors.patch new file mode 100644 index 0000000000..efd371a2e8 --- /dev/null +++ b/queue-6.18/smb-server-stop-sending-fake-security-descriptors.patch @@ -0,0 +1,71 @@ +From 31bf26cad307304e9a3e222b326b3a1d3e4552aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 10:14:50 +0900 +Subject: smb: server: stop sending fake security descriptors + +From: Marios Makassikis + +[ Upstream commit 5efb579e0d1ee02b85e3ce2da691c88c93111060 ] + +in smb2_get_info_sec, a dummy security descriptor (SD) is returned if +the requested information is not supported. + +the code is currently wrong, as DACL_PROTECTED is set in the type field, +but there is no DACL is present. + +instead of faking a security, report a STATUS_NOT_SUPPORTED error. + +this seems to fix a "Error 0x80090006: Invalid Signature" on file +transfers with Windows 11 clients (25H2, build 26200.8246). + +capturing traffic shows that the client is sending a GET_INFO/SEC_INFO +request, with the additional_info field set to 0x20 +(ATTRIBUTE_SECURITY_INFORMATION). Returning an empty SD +(with only SELF_RELATIVE set) does not fix the error. + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 756624b4e90e0..f309e8dbeae23 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -5748,20 +5748,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", + addition_info); + +- pntsd = kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), +- KSMBD_DEFAULT_GFP); +- if (!pntsd) +- return -ENOMEM; +- +- pntsd->revision = cpu_to_le16(1); +- pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); +- pntsd->osidoffset = 0; +- pntsd->gsidoffset = 0; +- pntsd->sacloffset = 0; +- pntsd->dacloffset = 0; +- +- secdesclen = sizeof(struct smb_ntsd); +- goto iov_pin; ++ rsp->hdr.Status = STATUS_NOT_SUPPORTED; ++ return -EINVAL; + } + + if (work->next_smb2_rcv_hdr_off) { +@@ -5828,7 +5816,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + if (rc) + goto err_out; + +-iov_pin: + rsp->OutputBufferLength = cpu_to_le32(secdesclen); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), + rsp, work->response_buf); +-- +2.53.0 + diff --git a/queue-6.18/srcu-use-irq_work-to-start-gp-in-tiny-srcu.patch b/queue-6.18/srcu-use-irq_work-to-start-gp-in-tiny-srcu.patch new file mode 100644 index 0000000000..8a654631a3 --- /dev/null +++ b/queue-6.18/srcu-use-irq_work-to-start-gp-in-tiny-srcu.patch @@ -0,0 +1,134 @@ +From 91c13adcefabbdfed2fc3a9f37ff329d8231d1ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:14:18 -0400 +Subject: srcu: Use irq_work to start GP in tiny SRCU + +From: Joel Fernandes + +[ Upstream commit a6fc88b22bc8d12ad52e8412c667ec0f5bf055af ] + +Tiny SRCU's srcu_gp_start_if_needed() directly calls schedule_work(), +which acquires the workqueue pool->lock. + +This causes a lockdep splat when call_srcu() is called with a scheduler +lock held, due to: + + call_srcu() [holding pi_lock] + srcu_gp_start_if_needed() + schedule_work() -> pool->lock + + workqueue_init() / create_worker() [holding pool->lock] + wake_up_process() -> try_to_wake_up() -> pi_lock + +Also add irq_work_sync() to cleanup_srcu_struct() to prevent a +use-after-free if a queued irq_work fires after cleanup begins. + +Tested with rcutorture SRCU-T and no lockdep warnings. + +[ Thanks to Boqun for similar fix in patch "rcu: Use an intermediate irq_work +to start process_srcu()" ] + +Signed-off-by: Joel Fernandes +Reviewed-by: Paul E. McKenney +Signed-off-by: Boqun Feng +Signed-off-by: Sasha Levin +--- + include/linux/srcutiny.h | 4 ++++ + kernel/rcu/srcutiny.c | 19 ++++++++++++++++++- + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/include/linux/srcutiny.h b/include/linux/srcutiny.h +index 51ce25f07930e..1f9a226e6fd81 100644 +--- a/include/linux/srcutiny.h ++++ b/include/linux/srcutiny.h +@@ -11,6 +11,7 @@ + #ifndef _LINUX_SRCU_TINY_H + #define _LINUX_SRCU_TINY_H + ++#include + #include + + struct srcu_struct { +@@ -24,18 +25,21 @@ struct srcu_struct { + struct rcu_head *srcu_cb_head; /* Pending callbacks: Head. */ + struct rcu_head **srcu_cb_tail; /* Pending callbacks: Tail. */ + struct work_struct srcu_work; /* For driving grace periods. */ ++ struct irq_work srcu_irq_work; /* Defer schedule_work() to irq work. */ + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; + #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + }; + + void srcu_drive_gp(struct work_struct *wp); ++void srcu_tiny_irq_work(struct irq_work *irq_work); + + #define __SRCU_STRUCT_INIT(name, __ignored, ___ignored) \ + { \ + .srcu_wq = __SWAIT_QUEUE_HEAD_INITIALIZER(name.srcu_wq), \ + .srcu_cb_tail = &name.srcu_cb_head, \ + .srcu_work = __WORK_INITIALIZER(name.srcu_work, srcu_drive_gp), \ ++ .srcu_irq_work = { .func = srcu_tiny_irq_work }, \ + __SRCU_DEP_MAP_INIT(name) \ + } + +diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c +index e3b64a5e0ec7e..d9c11d5f0ea45 100644 +--- a/kernel/rcu/srcutiny.c ++++ b/kernel/rcu/srcutiny.c +@@ -9,6 +9,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -41,6 +42,7 @@ static int init_srcu_struct_fields(struct srcu_struct *ssp) + ssp->srcu_idx_max = 0; + INIT_WORK(&ssp->srcu_work, srcu_drive_gp); + INIT_LIST_HEAD(&ssp->srcu_work.entry); ++ init_irq_work(&ssp->srcu_irq_work, srcu_tiny_irq_work); + return 0; + } + +@@ -84,6 +86,7 @@ EXPORT_SYMBOL_GPL(init_srcu_struct); + void cleanup_srcu_struct(struct srcu_struct *ssp) + { + WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]); ++ irq_work_sync(&ssp->srcu_irq_work); + flush_work(&ssp->srcu_work); + WARN_ON(ssp->srcu_gp_running); + WARN_ON(ssp->srcu_gp_waiting); +@@ -172,6 +175,20 @@ void srcu_drive_gp(struct work_struct *wp) + } + EXPORT_SYMBOL_GPL(srcu_drive_gp); + ++/* ++ * Use an irq_work to defer schedule_work() to avoid acquiring the workqueue ++ * pool->lock while the caller might hold scheduler locks, causing lockdep ++ * splats due to workqueue_init() doing a wakeup. ++ */ ++void srcu_tiny_irq_work(struct irq_work *irq_work) ++{ ++ struct srcu_struct *ssp; ++ ++ ssp = container_of(irq_work, struct srcu_struct, srcu_irq_work); ++ schedule_work(&ssp->srcu_work); ++} ++EXPORT_SYMBOL_GPL(srcu_tiny_irq_work); ++ + static void srcu_gp_start_if_needed(struct srcu_struct *ssp) + { + unsigned long cookie; +@@ -184,7 +201,7 @@ static void srcu_gp_start_if_needed(struct srcu_struct *ssp) + WRITE_ONCE(ssp->srcu_idx_max, cookie); + if (!READ_ONCE(ssp->srcu_gp_running)) { + if (likely(srcu_init_done)) +- schedule_work(&ssp->srcu_work); ++ irq_work_queue(&ssp->srcu_irq_work); + else if (list_empty(&ssp->srcu_work.entry)) + list_add(&ssp->srcu_work.entry, &srcu_boot_list); + } +-- +2.53.0 + diff --git a/queue-6.18/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-6.18/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..42ae6b9c4d --- /dev/null +++ b/queue-6.18/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From db606e2be69b4d9505c0f829c9aebfb352576e22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 207d578547cd9..b4883c365ba33 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -375,7 +375,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-6.18/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-6.18/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..c1e3175c84 --- /dev/null +++ b/queue-6.18/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From cc8831faf750ce134a2fdf47277bd745046c8a62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 965330eec80a8..d0b43d50b83ce 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-6.18/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-6.18/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..260236cccb --- /dev/null +++ b/queue-6.18/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From 7f05ccd83aff1ffb645a3516cf658b3761815093 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index ed773cd488769..c777895a720ee 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1149,7 +1149,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-6.18/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch b/queue-6.18/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch new file mode 100644 index 0000000000..ea89637a6b --- /dev/null +++ b/queue-6.18/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch @@ -0,0 +1,52 @@ +From 2a8f9f74b4d79418c42aeba2b0b3ab0e8936726f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 12:08:46 +0000 +Subject: tcp: Fix out-of-bounds access for twsk in tcp_ao_established_key(). + +From: Kuniyuki Iwashima + +[ Upstream commit 03cb001ef87b3f8d859cf7f96329acf3d6235d29 ] + +lockdep_sock_is_held() was added in tcp_ao_established_key() +by the cited commit. + +It can be called from tcp_v[46]_timewait_ack() with twsk. + +Since it does not have sk->sk_lock, the lockdep annotation +results in out-of-bound access. + + $ pahole -C tcp_timewait_sock vmlinux | grep size + /* size: 288, cachelines: 5, members: 8 */ + $ pahole -C sock vmlinux | grep sk_lock + socket_lock_t sk_lock; /* 440 192 */ + +Let's not use lockdep_sock_is_held() for TCP_TIME_WAIT. + +Fixes: 6b2d11e2d8fc ("net/tcp: Add missing lockdep annotations for TCP-AO hlist traversals") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260508120853.4098365-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_ao.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c +index 849a69c1f497f..aa624434b5556 100644 +--- a/net/ipv4/tcp_ao.c ++++ b/net/ipv4/tcp_ao.c +@@ -116,7 +116,8 @@ struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, + { + struct tcp_ao_key *key; + +- hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) { ++ hlist_for_each_entry_rcu(key, &ao->head, node, ++ sk_fullsock(sk) && lockdep_sock_is_held(sk)) { + if ((sndid >= 0 && key->sndid != sndid) || + (rcvid >= 0 && key->rcvid != rcvid)) + continue; +-- +2.53.0 + diff --git a/queue-6.18/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch b/queue-6.18/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch new file mode 100644 index 0000000000..11f8d1a335 --- /dev/null +++ b/queue-6.18/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch @@ -0,0 +1,48 @@ +From 30af9a96ef211d2eef917546fd5a4904e169f81a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 19:26:04 -0600 +Subject: tcp: use WRITE_ONCE() for tsoffset in tcp_v6_connect() + +From: Wesley Atwell + +[ Upstream commit dc9902bbd480aae510b885b67cd30cd04cfce3a8 ] + +Commit dd23c9f1e8d5 ("tcp: annotate data-races around tp->tsoffset") +updated do_tcp_getsockopt() to read tp->tsoffset with READ_ONCE() +for TCP_TIMESTAMP because another CPU may change it concurrently. + +tcp_v6_connect() still stores tp->tsoffset with a plain write. That +store runs under lock_sock() via inet_stream_connect(), but the socket +lock does not serialize a concurrent getsockopt(TCP_TIMESTAMP) from +another task sharing the socket. + +Use WRITE_ONCE() for the tcp_v6_connect() store so the connect-time +writer matches the lockless TCP_TIMESTAMP reader. This also makes the +IPv6 path consistent with tcp_v4_connect(). + +Signed-off-by: Wesley Atwell +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260310012604.145661-1-atwellwea@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/tcp_ipv6.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index 7f20db11e8ce9..1f020753b4202 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -325,7 +325,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + inet->inet_dport); + if (!tp->write_seq) + WRITE_ONCE(tp->write_seq, st.seq); +- tp->tsoffset = st.ts_off; ++ WRITE_ONCE(tp->tsoffset, st.ts_off); + } + + if (tcp_fastopen_defer_connect(sk, &err)) +-- +2.53.0 + diff --git a/queue-6.18/test_kprobes-clear-kprobes-between-test-runs.patch b/queue-6.18/test_kprobes-clear-kprobes-between-test-runs.patch new file mode 100644 index 0000000000..b18b854769 --- /dev/null +++ b/queue-6.18/test_kprobes-clear-kprobes-between-test-runs.patch @@ -0,0 +1,128 @@ +From feca44c43fb4512f583db44cf6c98e2150925ccc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: test_kprobes: clear kprobes between test runs + +From: Martin Kaiser + +[ Upstream commit ef5581bb30efb939cc2bf093475c6cc85258e5cd ] + +Running the kprobes sanity tests twice makes all tests fail and +eventually crashes the kernel. + +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # Totals: pass:5 fail:0 skip:0 total:5 + ok 1 kprobes_test +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # test_kprobe: EXPECTATION FAILED at lib/tests/test_kprobes.c:64 + Expected 0 == register_kprobe(&kp), but + register_kprobe(&kp) == -22 (0xffffffffffffffea) +... + Unable to handle kernel paging request ... + +The testsuite defines several kprobes and kretprobes as static variables +that are preserved across test runs. + +After register_kprobe and unregister_kprobe, a kprobe contains some +leftover data that must be cleared before the kprobe can be registered +again. The tests are setting symbol_name to define the probe location. +Address and flags must be cleared. + +The existing code clears some of the probes between subsequent tests, but +not between two test runs. The leftover data from a previous test run +makes the registrations fail in the next run. + +Move the cleanups for all kprobes into kprobes_test_init, this function +is called before each single test (including the first test of a test +run). + +Link: https://lore.kernel.org/all/20260507134615.1010905-1-martin@kaiser.cx/ + +Fixes: e44e81c5b90f ("kprobes: convert tests to kunit") +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + lib/tests/test_kprobes.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/lib/tests/test_kprobes.c b/lib/tests/test_kprobes.c +index b7582010125c3..06e729e4de051 100644 +--- a/lib/tests/test_kprobes.c ++++ b/lib/tests/test_kprobes.c +@@ -12,6 +12,12 @@ + + #define div_factor 3 + ++#define KP_CLEAR(_kp) \ ++do { \ ++ (_kp).addr = NULL; \ ++ (_kp).flags = 0; \ ++} while (0) ++ + static u32 rand1, preh_val, posth_val; + static u32 (*target)(u32 value); + static u32 (*recursed_target)(u32 value); +@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test) + + current_test = test; + +- /* addr and flags should be cleard for reusing kprobe. */ +- kp.addr = NULL; +- kp.flags = 0; +- + KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2)); + preh_val = 0; + posth_val = 0; +@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test) + struct kretprobe *rps[2] = {&rp, &rp2}; + + current_test = test; +- /* addr and flags should be cleard for reusing kprobe. */ +- rp.kp.addr = NULL; +- rp.kp.flags = 0; + KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2)); + + krph_val = 0; +@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test) + unsigned long myretaddr = (unsigned long)__builtin_return_address(0); + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + /* + * Run the stacktrace_driver() to record correct return address in +@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + struct kretprobe *rps[2] = {&rp3, &rp4}; + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + //KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver()); + +@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + + static int kprobes_test_init(struct kunit *test) + { ++ KP_CLEAR(kp); ++ KP_CLEAR(kp2); ++ KP_CLEAR(kp_missed); ++#ifdef CONFIG_KRETPROBES ++ KP_CLEAR(rp.kp); ++ KP_CLEAR(rp2.kp); ++#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE ++ KP_CLEAR(rp3.kp); ++ KP_CLEAR(rp4.kp); ++#endif ++#endif ++ + target = kprobe_target; + target2 = kprobe_target2; + recursed_target = kprobe_recursed_target; +-- +2.53.0 + diff --git a/queue-6.18/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch b/queue-6.18/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch new file mode 100644 index 0000000000..24a918bc7d --- /dev/null +++ b/queue-6.18/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch @@ -0,0 +1,53 @@ +From a78716991b01fc648f7131440be6ab64badcbe78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:25:57 -0800 +Subject: thunderbolt: Disable CLx on Titan Ridge-based devices with old + firmware + +From: Rene Sapiens + +[ Upstream commit 59b03d12b1f6d14d936a3ebec225f8d914dc3b70 ] + +Thunderbolt 3 devices based on Titan Ridge routers with NVM firmware +version < 0x65 have been observed to become unstable when CL states are +enabled. This can lead to link disconnect events and the device failing +to enumerate. + +Enable CLx on Titan Ridge only when the running NVM firmware version +is >= 0x65. + +Signed-off-by: Rene Sapiens +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +--- + drivers/thunderbolt/quirks.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c +index e81de9c30eac9..9f7914ac2f48c 100644 +--- a/drivers/thunderbolt/quirks.c ++++ b/drivers/thunderbolt/quirks.c +@@ -23,6 +23,9 @@ static void quirk_dp_credit_allocation(struct tb_switch *sw) + + static void quirk_clx_disable(struct tb_switch *sw) + { ++ if (tb_switch_is_titan_ridge(sw) && sw->nvm && sw->nvm->major >= 0x65) ++ return; ++ + sw->quirks |= QUIRK_NO_CLX; + tb_sw_dbg(sw, "disabling CL states\n"); + } +@@ -61,6 +64,10 @@ static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link }, + { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link }, ++ ++ /* Intel Titan Ridge CLx is unstable on early firmware versions */ ++ { 0x8086, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE, 0x0000, 0x0000, ++ quirk_clx_disable }, + /* + * Intel Goshen Ridge NVM 27 and before report wrong number of + * DP buffers. +-- +2.53.0 + diff --git a/queue-6.18/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-6.18/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..3ec96b1cf0 --- /dev/null +++ b/queue-6.18/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 421ea04f5b303751730b4e1dfed7a7814a18d6fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index a7d54dfd3c68b..08d7e4e2c2653 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1730,6 +1730,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1737,7 +1740,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-6.18/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-6.18/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..ecfb0c60cc --- /dev/null +++ b/queue-6.18/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From cd32b7651258dc55ebd61bb8d6e0c5eba7e56a1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 90e2ea1e8afe5..70b3ebbdcd3d3 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1442,9 +1442,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1567,8 +1567,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-6.18/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch b/queue-6.18/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch new file mode 100644 index 0000000000..f62fb6286e --- /dev/null +++ b/queue-6.18/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch @@ -0,0 +1,63 @@ +From 20ac49f255b346e09b898650d79c9373ac3b85d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 11:28:54 +0000 +Subject: tty: serial: samsung_tty: avoid dev_dbg deadlock + +From: Alyssa Milburn + +[ Upstream commit 43c2b86ff633c34831c8430925ba73d7c20da1ad ] + +commit a05025d0ce72 ("tty: serial: samsung_tty: use standard +debugging macros") changed the debug prints to dev_dbg, which can +result in deadlocks: + +s3c24xx_serial_set_termios can be called with the port lock, and then +calls dev_dbg, which needs the console mutex. At the same time, +s3c24xx_serial_console_write can be called with the console lock +(e.g., inside console_unlock), and needs the port lock. + +To avoid this, move one dev_dbg call and just delete the other. + +Signed-off-by: Alyssa Milburn +Link: https://patch.msgid.link/aXny9km6N1v9eoXU@zall.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/samsung_tty.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index 2fb58c626daf3..97178877f490e 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -1562,12 +1562,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + ulcon |= S3C2410_LCON_PNONE; + } + +- uart_port_lock_irqsave(port, &flags); +- + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", + ulcon, quot, udivslot); + ++ uart_port_lock_irqsave(port, &flags); ++ + wr_regl(port, S3C2410_ULCON, ulcon); + wr_regl(port, S3C2410_UBRDIV, quot); + +@@ -1587,12 +1587,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + if (ourport->info->has_divslot) + wr_regl(port, S3C2443_DIVSLOT, udivslot); + +- dev_dbg(port->dev, +- "uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", +- rd_regl(port, S3C2410_ULCON), +- rd_regl(port, S3C2410_UCON), +- rd_regl(port, S3C2410_UFCON)); +- + /* + * Update the per-port timeout. + */ +-- +2.53.0 + diff --git a/queue-6.18/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch b/queue-6.18/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch new file mode 100644 index 0000000000..9133f278e1 --- /dev/null +++ b/queue-6.18/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch @@ -0,0 +1,52 @@ +From 0b60f676346ce265d3c2f139ec5c3c2894fdb3f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 22:48:43 +0800 +Subject: ublk: reject max_sectors smaller than PAGE_SECTORS in parameter + validation + +From: Ming Lei + +[ Upstream commit 1860c2f85922917d8a46f16a6f4bd2298ffa0fb5 ] + +blk_validate_limits() requires max_hw_sectors >= PAGE_SECTORS and fires +a WARN_ON_ONCE if this invariant is violated. ublk_validate_params() +only checked the upper bound of max_sectors against max_io_buf_bytes, +allowing userspace to pass small values (including zero) that trigger +the warning when blk_mq_alloc_disk() is called from +ublk_ctrl_start_dev(). + +Before 494ea040bcb5, ublk used blk_queue_max_hw_sectors() which silently +clamped small values up to PAGE_SECTORS. The conversion to passing +queue_limits directly to blk_mq_alloc_disk() lost that clamping and now +hits blk_validate_limits()'s WARN_ON_ONCE instead. + +Validate that max_sectors is at least PAGE_SECTORS in +ublk_validate_params() so invalid values are rejected early with +-EINVAL instead of reaching the block layer. + +Fixes: 494ea040bcb5 ("ublk: pass queue_limits to blk_mq_alloc_disk") +Signed-off-by: Ming Lei +Link: https://patch.msgid.link/20260510144843.769031-1-tom.leiming@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 2729b1556e810..c339222513b03 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -601,6 +601,9 @@ static int ublk_validate_params(const struct ublk_device *ub) + if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9)) + return -EINVAL; + ++ if (p->max_sectors < PAGE_SECTORS) ++ return -EINVAL; ++ + if (ublk_dev_is_zoned(ub) && !p->chunk_sectors) + return -EINVAL; + } else +-- +2.53.0 + diff --git a/queue-6.18/um-avoid-struct-sigcontext-redefinition-with-musl.patch b/queue-6.18/um-avoid-struct-sigcontext-redefinition-with-musl.patch new file mode 100644 index 0000000000..e905de2814 --- /dev/null +++ b/queue-6.18/um-avoid-struct-sigcontext-redefinition-with-musl.patch @@ -0,0 +1,62 @@ +From 0593d2e9feb4c97609c78215c78ce9876bdb8bcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:28:03 +0800 +Subject: um: avoid struct sigcontext redefinition with musl + +From: Marcel W. Wysocki + +[ Upstream commit d46dfb369a4627d90efc2c2ffbe29e38e3e74286 ] + +mcontext.c includes both and . +With musl libc, this causes a struct sigcontext redefinition error: + + pulls in musl's , which defines + struct sigcontext directly. The kernel's then + provides a second, conflicting definition of the same struct. + +With glibc this does not conflict because glibc's signal headers +source their struct sigcontext from the kernel's own UAPI headers, +so the include guard in makes the second +inclusion a no-op. + +mcontext.c does not actually use struct sigcontext by name -- it +only needs the FP-state types (_fpstate, _xstate, etc.) that are +defined in independently of the sigcontext +struct. + +Temporarily rename sigcontext to __kernel_sigcontext during the +inclusion of so that the kernel's definition +does not collide with musl's. The #undef restores normal name +resolution immediately afterward. + +No functional change with glibc; fixes the build with musl. + +Signed-off-by: Marcel W. Wysocki +Link: https://patch.msgid.link/20260215142803.1455757-2-maci.stgn@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/x86/um/os-Linux/mcontext.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c +index a21403df66637..b1580df80b3fc 100644 +--- a/arch/x86/um/os-Linux/mcontext.c ++++ b/arch/x86/um/os-Linux/mcontext.c +@@ -4,7 +4,13 @@ + #include + #include + #include ++/* ++ * musl defines struct sigcontext in . Rename the kernel's ++ * copy to avoid redefinition while keeping the FP-state types available. ++ */ ++#define sigcontext __kernel_sigcontext + #include ++#undef sigcontext + #include + #include + #include +-- +2.53.0 + diff --git a/queue-6.18/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch b/queue-6.18/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch new file mode 100644 index 0000000000..55b86caa76 --- /dev/null +++ b/queue-6.18/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch @@ -0,0 +1,60 @@ +From 610f36a153f87e0258a32384f00151df9de88717 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:20:42 -0700 +Subject: um: Disable GCOV_PROFILE_ALL on 32-bit UML with Clang 20/21 + +From: Kees Cook + +[ Upstream commit 6522fe5c1b007c376fc5f2de1016c99a18b0af8e ] + +Clang 20 and 21 miscompute __builtin_object_size() when -fprofile-arcs +is active on 32-bit UML targets, which passes incorrect object size +calculations for local variables through always_inline copy_to_user() +and check_copy_size(), causing spurious compile-time errors: + + include/linux/ucopysize.h:52:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small + +The regression was introduced in LLVM commit 02b8ee281947 ("[llvm] +Improve llvm.objectsize computation by computing GEP, alloca and malloc +parameters bound"), which shipped in Clang 20. It was fixed in LLVM +by commit 45b697e610fd ("[MemoryBuiltins] Consider index type size +when aggregating gep offsets"), which was backported to the LLVM 22.x +release branch. + +The bug requires 32-bit UML + GCOV_PROFILE_ALL (which uses -fprofile-arcs), +though the exact trigger depends on optimizer decisions influenced by other +enabled configs. + +Prevent the bad combination by disabling UML's ARCH_HAS_GCOV_PROFILE_ALL +on 32-bit when using Clang 20.x or 21.x. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604030531.O6FveVgn-lkp@intel.com/ +Suggested-by: Nathan Chancellor +Assisted-by: Claude:claude-opus-4-6[1m] +Signed-off-by: Kees Cook +Link: https://patch.msgid.link/20260409052038.make.995-kees@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/Kconfig | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/um/Kconfig b/arch/um/Kconfig +index 93ed850d508ed..0c503ee18e29d 100644 +--- a/arch/um/Kconfig ++++ b/arch/um/Kconfig +@@ -11,7 +11,9 @@ config UML + select ARCH_HAS_CACHE_LINE_SIZE + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +- select ARCH_HAS_GCOV_PROFILE_ALL ++ # Clang 20 & 21 miscompute __builtin_object_size() under -fprofile-arcs ++ # on 32-bit, causing spurious compile-time errors in check_copy_size(). ++ select ARCH_HAS_GCOV_PROFILE_ALL if !(!64BIT && CLANG_VERSION >= 200000 && CLANG_VERSION < 220100) + select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER +-- +2.53.0 + diff --git a/queue-6.18/um-fix-address-of-cmsg_data-rvalue-in-stub.patch b/queue-6.18/um-fix-address-of-cmsg_data-rvalue-in-stub.patch new file mode 100644 index 0000000000..90563339cd --- /dev/null +++ b/queue-6.18/um-fix-address-of-cmsg_data-rvalue-in-stub.patch @@ -0,0 +1,66 @@ +From 982aa95327293007fcea9ce4412169400c7047c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:28:02 +0800 +Subject: um: fix address-of CMSG_DATA() rvalue in stub + +From: Marcel W. Wysocki + +[ Upstream commit 4076f7329832074196e050def49d22265fce2021 ] + +The UML stub takes the address of CMSG_DATA(fd_msg): + + fd_map = (void *)&CMSG_DATA(fd_msg); + +CMSG_DATA() is specified by POSIX to return unsigned char *. Taking +its address is semantically wrong -- the intent is to get a pointer +to the control message data, which is exactly what CMSG_DATA() +already returns. + +This happens to compile with glibc because glibc's primary +CMSG_DATA definition accesses a flexible array member: + + #define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data) + +An array lvalue can have its address taken, and &array yields the +same address as array. However, glibc also has an alternative +definition that uses pointer arithmetic (returning an rvalue), and +musl's definition always uses pointer arithmetic: + + /* musl */ + #define CMSG_DATA(cmsg) \ + ((unsigned char *)(((struct cmsghdr *)(cmsg)) + 1)) + +Taking the address of an rvalue is a hard error in C, so the +current code fails to compile with musl libc. + +Remove the erroneous & operator. The resulting code is correct +regardless of the CMSG_DATA implementation -- it simply assigns the +data pointer, which is what the subsequent code (fd_map[--num_fds]) +expects. + +No functional change with glibc; fixes the build with musl. + +Signed-off-by: Marcel W. Wysocki +Link: https://patch.msgid.link/20260215142803.1455757-1-maci.stgn@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/kernel/skas/stub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c +index 67cab46a602cf..e09216a20cb57 100644 +--- a/arch/um/kernel/skas/stub.c ++++ b/arch/um/kernel/skas/stub.c +@@ -146,7 +146,7 @@ stub_signal_interrupt(int sig, siginfo_t *info, void *p) + /* Receive the FDs */ + num_fds = 0; + fd_msg = msghdr.msg_control; +- fd_map = (void *)&CMSG_DATA(fd_msg); ++ fd_map = (void *)CMSG_DATA(fd_msg); + if (res == iov.iov_len && msghdr.msg_controllen > sizeof(struct cmsghdr)) + num_fds = (fd_msg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + +-- +2.53.0 + diff --git a/queue-6.18/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch b/queue-6.18/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch new file mode 100644 index 0000000000..4fd4734d5c --- /dev/null +++ b/queue-6.18/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch @@ -0,0 +1,155 @@ +From 71cb491e25731c0f2c9be1ca478f6a7975e08162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 13:14:52 +0100 +Subject: usb: dwc3: Support USB3340x ULPI PHY high-speed negotiation. + +From: Ingo Rohloff + +[ Upstream commit a28de63356575612954d4e5d5f48a2488f50e16d ] + +The Microchip USB3340x ULPI PHY requires a delay when switching to the +high-speed transmitter. See: + http://ww1.microchip.com/downloads/en/DeviceDoc/80000645A.pdf + Module 2 "Device Enumeration Failure with Link IP Systems" + +For details on the behavior and fix, refer to the AMD (formerly Xilinx) +forum post: "USB stuck in full speed mode with USB3340 ULPI PHY, ZynqMP." + +This patch uses the USB PHY Vendor-ID and Product-ID to detect the +USB3340 PHY and then applies the necessary fix if this PHY is found. + +Signed-off-by: Ingo Rohloff +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260305121452.54082-2-ingo.rohloff@lauterbach.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/core.c | 20 ++++++++++++++++++++ + drivers/usb/dwc3/core.h | 4 ++++ + drivers/usb/dwc3/ulpi.c | 25 +++++++++++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index a1f99c3b5f378..6fda6adbca18a 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -781,6 +781,24 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + return 0; + } + ++static void dwc3_ulpi_setup(struct dwc3 *dwc) ++{ ++ int index; ++ u32 reg; ++ ++ /* Don't do anything if there is no ULPI PHY */ ++ if (!dwc->ulpi) ++ return; ++ ++ if (dwc->enable_usb2_transceiver_delay) { ++ for (index = 0; index < dwc->num_usb2_ports; index++) { ++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); ++ reg |= DWC3_GUSB2PHYCFG_XCVRDLY; ++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); ++ } ++ } ++} ++ + /** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -1355,6 +1373,8 @@ static int dwc3_core_init(struct dwc3 *dwc) + dwc->ulpi_ready = true; + } + ++ dwc3_ulpi_setup(dwc); ++ + if (!dwc->phys_ready) { + ret = dwc3_core_get_phy(dwc); + if (ret) +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index a35b3db1f9f3e..a39bf284c763f 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -302,6 +302,7 @@ + #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) + #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) + #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) ++#define DWC3_GUSB2PHYCFG_XCVRDLY BIT(9) + #define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3) + #define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) + #define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10) +@@ -1161,6 +1162,8 @@ struct dwc3_glue_ops { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @enable_usb2_transceiver_delay: Set to insert a delay before the ++ * assertion of the TxValid signal during a HS Chirp. + * @sys_wakeup: set if the device may do system wakeup. + * @wakeup_configured: set if the device is configured for remote wakeup. + * @suspended: set to track suspend event due to U3/L2. +@@ -1403,6 +1406,7 @@ struct dwc3 { + unsigned dis_metastability_quirk:1; + + unsigned dis_split_quirk:1; ++ unsigned enable_usb2_transceiver_delay:1; + unsigned async_callbacks:1; + unsigned sys_wakeup:1; + unsigned wakeup_configured:1; +diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c +index 57daad15f502d..a256b7f5d78b4 100644 +--- a/drivers/usb/dwc3/ulpi.c ++++ b/drivers/usb/dwc3/ulpi.c +@@ -10,10 +10,13 @@ + #include + #include + #include ++#include + + #include "core.h" + #include "io.h" + ++#define USB_VENDOR_MICROCHIP 0x0424 ++ + #define DWC3_ULPI_ADDR(a) \ + ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \ + DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ +@@ -83,6 +86,26 @@ static const struct ulpi_ops dwc3_ulpi_ops = { + .write = dwc3_ulpi_write, + }; + ++static void dwc3_ulpi_detect_config(struct dwc3 *dwc) ++{ ++ struct ulpi *ulpi = dwc->ulpi; ++ ++ switch (ulpi->id.vendor) { ++ case USB_VENDOR_MICROCHIP: ++ switch (ulpi->id.product) { ++ case 0x0009: ++ /* Microchip USB3340 ULPI PHY */ ++ dwc->enable_usb2_transceiver_delay = true; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ + int dwc3_ulpi_init(struct dwc3 *dwc) + { + /* Register the interface */ +@@ -92,6 +115,8 @@ int dwc3_ulpi_init(struct dwc3 *dwc) + return PTR_ERR(dwc->ulpi); + } + ++ dwc3_ulpi_detect_config(dwc); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-6.18/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..daff9d2bd5 --- /dev/null +++ b/queue-6.18/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From da5715633761c6afa6468ec4ab25224ddc445d01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index f995cfa9b99e1..49baf24c77927 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-6.18/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-6.18/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..f0fa92899e --- /dev/null +++ b/queue-6.18/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From 0061d44783e0d62eb0da4591040097980b0ddb21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8f47a3b87871..f8d1d1167ef4b 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -674,7 +674,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -682,11 +682,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.18/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-6.18/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..9d3b9525b3 --- /dev/null +++ b/queue-6.18/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From 20d593d6a442ce61c42a1a605b0b3373df0dd791 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8d1d1167ef4b..a5837c0feb058 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -782,6 +782,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-6.18/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-6.18/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..c25e9298a2 --- /dev/null +++ b/queue-6.18/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From 28e1d89aa5eb8c391e0fbeba7a57d5e214c3638d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index ba9e7c616e129..f8f47a3b87871 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -677,7 +677,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -708,14 +708,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-6.18/virtiofs-add-fuse-protocol-validation.patch b/queue-6.18/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..4824e3f16a --- /dev/null +++ b/queue-6.18/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From 5ee4717bc9d95a276b96a8b74435cb3800a68ebb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index b2f6486fe1d56..8847d083ce57b 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -758,6 +758,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -767,10 +788,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct folio *folio; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -824,6 +841,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-6.18/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-6.18/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..0800bf2d26 --- /dev/null +++ b/queue-6.18/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From b0fddfd1d86056398903276f338b1476bc8467f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 0572f6a9bdb62..40522afc05320 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -2268,10 +2268,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-6.18/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch b/queue-6.18/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch new file mode 100644 index 0000000000..b9aac42967 --- /dev/null +++ b/queue-6.18/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch @@ -0,0 +1,109 @@ +From 70f16ee2273232825b8a70d9452a194e83864c8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 09:49:11 +0530 +Subject: wifi: ath12k: Fix the assignment of logical link index + +From: Manish Dharanenthiran + +[ Upstream commit aecb569d7fb689e3e5b0005ca7bd0a2ef28915e8 ] + +Per-link logical index is assigned from the global counter, +ahsta->num_peer. This logical index is sent to firmware during peer +association. If there is a failure in creating a link station, +ath12k_mac_free_unassign_link_sta() clears the link, but does not decrement +the logical link index. This will result in a higher logical link index for +the next link station created. Also, if there is a leak in logical link +index as we assign the incremented num_peer, then the index can exceed the +maximum valid value of 15. + +As an example, let's say we have a 2 GHz + 5 GHz + 6 GHz MLO setup. So the +logical link indices that they have are 0, 1 and 2, respectively. If the +5 GHz link is removed, logical link index 1 becomes available, and num_peer +is not reduced to 2 and still remains at 3. If a new 5 GHz link is added +later, it gets the index 3, instead of reusing link index 1. Also, +num_peer is increased to 4, though only 3 links are present. + +To resolve these, create a bitmap, free_logical_link_idx, that tracks the +available logical link indices. When a link station is created, select the +first free logical index and when a link station is removed, mark its +logical link index as available by setting the bit. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manish Dharanenthiran +Signed-off-by: Roopni Devanathan +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260226041911.2434999-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/core.h | 2 +- + drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++++++++-- + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h +index d7688b383f62c..44a76f8842833 100644 +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -589,7 +589,7 @@ struct ath12k_sta { + u16 links_map; + u8 assoc_link_id; + u16 ml_peer_id; +- u8 num_peer; ++ u16 free_logical_link_idx_map; + + enum ieee80211_sta_state state; + +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index b97469dca0467..97c6dee1945d9 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -6158,6 +6158,8 @@ static void ath12k_mac_free_unassign_link_sta(struct ath12k_hw *ah, + return; + + ahsta->links_map &= ~BIT(link_id); ++ ahsta->free_logical_link_idx_map |= BIT(arsta->link_idx); ++ + rcu_assign_pointer(ahsta->link[link_id], NULL); + synchronize_rcu(); + +@@ -6450,6 +6452,7 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta); + struct ieee80211_link_sta *link_sta; + struct ath12k_link_vif *arvif; ++ int link_idx; + + lockdep_assert_wiphy(ah->hw->wiphy); + +@@ -6468,8 +6471,16 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, + + ether_addr_copy(arsta->addr, link_sta->addr); + +- /* logical index of the link sta in order of creation */ +- arsta->link_idx = ahsta->num_peer++; ++ if (!ahsta->free_logical_link_idx_map) ++ return -ENOSPC; ++ ++ /* ++ * Allocate a logical link index by selecting the first available bit ++ * from the free logical index map ++ */ ++ link_idx = __ffs(ahsta->free_logical_link_idx_map); ++ ahsta->free_logical_link_idx_map &= ~BIT(link_idx); ++ arsta->link_idx = link_idx; + + arsta->link_id = link_id; + ahsta->links_map |= BIT(arsta->link_id); +@@ -6970,6 +6981,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, + if (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) { + memset(ahsta, 0, sizeof(*ahsta)); ++ ahsta->free_logical_link_idx_map = U16_MAX; + + arsta = &ahsta->deflink; + +-- +2.53.0 + diff --git a/queue-6.18/wifi-ath12k-set-up-mlo-after-ssr.patch b/queue-6.18/wifi-ath12k-set-up-mlo-after-ssr.patch new file mode 100644 index 0000000000..1b3fa3b3df --- /dev/null +++ b/queue-6.18/wifi-ath12k-set-up-mlo-after-ssr.patch @@ -0,0 +1,69 @@ +From 5b0eafa0d0c871a903e72958b96e99241bf96f69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:41:27 +0530 +Subject: wifi: ath12k: Set up MLO after SSR + +From: Ramya Gnanasekar + +[ Upstream commit f33a8e41826831fc8ceb5f62833488cd9388ed59 ] + +During recovery of an MLO setup from a core reset, +ATH12K_GROUP_FLAG_REGISTERED is set because ath12k_mac_unregister is not +called during core reset. So, when an MLO setup is recovering from a core +reset, ath12k_core_mlo_setup() is skipped. Hence, the firmware will not +have information about partner links. This makes MLO association fail +after recovery. + +To resolve this, call ath12k_core_mlo_setup() during recovery, to set up +MLO. Also, if MLO setup fails during recovery, call +ath12k_mac_unregister() and ath12k_mac_destroy() to unregister mac and +then tear down the mac structures. + +Also, initiate MLO teardown in the hardware group stop sequence to align +with the hardware group start sequence. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Ramya Gnanasekar +Signed-off-by: Roopni Devanathan +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260227041127.3265879-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c +index cc352eef19399..72c1e2da5a2bb 100644 +--- a/drivers/net/wireless/ath/ath12k/core.c ++++ b/drivers/net/wireless/ath/ath12k/core.c +@@ -996,6 +996,8 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag) + + ath12k_mac_unregister(ag); + ++ ath12k_mac_mlo_teardown(ag); ++ + for (i = ag->num_devices - 1; i >= 0; i--) { + ab = ag->ab[i]; + if (!ab) +@@ -1113,8 +1115,14 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag) + + lockdep_assert_held(&ag->mutex); + +- if (test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags)) ++ if (test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags)) { ++ ret = ath12k_core_mlo_setup(ag); ++ if (WARN_ON(ret)) { ++ ath12k_mac_unregister(ag); ++ goto err_mac_destroy; ++ } + goto core_pdev_create; ++ } + + ret = ath12k_mac_allocate(ag); + if (WARN_ON(ret)) +-- +2.53.0 + diff --git a/queue-6.18/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch b/queue-6.18/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch new file mode 100644 index 0000000000..1c424d8cd2 --- /dev/null +++ b/queue-6.18/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch @@ -0,0 +1,49 @@ +From 5d3df4bddfaa5dd41a68fc7f002d44e5c79801f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 09:37:32 +0530 +Subject: wifi: ath12k: Skip adding inactive partner vdev info + +From: Avula Sri Charan + +[ Upstream commit 7d7dc26f72abb7a76abb4a68ebad75d5ab7b375e ] + +Currently, a vdev that is created is considered active for partner link +population. In case of an MLD station, non-associated link vdevs can be +created but not started. Yet, they are added as partner links. This leads +to the creation of stale FW partner entries which accumulate and cause +assertions. + +To resolve this issue, check if the vdev is started and operating on a +chosen frequency, i.e., arvif->is_started, instead of checking if the vdev +is created, i.e., arvif->is_created. This determines if the vdev is active +or not and skips adding it as a partner link if it's inactive. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Avula Sri Charan +Signed-off-by: Roopni Devanathan +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260330040732.1847263-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index 97c6dee1945d9..2bc52097f26a3 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -10562,7 +10562,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif, + if (arvif == arvif_p) + continue; + +- if (!arvif_p->is_created) ++ if (!arvif_p->is_started) + continue; + + link_conf = wiphy_dereference(ahvif->ah->hw->wiphy, +-- +2.53.0 + diff --git a/queue-6.18/wifi-brcmfmac-of-defer-probe-for-mac-address.patch b/queue-6.18/wifi-brcmfmac-of-defer-probe-for-mac-address.patch new file mode 100644 index 0000000000..66acd34d6b --- /dev/null +++ b/queue-6.18/wifi-brcmfmac-of-defer-probe-for-mac-address.patch @@ -0,0 +1,39 @@ +From bd04bcbec7b93b844c2cff03214c32287eb2ec3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:27:39 -0800 +Subject: wifi: brcmfmac: of: defer probe for MAC address + +From: Rosen Penev + +[ Upstream commit 084863593243c5dce0f2eef44e23de8c53ebf4a2 ] + +of_get_mac_address can return EPROBE_DEFER if the specific nvmem driver +has not been loaded yet. + +Signed-off-by: Rosen Penev +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260220022739.41755-1-rosenp@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +index 1681ad00f82ec..03efae36a0b2d 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -128,7 +128,9 @@ int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + if (err) + brcmf_err("failed to get OF country code map (err=%d)\n", err); + +- of_get_mac_address(np, settings->mac); ++ err = of_get_mac_address(np, settings->mac); ++ if (err == -EPROBE_DEFER) ++ return err; + + if (bus_type != BRCMF_BUSTYPE_SDIO) + return 0; +-- +2.53.0 + diff --git a/queue-6.18/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch b/queue-6.18/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch new file mode 100644 index 0000000000..5b868d1297 --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch @@ -0,0 +1,58 @@ +From 60161f6cc4bbf928d860c57f2d76effee58493aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 19:29:14 +0200 +Subject: wifi: iwlwifi: mld: always assign a fw id to a vif + +From: Miri Korenblit + +[ Upstream commit 4f1da5cf31cf6345f145e914a0158c2e114bbe27 ] + +We used to have a fw id assignment in iwl_mld_init_vif since all interface +types that were added to the driver was immediately added to the FW as +well. +Since NAN was introduced, this is no longer the case - the NAN interface +is not added to the fw until a local schedule is configured. + +For this vif we don't assign a fw id so it is 0 by default. +But later, when the vif is removed from the driver, we think that it has +a valid fw id (0) and we point fw_id_to_vif[0] to NULL. +fw_id_to_vif[0] might actually point to another vif with a valid fw id +0. In this case, we end up messing fw_id_to_vif. + +Fix this by initializing a vif with a special invalid fw id, and by +exiting iwl_mld_rm_vif early for NAN interfaces. + +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260321192637.f3b5cc59098f.I3d1dbe66bd224cbb786c2b0ab3d1c9f7ec9003e4@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mld/iface.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c +index 80bcd18930c57..5a8c583134334 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c +@@ -431,6 +431,7 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) + lockdep_assert_wiphy(mld->wiphy); + + mld_vif->mld = mld; ++ mld_vif->fw_id = IWL_MLD_INVALID_FW_ID; + mld_vif->roc_activity = ROC_NUM_ACTIVITIES; + + ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); +@@ -478,6 +479,10 @@ void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) + + lockdep_assert_wiphy(mld->wiphy); + ++ /* NAN interface type is not known to FW */ ++ if (vif->type == NL80211_IFTYPE_NAN) ++ return; ++ + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); + + if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) +-- +2.53.0 + diff --git a/queue-6.18/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch b/queue-6.18/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch new file mode 100644 index 0000000000..de66c900ea --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch @@ -0,0 +1,45 @@ +From 20d6ab3540ef267424b1aa29bf1c8380385e88db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:43 +0200 +Subject: wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending + +From: Emmanuel Grumbach + +[ Upstream commit 5562b3bbeede8be25092064720e4a942e9fd3e3e ] + +Otherwise we may send garbage. + +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.2d494b0f4692.I9afd0fa6b2ea5a27118144ac4e3bbbedc2089c10@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index aa517978fc7a3..047f1de3915a7 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -916,7 +916,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) + + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + { +- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; ++ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; + struct iwl_geo_tx_power_profiles_resp *resp; + u16 len; + int ret; +@@ -968,7 +968,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) + { + u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); +- union iwl_geo_tx_power_profiles_cmd cmd; ++ union iwl_geo_tx_power_profiles_cmd cmd = {}; + u16 len; + u32 n_bands; + u32 n_profiles; +-- +2.53.0 + diff --git a/queue-6.18/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch b/queue-6.18/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch new file mode 100644 index 0000000000..fc8d41cacc --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch @@ -0,0 +1,72 @@ +From 49f6e38f98447beb3175e158171a785889dbbc78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 10:09:16 +0200 +Subject: wifi: iwlwifi: pcie: don't dump on reset handshake in dump + +From: Johannes Berg + +[ Upstream commit 4a481720106d6bad1521d0e0322fd74fa2f6c464 ] + +When a FW dump happens, possibly even because of a reset handshake +timeout, there's no point in attempting to dump again. Since all the +callers of the function outside the transport itself are from the FW +dump infrastructure, just split the internal function and make the +external one not dump on timeout. + +Signed-off-by: Johannes Berg +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260320100746.f36ba3893899.I063ccc3a037ae6dabcde61941acb162c4b33f127@changeid +Signed-off-by: Sasha Levin +--- + .../wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +index b15c5d4865277..a50e845cea421 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +@@ -95,7 +95,9 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + } + +-void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) ++static void ++_iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans, ++ bool dump_on_timeout) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; +@@ -133,7 +135,7 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) + "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n", + inta_hw, reset_done); + +- if (!reset_done) { ++ if (!reset_done && dump_on_timeout) { + struct iwl_fw_error_dump_mode mode = { + .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT, + .context = IWL_ERR_CONTEXT_FROM_OPMODE, +@@ -147,6 +149,11 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) + trans_pcie->fw_reset_state = FW_RESET_IDLE; + } + ++void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) ++{ ++ _iwl_trans_pcie_fw_reset_handshake(trans, false); ++} ++ + static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +@@ -163,7 +170,7 @@ static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) + * should assume that the firmware is already dead. + */ + trans->state = IWL_TRANS_NO_FW; +- iwl_trans_pcie_fw_reset_handshake(trans); ++ _iwl_trans_pcie_fw_reset_handshake(trans, true); + } + + trans_pcie->is_down = true; +-- +2.53.0 + diff --git a/queue-6.18/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch b/queue-6.18/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch new file mode 100644 index 0000000000..d0be33c5fc --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch @@ -0,0 +1,98 @@ +From 2b93c1a3533925c4eb455e6d68410021a099a7e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:42 +0200 +Subject: wifi: iwlwifi: restrict TOP reset to some devices + +From: Johannes Berg + +[ Upstream commit f473f609164ee9907497ac55934689110c248e23 ] + +Due to the Bluetooth implementation needing to match, not all +devices can actually do TOP reset. Restrict it to Sc2/Sc2f or +later, with Wh RF or later. + +Signed-off-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.6c4479f4e49d.I5023d70cb33f1e18f7cb15981fc3acfbb00862b7@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 10 +++++----- + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 18 ++++++++++++++++++ + .../wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 2 +- + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +index 5232f66c2d52a..c67b00511764b 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +@@ -138,7 +138,7 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) + IWL_RESET_MODE_FUNC_RESET, + IWL_RESET_MODE_PROD_RESET, + }; +- static const enum iwl_reset_mode escalation_list_sc[] = { ++ static const enum iwl_reset_mode escalation_list_top[] = { + IWL_RESET_MODE_SW_RESET, + IWL_RESET_MODE_REPROBE, + IWL_RESET_MODE_REPROBE, +@@ -159,14 +159,14 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) + + if (trans->request_top_reset) { + trans->request_top_reset = 0; +- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) ++ if (iwl_trans_is_top_reset_supported(trans)) + return IWL_RESET_MODE_TOP_RESET; + return IWL_RESET_MODE_PROD_RESET; + } + +- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { +- escalation_list = escalation_list_sc; +- escalation_list_size = ARRAY_SIZE(escalation_list_sc); ++ if (iwl_trans_is_top_reset_supported(trans)) { ++ escalation_list = escalation_list_top; ++ escalation_list_size = ARRAY_SIZE(escalation_list_top); + } else { + escalation_list = escalation_list_old; + escalation_list_size = ARRAY_SIZE(escalation_list_old); +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +index a552669db6e2a..2eaa099daf611 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +@@ -1262,4 +1262,22 @@ bool iwl_trans_is_pm_supported(struct iwl_trans *trans); + + bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); + ++static inline bool iwl_trans_is_top_reset_supported(struct iwl_trans *trans) ++{ ++ /* not supported before Sc family */ ++ if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) ++ return false; ++ ++ /* for Sc family only supported for Sc2/Sc2f */ ++ if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC && ++ CSR_HW_REV_TYPE(trans->info.hw_rev) == IWL_CFG_MAC_TYPE_SC) ++ return false; ++ ++ /* so far these numbers are increasing - not before Pe */ ++ if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) < IWL_CFG_RF_TYPE_PE) ++ return false; ++ ++ return true; ++} ++ + #endif /* __iwl_trans_h__ */ +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +index 59307b5df4417..91bdf2863ddf8 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +@@ -3197,7 +3197,7 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file, + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + return -EINVAL; + if (mode == IWL_RESET_MODE_TOP_RESET) { +- if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) ++ if (!iwl_trans_is_top_reset_supported(trans)) + return -EINVAL; + trans->request_top_reset = 1; + } +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch b/queue-6.18/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch new file mode 100644 index 0000000000..9149d65e91 --- /dev/null +++ b/queue-6.18/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch @@ -0,0 +1,64 @@ +From 70bf21c102dc1c3b150c7637abe6edbad965140c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 14:13:46 +0200 +Subject: wifi: mac80211: properly handle error in + ieee80211_add_virtual_monitor + +From: Miri Korenblit + +[ Upstream commit 876565d4a826f3f04ef36f1cef6123ed4b150aa3 ] + +In case of an error in ieee80211_add_virtual_monitor, +SDATA_STATE_RUNNING should be cleared as it was set in this function. +Do it there instead of in the error path of ieee80211_do_open. + +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260320141312.5546126313b1.I689dba2f54069b259702e8d246cedf79a73b82c6@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/iface.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 72c129478da08..191bc715bd98c 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1216,14 +1216,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) + } + } + +- set_bit(SDATA_STATE_RUNNING, &sdata->state); +- + ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); + if (ret) { + kfree(sdata); + return ret; + } + ++ set_bit(SDATA_STATE_RUNNING, &sdata->state); ++ + mutex_lock(&local->iflist_mtx); + rcu_assign_pointer(local->monitor_sdata, sdata); + mutex_unlock(&local->iflist_mtx); +@@ -1236,6 +1236,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) + mutex_unlock(&local->iflist_mtx); + synchronize_net(); + drv_remove_interface(local, sdata); ++ clear_bit(SDATA_STATE_RUNNING, &sdata->state); + kfree(sdata); + return ret; + } +@@ -1516,8 +1517,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) + sdata->bss = NULL; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + list_del(&sdata->u.vlan.list); +- /* might already be clear but that doesn't matter */ +- clear_bit(SDATA_STATE_RUNNING, &sdata->state); + return res; + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch b/queue-6.18/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch new file mode 100644 index 0000000000..add2af64be --- /dev/null +++ b/queue-6.18/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch @@ -0,0 +1,53 @@ +From b936b9405c91925d99ac421fe70b32ab5613dc14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:28:28 +0100 +Subject: wifi: mac80211: Remove deleted sta links in + ieee80211_ml_reconf_work() + +From: Lorenzo Bianconi + +[ Upstream commit 84674b03d8bf3a850f023a98136c27909f0a2b61 ] + +Delete stale station links announced in the reconfiguration IE +transmitted by the AP in the beacon frames. + +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260309-mac80211-reconf-remove-sta-link-v2-1-1582aac720c6@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index bcc4090ddc1a5..d3431c2d804fc 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -6894,6 +6894,7 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + container_of(work, struct ieee80211_sub_if_data, + u.mgd.ml_reconf_work.work); + u16 new_valid_links, new_active_links, new_dormant_links; ++ struct sta_info *sta; + int ret; + + if (!sdata->u.mgd.removed_links) +@@ -6929,6 +6930,16 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + } + } + ++ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); ++ if (sta) { ++ unsigned long removed_links = sdata->u.mgd.removed_links; ++ unsigned int link_id; ++ ++ for_each_set_bit(link_id, &removed_links, ++ IEEE80211_MLD_MAX_NUM_LINKS) ++ ieee80211_sta_free_link(sta, link_id); ++ } ++ + new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links; + + ret = ieee80211_vif_set_links(sdata, new_valid_links, +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-set-band-information-only-for-non-mld-.patch b/queue-6.18/wifi-mac80211-set-band-information-only-for-non-mld-.patch new file mode 100644 index 0000000000..c44cd743c1 --- /dev/null +++ b/queue-6.18/wifi-mac80211-set-band-information-only-for-non-mld-.patch @@ -0,0 +1,78 @@ +From a81b5502b94c69377276740d61993828d60e66aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 15:31:25 +0530 +Subject: wifi: mac80211: set band information only for non-MLD when probing + stations using NULL frame + +From: Suraj P Kizhakkethil + +[ Upstream commit 73e7df69edb6f1271ea0fa876794761e6c73e76a ] + +Currently, when sending a NULL frame to probe a station, the band +information is derived from the chanctx_conf in the mac80211 vif's +bss_conf. However, for AP MLD, chanctx_conf is not assigned to the +vif's bss_conf; instead it is assigned on a per-link basis. As a result, +for AP MLD, sending a NULL packet to probe will trigger a warning. + +WARNING: net/mac80211/cfg.c:4635 at ieee80211_probe_client+0x1a8/0x1d8 [mac80211], CPU#2: hostapd/244 +Call trace: + ieee80211_probe_client+0x1a8/0x1d8 [mac80211] (P) + nl80211_probe_client+0xac/0x170 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + genl_rcv_msg+0x200/0x280 + netlink_rcv_skb+0x38/0xf0 + genl_rcv+0x34/0x48 + netlink_unicast+0x314/0x3a0 + netlink_sendmsg+0x150/0x390 + ____sys_sendmsg+0x1f4/0x21c + ___sys_sendmsg+0x98/0xc0 + __sys_sendmsg+0x74/0xcc + __arm64_sys_sendmsg+0x20/0x34 + invoke_syscall.constprop.0+0x4c/0xd0 + do_el0_svc+0x3c/0xd0 + el0_svc+0x28/0xc0 + el0t_64_sync_handler+0x98/0xdc + el0t_64_sync+0x154/0x158 +---[ end trace 0000000000000000 ]--- + +For NULL packets sent to probe stations, set the band information only +for non-MLD, since MLD transmissions does not rely on band. + +Signed-off-by: Suraj P Kizhakkethil +Link: https://patch.msgid.link/20260213100126.1414398-2-suraj.kizhakkethil@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/cfg.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index d32eacbb7517d..14769da9a14c7 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4582,12 +4582,17 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, + + qos = sta->sta.wme; + +- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- ret = -EINVAL; +- goto unlock; ++ if (ieee80211_vif_is_mld(&sdata->vif)) { ++ /* MLD transmissions must not rely on the band */ ++ band = 0; ++ } else { ++ chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ ret = -EINVAL; ++ goto unlock; ++ } ++ band = chanctx_conf->def.chan->band; + } +- band = chanctx_conf->def.chan->band; + + if (qos) { + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch b/queue-6.18/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch new file mode 100644 index 0000000000..b58e4f6c82 --- /dev/null +++ b/queue-6.18/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch @@ -0,0 +1,51 @@ +From 44dfd89d39966edbd291cc775d1b45f45746d92b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:17:22 +0530 +Subject: wifi: mac80211: use ap_addr for 4-address NULL frame destination + +From: Tamizh Chelvam Raja + +[ Upstream commit 594be50a3f0a6b7389f40f7acbf0dd731beb5204 ] + +Currently ieee80211_send_4addr_nullfunc() uses deflink.u.mgd.bssid +for addr1 and addr3 fields. In MLO configurations, deflink.u.mgd.bssid +represents link 0's BSSID and is not updated when link 0 is not an +assoc link. This causes 4-address NULL frames to be sent to the +wrong address, preventing WDS AP_VLAN interface creation on the peer AP. + +To fix this use sdata->vif.cfg.ap_addr instead, which contains the AP's MLD +address populated during authentication/association and remains +valid regardless of which links are active. + +This ensures 4-address NULL frames reach the correct AP, allowing +proper WDS operation over MLO connections. + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Tamizh Chelvam Raja +Link: https://patch.msgid.link/20260326164723.553927-3-tamizh.raja@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index d3431c2d804fc..aadef1888f298 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2411,9 +2411,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; +- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-abort-roc-on-chanctx-changes.patch b/queue-6.18/wifi-mt76-abort-roc-on-chanctx-changes.patch new file mode 100644 index 0000000000..bcc09f80d2 --- /dev/null +++ b/queue-6.18/wifi-mt76-abort-roc-on-chanctx-changes.patch @@ -0,0 +1,41 @@ +From f8302ca95795150f64b200abf72a6dc3b33ceede Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:24 +0000 +Subject: wifi: mt76: abort ROC on chanctx changes + +From: Felix Fietkau + +[ Upstream commit de62b24224ac1533c17b3d5bae77164a82ae2e49 ] + +mt76_change_chanctx() calls mt76_phy_update_channel() which switches +the hardware channel. If ROC is active on the same phy, this switches +away from the ROC channel and clears offchannel, but leaves ROC state +intact. Mac80211 still thinks the phy is on the ROC channel. + +Abort any active ROC before proceeding, matching the pattern already +used in add, remove, assign, unassign, and switch chanctx functions. + +Link: https://patch.msgid.link/20260309060730.87840-5-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/channel.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c +index eccaee1fd434f..b0be0a3904878 100644 +--- a/drivers/net/wireless/mediatek/mt76/channel.c ++++ b/drivers/net/wireless/mediatek/mt76/channel.c +@@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw, + IEEE80211_CHANCTX_CHANGE_RADAR))) + return; + ++ if (phy->roc_vif) ++ mt76_abort_roc(phy); ++ + cancel_delayed_work_sync(&phy->mac_work); + + mutex_lock(&dev->mutex); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch b/queue-6.18/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch new file mode 100644 index 0000000000..afbd593e8b --- /dev/null +++ b/queue-6.18/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch @@ -0,0 +1,51 @@ +From bf9d631e852b928345299629fd45a8b42fea24cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 03:52:10 +0000 +Subject: wifi: mt76: add missing lock protection in mt76_sta_state for + sta_event callback + +From: Ziyi Guo + +[ Upstream commit f0168f2f9a1eca55d3ae09d8250b94e82b67cac3 ] + +mt76_sta_state() calls the sta_event callback without holding dev->mutex. +However, mt7915_mac_sta_event() (MT7915 implementation of this callback) +calls mt7915_mac_twt_teardown_flow() which has +lockdep_assert_held(&dev->mt76.mutex) indicating that callers must +hold this lock. + +The locking pattern in mt76_sta_state() is inconsistent: +- mt76_sta_add() acquires dev->mutex before calling dev->drv->sta_add +- mt76_sta_remove() acquires dev->mutex before calling __mt76_sta_remove +- But sta_event callback is called without acquiring the lock + +Add mutex_lock()/mutex_unlock() around the mt7915_mac_twt_teardown_flow +invocation to fix the missing lock protection and maintain consistency +with the existing locking pattern. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260131035210.2198259-1-n7l8m4@u.northwestern.edu +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index 6f594677474b0..5da90c5e2f034 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -852,8 +852,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); + + case MT76_STA_EVENT_DISASSOC: ++ mutex_lock(&dev->mt76.mutex); + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); ++ mutex_unlock(&dev->mt76.mutex); + + mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch b/queue-6.18/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch new file mode 100644 index 0000000000..8c1832b66d --- /dev/null +++ b/queue-6.18/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch @@ -0,0 +1,79 @@ +From 1f1613390a466d13b509174ecc52a0a700c6381d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 00:23:20 +0100 +Subject: wifi: mt76: don't return TXQ when exceeding max non-AQL packets + +From: David Bauer + +[ Upstream commit 964f870e090e9c88a41e2890333421204cc0bdf4 ] + +mt76_txq_send_burst does check if the number of non-AQL frames exceeds +the maximum. In this case the queue is returned to ieee80211_return_txq +when iterating over the scheduled TXQs in mt76_txq_schedule_list. + +This has the effect of inserting said TXQ at the head of the list. This +means the loop will get the same TXQ again, which will terminate the +scheduling round. TXQs following in the list thus never get scheduled +for transmission. + +This can manifest in high latency low throughput or broken connections +for said STAs. + +Check if the non-AQL packet count exceeds the limit and not return the +TXQ in this case. +Schedule all TXQs for the STA in case the non-AQL limit can be satisfied +again. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20260129232321.276575-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/tx.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index b78ae6a34b658..9a4ac31d93dc2 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -227,7 +227,9 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + struct sk_buff *skb) + { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_sta *sta; + int pending; ++ int i; + + if (!wcid || info->tx_time_est) + return; +@@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); ++ ++ sta = wcid_to_sta(wcid); ++ if (!sta || pending != MT_MAX_NON_AQL_PKT - 1) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { ++ if (!sta->txq[i]) ++ continue; ++ ++ ieee80211_schedule_txq(dev->hw, sta->txq[i]); ++ } + } + + void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, +@@ -542,6 +555,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) + if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) + continue; + ++ if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) ++ continue; ++ + phy = mt76_dev_phy(dev, wcid->phy_idx); + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + continue; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch b/queue-6.18/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch new file mode 100644 index 0000000000..8ca6962d05 --- /dev/null +++ b/queue-6.18/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch @@ -0,0 +1,54 @@ +From bb46f6cd22034e08e724c33ce3bbf12dea9c95fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:10:32 -0800 +Subject: wifi: mt76: fix list corruption in mt76_wcid_cleanup + +From: Zac Bowling + +[ Upstream commit 34163942195410372fb138bea806c9b34e2f5257 ] + +mt76_wcid_cleanup() was not removing wcid entries from sta_poll_list +before mt76_reset_device() reinitializes the master list. This leaves +stale pointers in wcid->poll_list, causing list corruption when +mt76_wcid_add_poll() later checks list_empty() and tries to add the +entry back. + +The fix adds proper cleanup of poll_list in mt76_wcid_cleanup(), +matching how tx_list is already handled. This is similar to what +mt7996_mac_sta_deinit_link() already does correctly. + +Fixes list corruption warnings like: + list_add corruption. prev->next should be next (ffffffff...) + +Signed-off-by: Zac Bowling +Link: https://patch.msgid.link/20260120201043.38225-3-zac@zacbowling.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 76eb740428b8d..bfa4b25765a16 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1713,6 +1713,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) + + idr_destroy(&wcid->pktid); + ++ /* Remove from sta_poll_list to prevent list corruption after reset. ++ * Without this, mt76_reset_device() reinitializes sta_poll_list but ++ * leaves wcid->poll_list with stale pointers, causing list corruption ++ * when mt76_wcid_add_poll() checks list_empty(). ++ */ ++ spin_lock_bh(&dev->sta_poll_lock); ++ if (!list_empty(&wcid->poll_list)) ++ list_del_init(&wcid->poll_list); ++ spin_unlock_bh(&dev->sta_poll_lock); ++ + spin_lock_bh(&phy->tx_lock); + + if (!list_empty(&wcid->tx_list)) +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-flush-pending-tx-before-channel-switch.patch b/queue-6.18/wifi-mt76-flush-pending-tx-before-channel-switch.patch new file mode 100644 index 0000000000..2cdc796842 --- /dev/null +++ b/queue-6.18/wifi-mt76-flush-pending-tx-before-channel-switch.patch @@ -0,0 +1,74 @@ +From 633dd253af74c360d3795939489685df1ae5af0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:27 +0000 +Subject: wifi: mt76: flush pending TX before channel switch + +From: Felix Fietkau + +[ Upstream commit 0dcef1cbae27d806cd29c296cc03ad6e8ece771d ] + +mt76_tx() queues frames on wcid->tx_pending for async processing by +tx_worker. In __mt76_set_channel(), the worker gets disabled before it +may have run, and the subsequent wait only checks DMA ring queues, not +the software pending list. This means frames like nullfunc PS frames +from mt76_offchannel_notify() may never be transmitted on the correct +channel. + +Fix this by running mt76_txq_schedule_pending() synchronously after +disabling the tx_worker but before setting MT76_RESET, which would +otherwise cause mt76_txq_schedule_pending_wcid() to bail out. + +Link: https://patch.msgid.link/20260309060730.87840-8-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++-- + drivers/net/wireless/mediatek/mt76/mt76.h | 1 + + drivers/net/wireless/mediatek/mt76/tx.c | 2 +- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index bfa4b25765a16..dad0ea6ec26b3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1028,9 +1028,10 @@ int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + int timeout = HZ / 5; + int ret; + +- set_bit(MT76_RESET, &phy->state); +- + mt76_worker_disable(&dev->tx_worker); ++ mt76_txq_schedule_pending(phy); ++ ++ set_bit(MT76_RESET, &phy->state); + wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); + mt76_update_survey(phy); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 125ac1eb2d541..85653c4c5d882 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -1496,6 +1496,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, + void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); + void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); + void mt76_txq_schedule_all(struct mt76_phy *phy); ++void mt76_txq_schedule_pending(struct mt76_phy *phy); + void mt76_tx_worker_run(struct mt76_dev *dev); + void mt76_tx_worker(struct mt76_worker *w); + void mt76_release_buffered_frames(struct ieee80211_hw *hw, +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 9a4ac31d93dc2..a7102c30fbf4a 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -660,7 +660,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, + return ret; + } + +-static void mt76_txq_schedule_pending(struct mt76_phy *phy) ++void mt76_txq_schedule_pending(struct mt76_phy *phy) + { + LIST_HEAD(tx_list); + int ret = 0; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-6.18/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..25b430d78a --- /dev/null +++ b/queue-6.18/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From ec517d6b0e0051a66605807acad2263a8a8dd8fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index a683d53c7ceb8..1ccb6b300a906 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch b/queue-6.18/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch new file mode 100644 index 0000000000..f4a987c6ba --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch @@ -0,0 +1,42 @@ +From 6ef96c3c65c38aae92bc8fb8ce47e4ddd3971a1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 17:22:30 -0600 +Subject: wifi: mt76: mt7925: resolve link after acquiring mt76 mutex + +From: Sean Wang + +[ Upstream commit beec58f36983f826fe90287a90edff46b32e8a89 ] + +mt792x_sta_to_link() uses rcu_dereference_protected() and therefore +expects mt76.mutex to be held. Move the lookup after +mt792x_mutex_acquire() to make the locking explicit and correct. + +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20260306232238.2039675-12-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 1894b2f607d92..d4b62d8c3043d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1029,11 +1029,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + ++ mt792x_mutex_acquire(dev); ++ + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + +- mt792x_mutex_acquire(dev); +- + if (ieee80211_vif_is_mld(vif)) { + link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); + } else { +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch b/queue-6.18/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch new file mode 100644 index 0000000000..a9a3e711e2 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch @@ -0,0 +1,49 @@ +From a17d6134191d5834d21be7b234208eae1743fc86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 19:40:07 +0800 +Subject: wifi: mt76: mt7925: Skip scan process during suspend. + +From: Michael Lo + +[ Upstream commit 8c7e19612b01567f641d3ffe21e47fa21c331171 ] + +We are experiencing command timeouts because an upper layer triggers +an unexpected scan while the system/device is in suspend. +The upper layer should not initiate scans until the NIC has fully resumed. +We want to prevent scans during suspend and avoid timeouts without harming +power management or user experience. + +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260112114007.2115873-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 00126f563dfd9..1894b2f607d92 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1336,10 +1336,18 @@ static bool is_valid_alpha2(const char *alpha2) + void mt7925_scan_work(struct work_struct *work) + { + struct mt792x_phy *phy; ++ struct mt792x_dev *dev; ++ struct mt76_connac_pm *pm; + + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + scan_work.work); + ++ dev = phy->dev; ++ pm = &dev->pm; ++ ++ if (pm->suspended) ++ return; ++ + while (true) { + struct mt76_dev *mdev = &phy->dev->mt76; + struct sk_buff *skb; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch b/queue-6.18/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch new file mode 100644 index 0000000000..f30966df6c --- /dev/null +++ b/queue-6.18/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch @@ -0,0 +1,49 @@ +From d06758b0d945e7f86f07928851a57e58d27147aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:22:31 +0800 +Subject: wifi: mt76: mt792x: Fix a potential deadlock in high-load situations + +From: Leon Yen + +[ Upstream commit bb2f07819d063a58756186cac6465341956ac0a4 ] + +A deadlock may occur between two works, ps_work and mac_work, if their work +functions run simultaneously as they attempt to cancel each other by +calling cancel_delayed_work_sync(). + +mt792x_mac_work() -> ... -> cancel_delayed_work_sync(&pm->ps_work); +mt792x_pm_power_save_work() -> cancel_delayed_work_sync(&mphy->mac_work); + +In high-load situations, they are queued but may not have chance to be +executed until the CPUs are released. Once the CPUs are available, there +is a high possibility that the ps_work function and mac_work function will +be executed simultaneously, resulting in a possible deadlock. + +This patch replaces cancel_delayed_work_sync() with cancel_delayed_work() +in ps_work to eliminate the deadlock and make the code easier to maintain. + +Signed-off-by: Leon Yen +Tested-by: Chia-Lin Kao (AceLan) +Link: https://patch.msgid.link/20251215122231.3180648-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +index 3f1d9ba49076f..1e7a3108770c3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +@@ -375,7 +375,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) + } + + if (!mt792x_mcu_fw_pmctrl(dev)) { +- cancel_delayed_work_sync(&mphy->mac_work); ++ cancel_delayed_work(&mphy->mac_work); + return; + } + out: +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch b/queue-6.18/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch new file mode 100644 index 0000000000..6c87fa9b46 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch @@ -0,0 +1,50 @@ +From 8ac4b3874f99a84cef6c6a87aa5976940c0c8f1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 00:00:29 -0800 +Subject: wifi: mt76: mt7996: Disable Rx hdr_trans in monitor mode + +From: Ryder Lee + +[ Upstream commit 947d63d8cd3b03c7be16875ca90273edbdbe7ce5 ] + +Ensure raw frames are captured without header modification. + +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/04008426d6cd5de3995beefb98f9d13f35526c25.1770969275.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 ++ + drivers/net/wireless/mediatek/mt76/mt7996/regs.h | 3 +++ + 2 files changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index d714b7f3efe56..a96db82890af8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -482,6 +482,8 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) + + mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), + MT_DMA_DCR0_RXD_G5_EN, enabled); ++ mt76_rmw_field(dev, MT_MDP_DCR0, ++ MT_MDP_DCR0_RX_HDR_TRANS_EN, !enabled); + mt7996_phy_set_rxfilter(phy); + mt7996_mcu_set_sniffer_mode(phy, enabled); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +index 0fa325f87fcd9..a05681b4d675b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +@@ -159,6 +159,9 @@ enum offs_rev { + #define MT_MDP_BASE 0x820cc000 + #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + ++#define MT_MDP_DCR0 MT_MDP(0x800) ++#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) ++ + #define MT_MDP_DCR2 MT_MDP(0x8e8) + #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch b/queue-6.18/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch new file mode 100644 index 0000000000..5ed93bebeb --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch @@ -0,0 +1,36 @@ +From c99512c9d4b76e5464a0e85fcb0ecedefd0cf1dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 12:44:27 +0100 +Subject: wifi: mt76: mt7996: fix frequency separation for station STR mode + +From: Peter Chiu + +[ Upstream commit 59a295335021f6973a34566554b2b9371f1c6f7d ] + +Fix frequency separation field for STR in MLD capabilities to get the +correct chip capability. + +Signed-off-by: Peter Chiu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260316-mt7996-sta-str-v1-1-666814e6ab2d@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index efbd46d649017..57d72e8359835 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -99,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { + .extended_capabilities_mask = if_types_ext_capa_ap, + .extended_capabilities_len = sizeof(if_types_ext_capa_ap), + .mld_capa_and_ops = ++ FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) | + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, + MT7996_MAX_RADIOS - 1), + }, +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch b/queue-6.18/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch new file mode 100644 index 0000000000..5dcc2d4192 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch @@ -0,0 +1,49 @@ +From 8ed5a50e14b3e038f908fb3b4f794e20954beb88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:32 +0800 +Subject: wifi: mt76: mt7996: fix queue pause after scan due to wrong channel + switch reason + +From: StanleyYP Wang + +[ Upstream commit 1f9017d19db38ad2cb9bedb5b078f6f4f60afa94 ] + +Previously, we used the IEEE80211_CONF_IDLE flag to avoid setting the +parking channel with the CH_SWITCH_NORMAL reason, which could trigger TX +emission before bootup CAC. + +However, we found that this flag can be set after triggering scanning on a +connected station interface, and the reason CH_SWITCH_SCAN_BYPASS_DPD will +be used when switching back to the operating channel, which makes the +firmware failed to resume paused AC queues. + +Seems that we should avoid relying on this flag after switching to single +multi-radio architecture. Instead, use the existence of chanctx as the +condition. + +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-4-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index c7ffcad66d96a..260edf1ffb51d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -3754,8 +3754,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) + + if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) + req.switch_reason = CH_SWITCH_NORMAL; +- else if (phy->mt76->offchannel || +- phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) ++ else if (phy->mt76->offchannel || !phy->mt76->chanctx) + req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; + else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, + NL80211_IFTYPE_AP)) +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch b/queue-6.18/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch new file mode 100644 index 0000000000..586dad4135 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch @@ -0,0 +1,66 @@ +From 9c7b3843cc1694393ed2d03de2cb941b376d1713 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:24:00 +0000 +Subject: wifi: mt76: mt7996: reset device after MCU message timeout + +From: Chad Monroe + +[ Upstream commit d2b860454ea2df8f336e9b859da7ffb27f43444d ] + +Trigger a full reset after MCU message timeout. + +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/6e05ed063f3763ad3457633c56b60a728a49a6f0.1765203753.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 +++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 149d8d711fc4c..c04717bc54c5b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2742,6 +2742,11 @@ void mt7996_reset(struct mt7996_dev *dev) + return; + } + ++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { ++ set_bit(MT76_MCU_RESET, &dev->mphy.state); ++ wake_up(&dev->mt76.mcu.wait); ++ } ++ + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 38b8743409a0c..c7ffcad66d96a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -209,6 +209,7 @@ static int + mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) + { ++ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_mcu_rxd *rxd; + struct mt7996_mcu_uni_event *event; + int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); +@@ -217,6 +218,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + if (!skb) { + dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", + cmd, seq); ++ ++ if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { ++ dev->recovery.restart = true; ++ wake_up(&dev->mt76.mcu.wait); ++ queue_work(dev->mt76.wq, &dev->reset_work); ++ wake_up(&dev->reset_wait); ++ } ++ + return -ETIMEDOUT; + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-6.18/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..f99fa45c34 --- /dev/null +++ b/queue-6.18/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From 20210bb92844a0a95a012c0a441cd2a439ac2484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index c7ae8031436ae..3faf2235728be 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index dccc139cabb29..699c64e8d07e7 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch b/queue-6.18/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch new file mode 100644 index 0000000000..c1eb8985f1 --- /dev/null +++ b/queue-6.18/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch @@ -0,0 +1,118 @@ +From d84019cdbf4508b6e996bf3202aec8799f7e6a9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:56:35 +0800 +Subject: wifi: rtw88: add quirks to disable PCI ASPM and deep LPS for HP + P3S95EA#ACB + +From: Ping-Ke Shih + +[ Upstream commit b2bf9d61e14af4129362aeb9c10034229a6d8f08 ] + +On an HP laptop (P3S95EA#ACB) equipped with a Realtek RTL8821CE 802.11ac +PCIe adapter (PCI ID: 10ec:c821), the system experiences a hard lockup +(complete freeze of the UI and kernel, sysrq doesn't work, requires +holding the power button) when the WiFi adapter enters the power +saving state. Disable PCI ASPM to avoid system freeze. + +In addition, driver throws messages periodically. Though this doesn't +always cause unstable connection, missing H2C commands might cause +unpredictable results. Disable deep LPS to avoid this as well. + + rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state + rtw88_8821ce 0000:13:00.0: failed to send h2c command + rtw88_8821ce 0000:13:00.0: failed to send h2c command + +Tested on HP Notebook P3S95EA#ACB (kernel 6.19.7-1-cachyos): + + - No hard freeze observed during idle or active usage. + - Zero h2c or lps errors in dmesg across idle (10 min), + load stress (100MB download), and suspend/resume cycle. + - Both quirk flags confirmed active via sysfs without any + manual modprobe parameters. + +Reported-by: Oleksandr Havrylov +Closes: https://lore.kernel.org/linux-wireless/CALdGYqSQ1Ko2TTBhUizMu_FvLMUAuQfFrVwS10n_C-LSQJQQkQ@mail.gmail.com/ +Signed-off-by: Ping-Ke Shih +Tested-by: Oleksandr Havrylov +Link: https://patch.msgid.link/20260316035635.16550-1-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/main.h | 5 ++++ + drivers/net/wireless/realtek/rtw88/pci.c | 31 +++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h +index 1ab70214ce36e..55b794d4584c4 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.h ++++ b/drivers/net/wireless/realtek/rtw88/main.h +@@ -432,6 +432,11 @@ enum rtw_wow_flags { + RTW_WOW_FLAG_MAX, + }; + ++enum rtw_quirk_dis_caps { ++ QUIRK_DIS_CAP_PCI_ASPM, ++ QUIRK_DIS_CAP_LPS_DEEP, ++}; ++ + /* the power index is represented by differences, which cck-1s & ht40-1s are + * the base values, so for 1s's differences, there are only ht20 & ofdm + */ +diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c +index ec0a45bfb670e..bba370ad510cf 100644 +--- a/drivers/net/wireless/realtek/rtw88/pci.c ++++ b/drivers/net/wireless/realtek/rtw88/pci.c +@@ -2,6 +2,7 @@ + /* Copyright(c) 2018-2019 Realtek Corporation + */ + ++#include + #include + #include + #include "main.h" +@@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = { + }; + EXPORT_SYMBOL(rtw_pci_err_handler); + ++static int rtw_pci_disable_caps(const struct dmi_system_id *dmi) ++{ ++ uintptr_t dis_caps = (uintptr_t)dmi->driver_data; ++ ++ if (dis_caps & BIT(QUIRK_DIS_CAP_PCI_ASPM)) ++ rtw_pci_disable_aspm = true; ++ ++ if (dis_caps & BIT(QUIRK_DIS_CAP_LPS_DEEP)) ++ rtw_disable_lps_deep_mode = true; ++ ++ return 1; ++} ++ ++static const struct dmi_system_id rtw_pci_quirks[] = { ++ { ++ .callback = rtw_pci_disable_caps, ++ .ident = "HP Notebook - P3S95EA#ACB", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"), ++ }, ++ .driver_data = (void *)(BIT(QUIRK_DIS_CAP_PCI_ASPM) | ++ BIT(QUIRK_DIS_CAP_LPS_DEEP)), ++ }, ++ {} ++}; ++ + int rtw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { +@@ -1771,6 +1800,8 @@ int rtw_pci_probe(struct pci_dev *pdev, + rtwpci = (struct rtw_pci *)rtwdev->priv; + atomic_set(&rtwpci->link_usage, 1); + ++ dmi_check_system(rtw_pci_quirks); ++ + ret = rtw_core_init(rtwdev); + if (ret) + goto err_release_hw; +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch b/queue-6.18/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch new file mode 100644 index 0000000000..bec57bae61 --- /dev/null +++ b/queue-6.18/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch @@ -0,0 +1,46 @@ +From 2d9b669116fcb1791c528f969ceda1a90127baf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:27:15 +0200 +Subject: wifi: rtw88: coex: Ignore BT info byte 5 from RTL8821A + +From: Bitterblue Smith + +[ Upstream commit 658e3c836969e1624a7572c75684f54ec503c2ed ] + +Sometimes while watching a Youtube video with Bluetooth headphones the +audio has a lot of interruptions, because the 5th byte of the BT info +sent by RTL8821AU has strange values, which result in +coex_stat->bt_hid_pair_num being 2 or 3. When this happens +rtw_coex_freerun_check() returns true, which causes +rtw_coex_action_wl_connected() to call rtw_coex_action_freerun() instead +of rtw_coex_action_bt_a2dp(). + +The RTL8821AU vendor driver doesn't do anything with the 5th byte of the +BT info, so ignore it here as well. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/bbf06c83-d2ee-4205-8fbb-829e2347586f@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/coex.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c +index b4dc6ff2c1750..97fc7392b48a8 100644 +--- a/drivers/net/wireless/realtek/rtw88/coex.c ++++ b/drivers/net/wireless/realtek/rtw88/coex.c +@@ -3095,6 +3095,9 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) + for (i = 0; i < COEX_BTINFO_LENGTH; i++) + coex_stat->bt_info_c2h[rsp_source][i] = buf[i]; + ++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) ++ coex_stat->bt_info_c2h[rsp_source][5] = 0; ++ + /* get the same info from bt, skip it */ + if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 && + coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 && +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-6.18/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..2ba7765582 --- /dev/null +++ b/queue-6.18/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From 9fa728b8d73fbf89dca3b5752af0c68e897b2b1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index 2ab440cb2d67b..3106edb84fb47 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -421,7 +421,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + pkt_info->mac_id = rtwvif->mac_id; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch b/queue-6.18/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch new file mode 100644 index 0000000000..0d63702d82 --- /dev/null +++ b/queue-6.18/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch @@ -0,0 +1,59 @@ +From 56dbf4b33ebb4ae6ea5ec1b8ba1c9996f0d294db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 09:10:01 +0800 +Subject: wifi: rtw88: validate RX rate to prevent out-of-bound + +From: Ping-Ke Shih + +[ Upstream commit bf14367719fa86f7c6922c64d37a2df347954c66 ] + +The reported RX rate might be unexpected, causing kernel warns: + + Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0 + WARNING: net/mac80211/rx.c:5491 at ieee80211_rx_list+0x183/0x1020 [mac80211] + +As the RX rate can be index of an array under certain conditions, validate +it to prevent accessing array out-of-bound potentially. + +Tested on HP Notebook P3S95EA#ACB (kernel 6.19.9-1-cachyos): + + - No WARNING: net/mac80211/rx.c:5491 observed after the v2 patch. +The unexpected `NSS: 0, MCS: 0` VHT rate warnings are successfully +mitigated. + - The system remains fully stable through prolonged idle periods, +high network load, active Bluetooth A2DP usage, and multiple deep +suspend/resume cycles. + - Zero h2c timeouts or firmware lps state errors observed in dmesg. + +Reported-by: Oleksandr Havrylov +Closes: https://lore.kernel.org/linux-wireless/CALdGYqSMUPnPfW-_q1RgYr0_SjoXUejAaJJr-o+jpwCk1S7ndQ@mail.gmail.com/ +Tested-by: Oleksandr Havrylov +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260324011001.5742-1-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/rx.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c +index 8b0afaaffaa0e..d9e11343d4988 100644 +--- a/drivers/net/wireless/realtek/rtw88/rx.c ++++ b/drivers/net/wireless/realtek/rtw88/rx.c +@@ -295,6 +295,14 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + + pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL); + ++ if (unlikely(pkt_stat->rate >= DESC_RATE_MAX)) { ++ rtw_dbg(rtwdev, RTW_DBG_UNEXP, ++ "unexpected RX rate=0x%x\n", pkt_stat->rate); ++ ++ pkt_stat->rate = DESC_RATE1M; ++ pkt_stat->bw = RTW_CHANNEL_WIDTH_20; ++ } ++ + /* drv_info_sz is in unit of 8-bytes */ + pkt_stat->drv_info_sz *= 8; + +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch b/queue-6.18/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch new file mode 100644 index 0000000000..10cca38751 --- /dev/null +++ b/queue-6.18/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch @@ -0,0 +1,78 @@ +From af7f18b5308734b9dc6dcb8aa3af3f6c2a558976 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:21:55 +0000 +Subject: wifi: rtw89: retry efuse physical map dump on transient failure + +From: Christian Hewitt + +[ Upstream commit d92f6ad6483e6d430c8273eeb7be97ce85244bd5 ] + +On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse +physical map dump intermittently fails with -EBUSY during probe. +The failure occurs in rtw89_dump_physical_efuse_map_ddv() where +read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY +bit after 1 second. + +The root cause is a timing race during boot: the WiFi driver's +chip initialization (firmware download via PCIe) overlaps with +Bluetooth firmware download to the same combo chip via USB. This +can leave the efuse controller temporarily unavailable when the +WiFi driver attempts to read the efuse map. + +The firmware download path retries up to 5 times, but the efuse +read that follows has no similar logic. Address this by adding +retry loop logic (also up to 5 attempts) around physical efuse +map dump. + +Signed-off-by: Christian Hewitt +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260317112155.1939569-1-christianshewitt@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/efuse.c | 23 ++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c +index 6c6c763510af6..fd648a8644750 100644 +--- a/drivers/net/wireless/realtek/rtw89/efuse.c ++++ b/drivers/net/wireless/realtek/rtw89/efuse.c +@@ -189,8 +189,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + +-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, +- u32 dump_addr, u32 dump_size, bool dav) ++static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) + { + int ret; + +@@ -212,6 +212,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + ++static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) ++{ ++ int retry; ++ int ret; ++ ++ for (retry = 0; retry < 5; retry++) { ++ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr, ++ dump_size, dav); ++ if (!ret) ++ return 0; ++ ++ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n", ++ dav, retry); ++ } ++ ++ return ret; ++} ++ + #define invalid_efuse_header(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) + #define invalid_efuse_content(word_en, i) \ +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch b/queue-6.18/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch new file mode 100644 index 0000000000..259d9cdd27 --- /dev/null +++ b/queue-6.18/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch @@ -0,0 +1,53 @@ +From 60b25b28f8e20be951a3d13d2c371dc4c0d477cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 14:15:51 +0800 +Subject: wifi: rtw89: ser: Wi-Fi 7 reset HALT C2H after reading it + +From: Zong-Zhe Yang + +[ Upstream commit 0cae26a78b14fe1292b0f50f28ebabe6801f3885 ] + +When a SER (system error recovery) interrupt happens, driver reads HALT C2H +register to get the error status via MAC. For Wi-Fi 7 chipset, driver needs +to reset HALT C2H register after reading it to make FW aware that. + +Signed-off-by: Zong-Zhe Yang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260213061552.29997-12-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/mac.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c +index 71194ea68bcee..b4a9953e79a42 100644 +--- a/drivers/net/wireless/realtek/rtw89/mac.c ++++ b/drivers/net/wireless/realtek/rtw89/mac.c +@@ -813,6 +813,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; ++ const struct rtw89_chip_info *chip = rtwdev->chip; + u32 err, err_scnr; + int ret; + +@@ -835,11 +836,15 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + err = MAC_AX_ERR_RXI300; + + if (rtw89_mac_suppress_log(rtwdev, err)) +- return err; ++ goto bottom; + + rtw89_fw_st_dbg_dump(rtwdev); + mac->dump_err_status(rtwdev, err); + ++bottom: ++ if (chip->chip_gen != RTW89_CHIP_AX) ++ rtw89_write32(rtwdev, R_AX_HALT_C2H, 0); ++ + return err; + } + EXPORT_SYMBOL(rtw89_mac_get_err_status); +-- +2.53.0 + diff --git a/queue-6.18/x86-mce-restore-mca-polling-interval-halving.patch b/queue-6.18/x86-mce-restore-mca-polling-interval-halving.patch new file mode 100644 index 0000000000..f748c6dbb3 --- /dev/null +++ b/queue-6.18/x86-mce-restore-mca-polling-interval-halving.patch @@ -0,0 +1,138 @@ +From c2b5b1dbf4553ebeed27b004877199caddc2ab43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:12:00 +0100 +Subject: x86/mce: Restore MCA polling interval halving + +From: Borislav Petkov (AMD) + +[ Upstream commit ea324444ece9f301b5c4ff71b258cc68990c4d61 ] + +RongQing reported that the MCA polling interval doesn't halve when an +error gets logged. It was traced down to the commit in Fixes:, because: + + mce_timer_fn() + |-> mce_poll_banks() + |-> machine_check_poll() + |-> mce_log() + +which will queue the work and return. + +Now, back in mce_timer_fn(): + + /* + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ + if (mce_notify_irq()) + +<--- here we haven't ran the notifier chain yet so mce_need_notify is +not set yet so this won't hit and we won't halve the interval iv. + +Now the notifier chain runs. mce_early_notifier() sets the bit, does +mce_notify_irq(), that clears the bit and then the notifier chain +a little later logs the error. + +So this is a silly timing issue. + +But, that's all unnecessary. + +All it needs to happen here is, the "should we notify of a logged MCE" +mce_notify_irq() asks, should be simply a question to the mce gen pool: +"Are you empty?" + +And that then turns into a simple yes or no answer and it all +JustWorks(tm). + +So do that and also distribute the functionality where it belongs: + - Print that MCE events have been logged in mce_log() + - Trigger the mcelog tool specific work in the first notifier + +As a result, mce_notify_irq() can go now. + +Fixes: 011d82611172 ("RAS: Add a Corrected Errors Collector") +Reported-by: Li RongQing +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Qiuxu Zhuo +Tested-by: Qiuxu Zhuo +Link: https://lore.kernel.org/r/20260112082747.2842-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/core.c | 33 +++++---------------------------- + 1 file changed, 5 insertions(+), 28 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 460e90a1a0b17..c8b112c6c5492 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -89,7 +89,6 @@ struct mca_config mca_cfg __read_mostly = { + }; + + static DEFINE_PER_CPU(struct mce_hw_err, hw_errs_seen); +-static unsigned long mce_need_notify; + + /* + * MCA banks polled by the period polling timer for corrected events. +@@ -151,8 +150,10 @@ EXPORT_PER_CPU_SYMBOL_GPL(injectm); + + void mce_log(struct mce_hw_err *err) + { +- if (mce_gen_pool_add(err)) ++ if (mce_gen_pool_add(err)) { ++ pr_info(HW_ERR "Machine check events logged\n"); + irq_work_queue(&mce_irq_work); ++ } + } + EXPORT_SYMBOL_GPL(mce_log); + +@@ -584,28 +585,6 @@ bool mce_is_correctable(struct mce *m) + } + EXPORT_SYMBOL_GPL(mce_is_correctable); + +-/* +- * Notify the user(s) about new machine check events. +- * Can be called from interrupt context, but not from machine check/NMI +- * context. +- */ +-static bool mce_notify_irq(void) +-{ +- /* Not more than two messages every minute */ +- static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); +- +- if (test_and_clear_bit(0, &mce_need_notify)) { +- mce_work_trigger(); +- +- if (__ratelimit(&ratelimit)) +- pr_info(HW_ERR "Machine check events logged\n"); +- +- return true; +- } +- +- return false; +-} +- + static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +@@ -617,9 +596,7 @@ static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + /* Emit the trace record: */ + trace_mce_record(err); + +- set_bit(0, &mce_need_notify); +- +- mce_notify_irq(); ++ mce_work_trigger(); + + return NOTIFY_DONE; + } +@@ -1771,7 +1748,7 @@ static void mce_timer_fn(struct timer_list *t) + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ +- if (mce_notify_irq()) ++ if (!mce_gen_pool_empty()) + iv = max(iv / 2, (unsigned long) HZ/100); + else + iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); +-- +2.53.0 + diff --git a/queue-6.18/x86-xen-fix-xen_e820_swap_entry_with_ram.patch b/queue-6.18/x86-xen-fix-xen_e820_swap_entry_with_ram.patch new file mode 100644 index 0000000000..aa872983aa --- /dev/null +++ b/queue-6.18/x86-xen-fix-xen_e820_swap_entry_with_ram.patch @@ -0,0 +1,39 @@ +From c99438a5462904a3e6af330c3c893b4f16a0695b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 12:24:17 +0200 +Subject: x86/xen: Fix xen_e820_swap_entry_with_ram() + +From: Juergen Gross + +[ Upstream commit 28e03f78e69cf6628b81f24777799778528a84c1 ] + +When swapping a not page-aligned E820 map entry with RAM, the start +address of the modified entry is calculated wrong (the offset into the +page is subtracted instead of being added to the page address). + +Fixes: be35d91c8880 ("xen: tolerate ACPI NVS memory overlapping with Xen allocated memory") +Reported-by: Jan Beulich +Reviewed-by: Jan Beulich +Signed-off-by: Juergen Gross +Message-ID: <20260505102417.208138-1-jgross@suse.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index 3823e52aef523..6260f65a78c5e 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -655,7 +655,7 @@ static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry) + /* Fill new entry (keep size and page offset). */ + entry->type = swap_entry->type; + entry->addr = entry_end - swap_size + +- swap_addr - swap_entry->addr; ++ swap_entry->addr - swap_addr; + entry->size = swap_entry->size; + + /* Convert old entry to RAM, align to pages. */ +-- +2.53.0 + diff --git a/queue-6.6/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch b/queue-6.6/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch new file mode 100644 index 0000000000..8dee85b04a --- /dev/null +++ b/queue-6.6/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch @@ -0,0 +1,78 @@ +From 6cc7932af9f92e061eb876948ab2de6a472959be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 12:39:01 -0700 +Subject: accel/qaic: Add overflow check to remap_pfn_range during mmap + +From: Zack McKevitt + +[ Upstream commit aa16b2bc0f02709919e2435f531406531e5bcc69 ] + +The call to remap_pfn_range in qaic_gem_object_mmap is susceptible to +(re)mapping beyond the VMA if the BO is too large. This can cause use +after free issues when munmap() unmaps only the VMA region and not the +additional mappings. To prevent this, check the remaining size of the +VMA before remapping and truncate the remapped length if sg->length is +too large. + +Reported-by: Lukas Maar +Fixes: ff13be830333 ("accel/qaic: Add datapath") +Reviewed-by: Karol Wachowski +Signed-off-by: Zack McKevitt +Reviewed-by: Jeff Hugo +[jhugo: fix braces from checkpatch --strict] +Signed-off-by: Jeff Hugo +Link: https://patch.msgid.link/20260430193858.1178641-1-zachary.mckevitt@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/accel/qaic/qaic_data.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c +index d00068987d9bd..7beab1309e369 100644 +--- a/drivers/accel/qaic/qaic_data.c ++++ b/drivers/accel/qaic/qaic_data.c +@@ -595,8 +595,11 @@ static const struct vm_operations_struct drm_vm_ops = { + static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) + { + struct qaic_bo *bo = to_qaic_bo(obj); ++ unsigned long remap_start; + unsigned long offset = 0; ++ unsigned long remap_end; + struct scatterlist *sg; ++ unsigned long length; + int ret = 0; + + if (obj->import_attach) +@@ -604,11 +607,27 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc + + for (sg = bo->sgt->sgl; sg; sg = sg_next(sg)) { + if (sg_page(sg)) { ++ /* if sg is too large for the VMA, so truncate it to fit */ ++ if (check_add_overflow(vma->vm_start, offset, &remap_start)) ++ return -EINVAL; ++ if (check_add_overflow(remap_start, sg->length, &remap_end)) ++ return -EINVAL; ++ ++ if (remap_end > vma->vm_end) { ++ if (check_sub_overflow(vma->vm_end, remap_start, &length)) ++ return -EINVAL; ++ } else { ++ length = sg->length; ++ } ++ ++ if (length == 0) ++ goto out; ++ + ret = remap_pfn_range(vma, vma->vm_start + offset, page_to_pfn(sg_page(sg)), +- sg->length, vma->vm_page_prot); ++ length, vma->vm_page_prot); + if (ret) + goto out; +- offset += sg->length; ++ offset += length; + } + } + +-- +2.53.0 + diff --git a/queue-6.6/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-6.6/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..ceb43a1ec2 --- /dev/null +++ b/queue-6.6/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From e530b62a8c40526af6aad71048920d422ccd5f4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index b524cf27213d4..b377afe11e699 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1087,6 +1087,8 @@ static int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-6.6/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-6.6/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..e9dc412586 --- /dev/null +++ b/queue-6.6/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From bf3394221ee1900cc9174ed6cc32b0a01cbc1848 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index b377afe11e699..f45758207512c 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1289,16 +1289,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-6.6/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-6.6/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..9574c08c90 --- /dev/null +++ b/queue-6.6/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From fb37a1ebcd62c9effc5a69414564744ba04090ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index b2bf7016e1b34..287f674b7af17 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -85,6 +85,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-6.6/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-6.6/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..a368cfc815 --- /dev/null +++ b/queue-6.6/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 944a9130bdaf5ca85df281ec3c4bf0aee50c7b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index a714a3f3f6a56..e721928528803 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -979,10 +979,12 @@ static int onyx_i2c_probe(struct i2c_client *client) + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.6/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-6.6/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..ac6cc24248 --- /dev/null +++ b/queue-6.6/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From e2dd7aa9379366a5930affe30a0aeecbed4a2b78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index 4446307c095ca..9500a127116c1 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client) + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.6/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-6.6/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..837dc1c912 --- /dev/null +++ b/queue-6.6/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From 92eae765a60d283faf463fbabd9399c334a8db1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 8545c7bbc58e3..3e8093d989235 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -161,6 +161,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %d total %d bytes\n", + tstamp->byte_offset, tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-6.6/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..e35a26252b --- /dev/null +++ b/queue-6.6/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From 117f137969f47e633697c673ff28a46a61c90669 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c +index 7b276047f85a7..c897fc443467c 100644 +--- a/sound/hda/hdmi_chmap.c ++++ b/sound/hda/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch b/queue-6.6/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch new file mode 100644 index 0000000000..8ffcc02b51 --- /dev/null +++ b/queue-6.6/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch @@ -0,0 +1,44 @@ +From 1aaee1d83265ec1fcfd76ea313635336a37bb2a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:01:39 +0800 +Subject: ALSA: hda: cs35l56: Put ACPI device after setting companion + +From: Shuhao Fu + +[ Upstream commit aa2fbece1b07954ef26488c800d126a36a8ab93e ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers are expected to balance it with acpi_dev_put(). + +When no companion is already attached, cs35l56_hda_read_acpi() looks +up an ACPI device and sets it with ACPI_COMPANION_SET(), but leaves +the lookup reference held. + +ACPI_COMPANION_SET() does not take ownership of that reference, so +drop it with acpi_dev_put() after attaching the companion. + +Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428080139.GA1649104@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/pci/hda/cs35l56_hda.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c +index bae7b1d592c6c..afb397c32361f 100644 +--- a/sound/pci/hda/cs35l56_hda.c ++++ b/sound/pci/hda/cs35l56_hda.c +@@ -855,6 +855,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); ++ acpi_dev_put(adev); + } + + property = "cirrus,dev-index"; +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch b/queue-6.6/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch new file mode 100644 index 0000000000..7e072cd097 --- /dev/null +++ b/queue-6.6/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch @@ -0,0 +1,47 @@ +From 90c81b34b9c976a3a58bd72617908db558601c4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:18:54 +0800 +Subject: ALSA: hda/realtek: Add quirk for HP Spectre x360 14-ea + +From: songxiebing + +[ Upstream commit 882321ccaeea52dd645dff98bfea2f92b286e673 ] + +HP Spectre x360 Convertible 14-ea0xxx (2021 model or so) +doesn't make produce sound,The Bang & Olufsen speaker amplifier +is not enabled. + +Root causing: +The PCI subsystem ID is 103c:0000 (HP left it unset), while the codec +subsystem ID is 103c:885b. The vendor-wide catch-all +SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED) matches +103c:0000 before the codec SSID fallback is reached, so +ALC245_FIXUP_HP_X360_AMP never applies. + +So add the quirk in alc269_fixup_tbl. + +Reported-by: dzidmail +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221341 +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260413011854.96520-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 937f3fdbab252..dfa1e99545784 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10132,6 +10132,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), ++ HDA_CODEC_QUIRK(0x103c, 0x885b, "HP Spectre x360 14-ea", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +-- +2.53.0 + diff --git a/queue-6.6/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-6.6/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..b2f1ef3556 --- /dev/null +++ b/queue-6.6/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From d75d7aa64bc15eccc989cc9d5e9ca18298dc880c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 214210c874745..ec8a4c0261ad4 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1758,6 +1758,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1770,8 +1773,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-6.6/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-6.6/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..a4e0902faa --- /dev/null +++ b/queue-6.6/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From 6534fd7a898be350f88ed1da598749d5909bafbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 8c4fb5be3dba9..e11cb9abf3134 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1191,6 +1191,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-6.6/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-6.6/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..5ce0a48868 --- /dev/null +++ b/queue-6.6/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From 1aa34cbc457d139a55131e3b821149a9989b3a42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index a395b6c0aae2a..56f6d8327d5c8 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -218,8 +218,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -228,9 +229,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-6.6/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch b/queue-6.6/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch new file mode 100644 index 0000000000..b43d1df5b9 --- /dev/null +++ b/queue-6.6/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch @@ -0,0 +1,47 @@ +From ee7095756b0ff39a4df026a5a31a230c8fa8db0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:45:53 +0200 +Subject: ASoC: amd: yc: Add MSI Vector A16 HX A8WHG to quirk table + +From: Ihor Uzlov + +[ Upstream commit 72dcd84938f5026dc44d0e7e1e68d9d571c113a0 ] + +Add the MSI Vector A16 HX A8WHG (board MS-15MM) to the DMI quirk table +to enable DMIC support. This laptop uses an AMD Ryzen 9 7945HX (Dragon +Range) with the ACP6x audio coprocessor (rev 0x62) and a Realtek ALC274 +codec. The built-in digital microphone is connected via the ACP PDM +interface and requires this DMI entry to be activated. + +Tested on MSI Vector A16 HX A8WHG with kernel 6.8.0-107 (Ubuntu 24.04). +DMIC capture device appears as 'acp6x' and records audio correctly. + +Signed-off-by: Ihor Uzlov +Link: https://patch.msgid.link/20260410094553.24654-1-igor.uzlov@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index 8281cdae9fd03..c2ca942606414 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -493,6 +493,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +-- +2.53.0 + diff --git a/queue-6.6/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch b/queue-6.6/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch new file mode 100644 index 0000000000..4e599d27fd --- /dev/null +++ b/queue-6.6/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch @@ -0,0 +1,65 @@ +From d2055f1c9ae0660244b99e90870bee1cdc2e13d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:34:08 +0800 +Subject: ASoC: aw88395: Fix kernel panic caused by invalid GPIO error pointer + +From: wangdicheng + +[ Upstream commit 241ee17ecb6be210f7b231b2a81bfb68871950d0 ] + +In aw88395_i2c_probe(), if `devm_gpiod_get_optional()` fails, it returns +an ERR_PTR() error pointer. The current code only prints a message and +continues execution, leaving `aw88395->reset_gpio` as an invalid pointer. + +Later, in `aw88395_hw_reset()`, this invalid pointer is passed to +`gpiod_set_value_cansleep()`, which dereferences it and causes a kernel +panic. + +For optional GPIOs, `devm_gpiod_get_optional()` returns NULL if the GPIO +is not defined in the DT, which is safe. If it returns an ERR_PTR, it +means a real error occurred (e.g., -EPROBE_DEFER) and the probe must be +aborted. + +Also, since the GPIO is optional, remove the dev_err() log in +aw88395_hw_reset() when the GPIO is missing to match the optional +semantics. This also fixes a potential NULL pointer dereference as +aw_pa is not initialized when aw88395_hw_reset() is called. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428023408.46420-1-wangdich9700@163.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/aw88395/aw88395.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c +index 9dcd75dd799a5..26bcc1de98e81 100644 +--- a/sound/soc/codecs/aw88395/aw88395.c ++++ b/sound/soc/codecs/aw88395/aw88395.c +@@ -459,8 +459,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); + gpiod_set_value_cansleep(aw88395->reset_gpio, 1); + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); +- } else { +- dev_err(aw88395->aw_pa->dev, "%s failed", __func__); + } + } + +@@ -525,9 +523,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) + i2c_set_clientdata(i2c, aw88395); + + aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(aw88395->reset_gpio)) +- dev_info(&i2c->dev, "reset gpio not defined\n"); +- ++ if (IS_ERR(aw88395->reset_gpio)) { ++ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), ++ "failed to get reset gpio\n"); ++ } + /* hardware reset */ + aw88395_hw_reset(aw88395); + +-- +2.53.0 + diff --git a/queue-6.6/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-6.6/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..2a34e0d207 --- /dev/null +++ b/queue-6.6/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From 33303e8ec67a6185a8d25e89dca24260fea5dd3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index d96e23ec43d4c..cf09b66eb2873 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -848,9 +848,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.6/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-6.6/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..f77d73c248 --- /dev/null +++ b/queue-6.6/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 669b92ef3f6bc6eea59071232d0adf88ed371815 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index beca466dd468e..20bb63feb3d30 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -289,6 +289,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.6/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-6.6/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..123d931842 --- /dev/null +++ b/queue-6.6/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 9bf2179515047faed7266fca293ad2fe72d28c2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index 2abe47303ecdb..16dda1c53d8ab 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -210,6 +210,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-6.6/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-6.6/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..80e4836ca7 --- /dev/null +++ b/queue-6.6/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From a6ae82e29c23a2f2a51912ae246097f8fd9fb8e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index daa630a0efc18..c2ac55d51e863 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-6.6/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch b/queue-6.6/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch new file mode 100644 index 0000000000..83acd22f29 --- /dev/null +++ b/queue-6.6/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch @@ -0,0 +1,46 @@ +From 526af811ba4b1a9bab15adbf3b20f5eefe2dfe2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 13:30:51 +0800 +Subject: ASoC: mxs-sgtl5000: disable MCLK on error paths of + mxs_sgtl5000_probe() + +From: Haoxiang Li + +[ Upstream commit c8ef13d692f19cdbbf195fb845421a5b71801704 ] + +Call mxs_saif_put_mclk() to disable MCLK on error +paths of mxs_sgtl5000_probe(). + +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260401053051.586290-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/mxs/mxs-sgtl5000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c +index 457c3a72a4147..8aba4bc25ff30 100644 +--- a/sound/soc/mxs/mxs-sgtl5000.c ++++ b/sound/soc/mxs/mxs-sgtl5000.c +@@ -158,13 +158,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); ++ mxs_saif_put_mclk(0); + return ret; + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) ++ if (ret) { ++ mxs_saif_put_mclk(0); + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-6.6/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..59a0d8e491 --- /dev/null +++ b/queue-6.6/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From c80c7f464a046ad62738f34284df765edcbec14e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 0f250e8e216a4..3581b1eb1e9ca 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1838,6 +1838,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + unsigned int pll_bit = 0; + int ret; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + ret = clk_set_rate(rt5640->mclk, freq); +-- +2.53.0 + diff --git a/queue-6.6/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-6.6/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..5351509a40 --- /dev/null +++ b/queue-6.6/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From 8a503e1fdec29a24fbaa104922a60e5d2fc59866 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index c65a4219ecd6c..32a93217ac5a1 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -492,7 +492,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -501,7 +501,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -590,7 +590,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { +@@ -615,7 +615,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -628,7 +628,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-6.6/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-6.6/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..bd850db62e --- /dev/null +++ b/queue-6.6/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From 6cc908fcdf49634cc55563c1301ebe1e8a676499 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index 8c8b2a2f6f862..386275e867280 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2529,6 +2529,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-6.6/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-6.6/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..0da28100d5 --- /dev/null +++ b/queue-6.6/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From b4727d7eb7ff0e89281a4713c22e30313371ae39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index fc2c508c41bd4..6c700ef41fc7f 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2919,7 +2919,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-6.6/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch b/queue-6.6/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch new file mode 100644 index 0000000000..a252053e20 --- /dev/null +++ b/queue-6.6/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch @@ -0,0 +1,215 @@ +From fec19a2cf9aa802e23438ae3e20cc60771efb0d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:05:09 +0000 +Subject: blk-iocost: fix busy_level reset when no IOs complete + +From: Jialin Wang + +[ Upstream commit f91ffe89b2016d280995a9c28d73288b02d83615 ] + +When a disk is saturated, it is common for no IOs to complete within a +timer period. Currently, in this case, rq_wait_pct and missed_ppm are +calculated as 0, the iocost incorrectly interprets this as meeting QoS +targets and resets busy_level to 0. + +This reset prevents busy_level from reaching the threshold (4) needed +to reduce vrate. On certain cloud storage, such as Azure Premium SSD, +we observed that iocost may fail to reduce vrate for tens of seconds +during saturation, failing to mitigate noisy neighbor issues. + +Fix this by tracking the number of IO completions (nr_done) in a period. +If nr_done is 0 and there are lagging IOs, the saturation status is +unknown, so we keep busy_level unchanged. + +The issue is consistently reproducible on Azure Standard_D8as_v5 (Dasv5) +VMs with 512GB Premium SSD (P20) using the script below. It was not +observed on GCP n2d VMs (with 100G pd-ssd and 1.5T local-ssd), and no +regressions were found with this patch. In this script, cgA performs +large IOs with iodepth=128, while cgB performs small IOs with iodepth=1 +rate_iops=100 rw=randrw. With iocost enabled, we expect it to throttle +cgA, the submission latency (slat) of cgA should be significantly higher, +cgB can reach 200 IOPS and the completion latency (clat) should below. + + BLK_DEVID="8:0" + MODEL="rbps=173471131 rseqiops=3566 rrandiops=3566 wbps=173333269 wseqiops=3566 wrandiops=3566" + QOS="rpct=90 rlat=3500 wpct=90 wlat=3500 min=80 max=10000" + + echo "$BLK_DEVID ctrl=user model=linear $MODEL" > /sys/fs/cgroup/io.cost.model + echo "$BLK_DEVID enable=1 ctrl=user $QOS" > /sys/fs/cgroup/io.cost.qos + + CG_A="/sys/fs/cgroup/cgA" + CG_B="/sys/fs/cgroup/cgB" + + FILE_A="/path/to/sda/A.fio.testfile" + FILE_B="/path/to/sda/B.fio.testfile" + RESULT_DIR="./iocost_results_$(date +%Y%m%d_%H%M%S)" + + mkdir -p "$CG_A" "$CG_B" "$RESULT_DIR" + + get_result() { + local file=$1 + local label=$2 + + local results=$(jq -r ' + .jobs[0].mixed | + ( .iops | tonumber | round ) as $iops | + ( .bw_bytes / 1024 / 1024 ) as $bps | + ( .slat_ns.mean / 1000000 ) as $slat | + ( .clat_ns.mean / 1000000 ) as $avg | + ( .clat_ns.max / 1000000 ) as $max | + ( .clat_ns.percentile["90.000000"] / 1000000 ) as $p90 | + ( .clat_ns.percentile["99.000000"] / 1000000 ) as $p99 | + ( .clat_ns.percentile["99.900000"] / 1000000 ) as $p999 | + ( .clat_ns.percentile["99.990000"] / 1000000 ) as $p9999 | + "\($iops)|\($bps)|\($slat)|\($avg)|\($max)|\($p90)|\($p99)|\($p999)|\($p9999)" + ' "$file") + + IFS='|' read -r iops bps slat avg max p90 p99 p999 p9999 <<<"$results" + printf "%-8s %-6s %-7.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f\n" \ + "$label" "$iops" "$bps" "$slat" "$avg" "$max" "$p90" "$p99" "$p999" "$p9999" + } + + run_fio() { + local cg_path=$1 + local filename=$2 + local name=$3 + local bs=$4 + local qd=$5 + local out=$6 + shift 6 + local extra=$@ + + ( + pid=$(sh -c 'echo $PPID') + echo $pid >"${cg_path}/cgroup.procs" + fio --name="$name" --filename="$filename" --direct=1 --rw=randrw --rwmixread=50 \ + --ioengine=libaio --bs="$bs" --iodepth="$qd" --size=4G --runtime=10 \ + --time_based --group_reporting --unified_rw_reporting=mixed \ + --output-format=json --output="$out" $extra >/dev/null 2>&1 + ) & + } + + echo "Starting Test ..." + + for bs_b in "4k" "32k" "256k"; do + echo "Running iteration: BS=$bs_b" + out_a="${RESULT_DIR}/cgA_1m.json" + out_b="${RESULT_DIR}/cgB_${bs_b}.json" + + # cgA: Heavy background (BS 1MB, QD 128) + run_fio "$CG_A" "$FILE_A" "cgA" "1m" 128 "$out_a" + # cgB: Latency sensitive (Variable BS, QD 1, Read/Write IOPS limit 100) + run_fio "$CG_B" "$FILE_B" "cgB" "$bs_b" 1 "$out_b" "--rate_iops=100" + + wait + SUMMARY_DATA+="$(get_result "$out_a" "cgA-1m")"$'\n' + SUMMARY_DATA+="$(get_result "$out_b" "cgB-$bs_b")"$'\n\n' + done + + echo -e "\nFinal Results Summary:\n" + + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n" \ + "" "" "" "slat" "clat" "clat" "clat" "clat" "clat" "clat" + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n\n" \ + "CGROUP" "IOPS" "MB/s" "avg(ms)" "avg(ms)" "max(ms)" "P90(ms)" "P99" "P99.9" "P99.99" + echo "$SUMMARY_DATA" + + echo "Results saved in $RESULT_DIR" + +Before: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 166 166.37 3.44 748.95 1298.29 977.27 1233.13 1300.23 1300.23 + cgB-4k 5 0.02 0.02 181.74 761.32 742.39 759.17 759.17 759.17 + + cgA-1m 167 166.51 1.98 748.68 1549.41 809.50 1451.23 1551.89 1551.89 + cgB-32k 6 0.18 0.02 169.98 761.76 742.39 759.17 759.17 759.17 + + cgA-1m 166 165.55 2.89 750.89 1540.37 851.44 1451.23 1535.12 1535.12 + cgB-256k 5 1.30 0.02 191.35 759.51 750.78 759.17 759.17 759.17 + +After: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 162 162.48 6.14 749.69 850.02 826.28 834.67 843.06 851.44 + cgB-4k 199 0.78 0.01 1.95 42.12 2.57 7.50 34.87 42.21 + + cgA-1m 146 146.20 6.83 833.04 908.68 893.39 901.78 910.16 910.16 + cgB-32k 200 6.25 0.01 2.32 31.40 3.06 7.50 16.58 31.33 + + cgA-1m 110 110.46 9.04 1082.67 1197.91 1182.79 1199.57 1199.57 1199.57 + cgB-256k 200 49.98 0.02 3.69 22.20 4.88 9.11 20.05 22.15 + +Signed-off-by: Jialin Wang +Acked-by: Tejun Heo +Link: https://patch.msgid.link/20260331100509.182882-1-wjl.linux@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 129732a8d0dd9..03448d0b4a784 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1596,7 +1596,8 @@ static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer) + return HRTIMER_NORESTART; + } + +-static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p) ++static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p, ++ u32 *nr_done) + { + u32 nr_met[2] = { }; + u32 nr_missed[2] = { }; +@@ -1633,6 +1634,8 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p + + *rq_wait_pct_p = div64_u64(rq_wait_ns * 100, + ioc->period_us * NSEC_PER_USEC); ++ ++ *nr_done = nr_met[READ] + nr_met[WRITE] + nr_missed[READ] + nr_missed[WRITE]; + } + + /* was iocg idle this period? */ +@@ -2250,12 +2253,12 @@ static void ioc_timer_fn(struct timer_list *timer) + u64 usage_us_sum = 0; + u32 ppm_rthr; + u32 ppm_wthr; +- u32 missed_ppm[2], rq_wait_pct; ++ u32 missed_ppm[2], rq_wait_pct, nr_done; + u64 period_vtime; + int prev_busy_level; + + /* how were the latencies during the period? */ +- ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct); ++ ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct, &nr_done); + + /* take care of active iocgs */ + spin_lock_irq(&ioc->lock); +@@ -2399,9 +2402,17 @@ static void ioc_timer_fn(struct timer_list *timer) + * and should increase vtime rate. + */ + prev_busy_level = ioc->busy_level; +- if (rq_wait_pct > RQ_WAIT_BUSY_PCT || +- missed_ppm[READ] > ppm_rthr || +- missed_ppm[WRITE] > ppm_wthr) { ++ if (!nr_done && nr_lagging) { ++ /* ++ * When there are lagging IOs but no completions, we don't ++ * know if the IO latency will meet the QoS targets. The ++ * disk might be saturated or not. We should not reset ++ * busy_level to 0 (which would prevent vrate from scaling ++ * up or down), but rather to keep it unchanged. ++ */ ++ } else if (rq_wait_pct > RQ_WAIT_BUSY_PCT || ++ missed_ppm[READ] > ppm_rthr || ++ missed_ppm[WRITE] > ppm_wthr) { + /* clearly missing QoS targets, slow down vrate */ + ioc->busy_level = max(ioc->busy_level, 0); + ioc->busy_level++; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-6.6/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..a2f4150bbf --- /dev/null +++ b/queue-6.6/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From d22b7332e43a1acc6cd055228739404c3ab1639b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 0a5445ac5e1b7..67bc2cf1825e4 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -506,6 +506,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch b/queue-6.6/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch new file mode 100644 index 0000000000..75e7acd7b2 --- /dev/null +++ b/queue-6.6/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch @@ -0,0 +1,40 @@ +From 7a1f5b9da721e9847bed53eaeb387d9fa465639f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:25:08 +0800 +Subject: Bluetooth: btmtk: improve mt79xx firmware setup retry flow + +From: Chris Lu + +[ Upstream commit 54f1f020e9f4a087779cc4d96a7c86f47d0c6797 ] + +If retries are exhausted, driver should not do futher operation. +During mt79xx firmware download process, if the retry count reaches0, +driver will return an -EIO error and release the firmware resources. + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index 4c53ab22d09b0..f90b4472b9aab 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -181,6 +181,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, + } + } + ++ /* If retry exhausted goto err_release_fw */ ++ if (retry == 0) { ++ err = -EIO; ++ goto err_release_fw; ++ } ++ + fw_ptr += section_offset; + wmt_params.op = BTMTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch b/queue-6.6/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch new file mode 100644 index 0000000000..f5bb7985e8 --- /dev/null +++ b/queue-6.6/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch @@ -0,0 +1,43 @@ +From e3af29f4bfcb71258c5a6cf5a998b1c98ca6cddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:16 +0800 +Subject: Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is + not defined + +From: Shuai Zhang + +[ Upstream commit 7b75867803a8712bdf7683c31d71d3d5e28ce821 ] + +On platforms using an M.2 slot with both UART and USB support, bt_en is +pulled high by hardware. In this case, software-based power control +should be disabled. The current platforms are Lemans-EVK and Monaco-EVK. + +Add QCA_WCN7850 to the existing condition so that power_ctrl_enabled is +cleared when bt_en is not software-controlled (or absent), aligning its +behavior with WCN6750 and WCN6855 + +Signed-off-by: Shuai Zhang +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index cdad817e632c6..74ecf9523c351 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2318,7 +2318,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + if (!qcadev->bt_en && + (data->soc_type == QCA_WCN6750 || +- data->soc_type == QCA_WCN6855)) ++ data->soc_type == QCA_WCN6855 || ++ data->soc_type == QCA_WCN7850)) + power_ctrl_enabled = false; + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch b/queue-6.6/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch new file mode 100644 index 0000000000..7c9987e23b --- /dev/null +++ b/queue-6.6/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch @@ -0,0 +1,72 @@ +From 36d33b6774b54966d18f7e412bd715f73a005ab8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:54:43 +0800 +Subject: Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling + +From: Shuai Zhang + +[ Upstream commit c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f ] + +When a Bluetooth controller encounters a coredump, it triggers the +Subsystem Restart (SSR) mechanism. The controller first reports the +coredump data and, once the upload is complete, sends a hw_error +event. The host relies on this event to proceed with subsequent +recovery actions. + +If the host has not finished processing the coredump data when the +hw_error event is received, it waits until either the processing is +complete or the 8-second timeout expires before handling the event. + +The current implementation clears QCA_MEMDUMP_COLLECTION using +clear_bit(), which does not wake up waiters sleeping in +wait_on_bit_timeout(). As a result, the waiting thread may remain +blocked until the timeout expires even if the coredump collection +has already completed. + +Fix this by clearing QCA_MEMDUMP_COLLECTION with +clear_and_wake_up_bit(), which also wakes up the waiting thread and +allows the hw_error handling to proceed immediately. + +Test case: +- Trigger a controller coredump using: + hcitool cmd 0x3f 0c 26 +- Tested on QCA6390. +- Capture HCI logs using btmon. +- Verify that the delay between receiving the hw_error event and + initiating the power-off sequence is reduced compared to the + timeout-based behavior. + +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Paul Menzel +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 74ecf9523c351..9f42ea37ebce3 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -1089,7 +1089,7 @@ static void qca_controller_memdump(struct work_struct *work) + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; +@@ -1167,7 +1167,7 @@ static void qca_controller_memdump(struct work_struct *work) + kfree(qca->qca_memdump); + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } + + mutex_unlock(&qca->hci_memdump_lock); +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-6.6/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..ce3858c867 --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From 6ea79caea79f618074efb5fa6f37aa0cd41c021a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index bbaf0070ca617..8bc7758095d58 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6636,6 +6636,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); +-- +2.53.0 + diff --git a/queue-6.6/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-6.6/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..cdd123d6f7 --- /dev/null +++ b/queue-6.6/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From 4cf8fa35f89345bdbc74358aa31f05f4a8d01b04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index d708cf3e6207f..a00829205c357 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1999,12 +1999,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-6.6/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch b/queue-6.6/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch new file mode 100644 index 0000000000..021641cf13 --- /dev/null +++ b/queue-6.6/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch @@ -0,0 +1,52 @@ +From b567922f053318103402cadbf7473b16260e3bca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:15 +0200 +Subject: bpf, sockmap: Annotate af_unix sock:: Sk_state data-races + +From: Michal Luczaj + +[ Upstream commit a25566084e391348385a72dd507e0cc0c268dd5d ] + +sock_map_sk_state_allowed() and sock_map_redirect_allowed() read af_unix +socket sk_state locklessly. + +Use READ_ONCE(). Note that for sock_map_redirect_allowed() change affects +not only af_unix, but all non-TCP sockets (UDP, af_vsock). + +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-1-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/core/sock_map.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock_map.c b/net/core/sock_map.c +index 3a53b6a0e76e2..6e7100cf9430c 100644 +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -527,7 +527,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return sk->sk_state != TCP_LISTEN; + else +- return sk->sk_state == TCP_ESTABLISHED; ++ return READ_ONCE(sk->sk_state) == TCP_ESTABLISHED; + } + + static bool sock_map_sk_is_suitable(const struct sock *sk) +@@ -540,7 +540,7 @@ static bool sock_map_sk_state_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); + if (sk_is_stream_unix(sk)) +- return (1 << sk->sk_state) & TCPF_ESTABLISHED; ++ return (1 << READ_ONCE(sk->sk_state)) & TCPF_ESTABLISHED; + if (sk_is_vsock(sk) && + (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) + return (1 << sk->sk_state) & TCPF_ESTABLISHED; +-- +2.53.0 + diff --git a/queue-6.6/btrfs-apply-first-key-check-for-readahead-when-possi.patch b/queue-6.6/btrfs-apply-first-key-check-for-readahead-when-possi.patch new file mode 100644 index 0000000000..072c2d0737 --- /dev/null +++ b/queue-6.6/btrfs-apply-first-key-check-for-readahead-when-possi.patch @@ -0,0 +1,129 @@ +From f1669fb4c50a6e6f5153cc49c312e1634db844b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 20:31:05 +0930 +Subject: btrfs: apply first key check for readahead when possible + +From: Qu Wenruo + +[ Upstream commit a86a283430e1a44907b142c4f53e1f3ad24e87ae ] + +Currently for tree block readahead we never pass a +btrfs_tree_parent_check with @has_first_key set. + +Without @has_first_key set, btrfs will skip the following extra +checks: + +- Header generation check + This is a minor one. + +- Empty leaf/node checks + This is more serious, for certain trees like the csum tree, they are + allowed to be empty, thus an empty leaf can pass the tree checker. + But if there is a parent node for such an empty leaf, it indicates + corruption. + + Without @has_first_key set, we can no longer detect such a problem. + + In fact there is already a fuzzed image report that a corrupted csum + leaf which has zero nritems but still has a parent node can trigger + a BUG_ON() during csum deletion. + +However there are only two call sites of btrfs_readahead_tree_block(): + +- Inside relocate_tree_blocks() + At this call site we are trying to grab the first key of the tree + block, thus we are not able to pass a @first_key parameter. + +- Inside btrfs_readahead_node_child() + This is the more common call site, where we have the parent node and + want to readahead the child tree blocks. + + In this case we can easily grab the node key and pass it for checks. + +Add a new parameter @first_key to btrfs_readahead_tree_block() and pass +the node key to it inside btrfs_readahead_node_child(). + +This should plug the gap in empty leaf detection during readahead. + +Link: https://lore.kernel.org/linux-btrfs/20260409071255.3358044-1-gality369@gmail.com/ +Reviewed-by: David Sterba +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 14 ++++++++++++-- + fs/btrfs/extent_io.h | 3 ++- + fs/btrfs/relocation.c | 2 +- + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 536c400e5964f..7fe6c098ec725 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -4912,7 +4912,8 @@ int try_release_extent_buffer(struct page *page) + * to read the block we will not block on anything. + */ + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level) ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key) + { + struct btrfs_tree_parent_check check = { + .has_first_key = 0, +@@ -4922,6 +4923,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb; + int ret; + ++ if (first_key) { ++ memcpy(&check.first_key, first_key, sizeof(struct btrfs_key)); ++ check.has_first_key = true; ++ } ++ + eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); + if (IS_ERR(eb)) + return; +@@ -4948,9 +4954,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + */ + void btrfs_readahead_node_child(struct extent_buffer *node, int slot) + { ++ struct btrfs_key node_key; ++ ++ btrfs_node_key_to_cpu(node, &node_key, slot); + btrfs_readahead_tree_block(node->fs_info, + btrfs_node_blockptr(node, slot), + btrfs_header_owner(node), + btrfs_node_ptr_generation(node, slot), +- btrfs_header_level(node) - 1); ++ btrfs_header_level(node) - 1, ++ &node_key); + } +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index ee955527f2985..a4f1c51cb82c6 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -214,7 +214,8 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num, + struct btrfs_tree_parent_check *parent_check); + void wait_on_extent_buffer_writeback(struct extent_buffer *eb); + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level); ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key); + void btrfs_readahead_node_child(struct extent_buffer *node, int slot); + + static inline int num_extent_pages(const struct extent_buffer *eb) +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 0f05eb97925fd..aa0e71125feab 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2741,7 +2741,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, + if (!block->key_ready) + btrfs_readahead_tree_block(fs_info, block->bytenr, + block->owner, 0, +- block->level); ++ block->level, NULL); + } + + /* Get first keys */ +-- +2.53.0 + diff --git a/queue-6.6/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-6.6/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..6408f94f20 --- /dev/null +++ b/queue-6.6/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 1674878a25a4d946630ae3dc92030837e5f09a17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index a54649a5e0785..f8634b0d6230e 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -413,10 +413,10 @@ static u64 calc_available_free_space(struct btrfs_fs_info *fs_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + return avail; +-- +2.53.0 + diff --git a/queue-6.6/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-6.6/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..a503026ff1 --- /dev/null +++ b/queue-6.6/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From b97095b005a82077bdbf0deecf557c9e58366f34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index 07bf07431a7f4..ebdea53dea1b5 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -527,6 +527,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-6.6/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-6.6/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..04088596a2 --- /dev/null +++ b/queue-6.6/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From 3d54eedbcad524438cc6e12e89d945db3d105892 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 1fb635a999760..6ad9f1eff80fc 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -267,7 +267,11 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -410,7 +414,11 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1471,7 +1479,11 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-6.6/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-6.6/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..a8970b7c8a --- /dev/null +++ b/queue-6.6/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From b2dfaf3a922424c7b24da2bd8fb933d46f5aa3b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 3bc6c99ed2e38..0d98d1c953705 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3177,7 +3177,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-6.6/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch b/queue-6.6/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch new file mode 100644 index 0000000000..bfa3529e8e --- /dev/null +++ b/queue-6.6/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch @@ -0,0 +1,75 @@ +From c490716c2b5c467dbd755cff027c4a138025370e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:58:56 +0100 +Subject: btrfs: tracepoints: fix sleep while in atomic context in + btrfs_sync_file() + +From: Filipe Manana + +[ Upstream commit c73370c677646e86fc4b1780fb07027bdf847375 ] + +The trace event btrfs_sync_file() is called in an atomic context (all trace +events are) and its call to dput(), which is needed due to the call to +dget_parent(), can sleep, triggering a kernel splat. + +This can be reproduced by enabling the trace event and running btrfs/056 +from fstests for example. The splat shown in dmesg is the following: + + [53.919] BUG: sleeping function called from invalid context at fs/dcache.c:970 + [53.947] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 32773, name: xfs_io + [53.988] preempt_count: 2, expected: 0 + [53.967] RCU nest depth: 0, expected: 0 + [53.943] Preemption disabled at: + [53.944] [<0000000000000000>] 0x0 + [54.078] CPU: 0 UID: 0 PID: 32773 Comm: xfs_io Tainted: G W 7.1.0-rc1-btrfs-next-232+ #1 PREEMPT(full) + [54.070] Tainted: [W]=WARN + [54.071] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [54.072] Call Trace: + [54.074] + [54.076] dump_stack_lvl+0x56/0x80 + [54.079] __might_resched.cold+0xd6/0x10f + [54.072] dput.part.0+0x24/0x110 + [54.078] trace_event_raw_event_btrfs_sync_file+0x75/0x140 [btrfs] + [54.089] btrfs_sync_file+0x1ed/0x530 [btrfs] + [54.087] ? __handle_mm_fault+0x8ae/0xed0 + [54.089] btrfs_do_write_iter+0x172/0x210 [btrfs] + [54.091] vfs_write+0x21f/0x450 + [54.094] __x64_sys_pwrite64+0x8d/0xc0 + [54.096] ? do_user_addr_fault+0x20c/0x670 + [54.099] do_syscall_64+0x60/0xf20 + [54.092] ? clear_bhb_loop+0x60/0xb0 + [54.094] entry_SYSCALL_64_after_hwframe+0x76/0x7e + +So stop using dget_parent() and dput() and access the parent dentry +directly as dentry->d_parent. This is also what ext4 is doing in +its equivalent trace event ext4_sync_file_enter(). + +Fixes: a85b46db143f ("btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file()") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + include/trace/events/btrfs.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index 2364c68df76c4..e06dbddc2872f 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -791,10 +791,8 @@ TRACE_EVENT(btrfs_sync_file, + TP_fast_assign( + struct dentry *dentry = file_dentry(file); + struct inode *inode = file_inode(file); +- struct dentry *parent = dget_parent(dentry); +- struct inode *parent_inode = d_inode(parent); ++ struct inode *parent_inode = d_inode(dentry->d_parent); + +- dput(parent); + TP_fast_assign_fsid(btrfs_sb(inode->i_sb)); + __entry->ino = btrfs_ino(BTRFS_I(inode)); + __entry->parent = btrfs_ino(BTRFS_I(parent_inode)); +-- +2.53.0 + diff --git a/queue-6.6/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-6.6/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..6f9f61c200 --- /dev/null +++ b/queue-6.6/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From 657257210ad35db71ec76d953c946b17f791a5dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index c7746baa86f8c..e2d03997ef631 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3564,7 +3564,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-6.6/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..412098df52 --- /dev/null +++ b/queue-6.6/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From 50ffc43e660f81938af220ecd19f4a0bc6db5866 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index 20bb72565f0ed..79ab8c8f3217d 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -771,6 +771,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-6.6/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-6.6/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..1297a355fb --- /dev/null +++ b/queue-6.6/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From 669efc99952fd17d5be52116bc5fdc997d43a175 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index 348eeab0a906b..c495f529f07e1 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -338,13 +338,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-6.6/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-6.6/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..2d669c85f1 --- /dev/null +++ b/queue-6.6/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 15a08626133237e78a3b95bf84177c336c9fb096 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index 202ca1a3105d5..3c3f4f06c00dd 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -2896,6 +2896,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-6.6/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..d0a3dbd6dc --- /dev/null +++ b/queue-6.6/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From a640926896fb4a05a6dba6db0df1455dd715c21f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 74078b90653f3..e12882372e4e7 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1858,3 +1858,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 24e4af14fcca4..2e26a46f535d2 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -144,6 +144,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 5522f8e9443f2..c15f3368aede1 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2964,6 +2964,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2980,6 +2983,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3551,7 +3568,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-6.6/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..b39684f97e --- /dev/null +++ b/queue-6.6/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From ddda0f2e94cd059ed8c1dd6c7c167befd77e6486 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index ac2a71e80723d..4616104093ced 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1940,7 +1940,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-display-merge-pipes-for-validate.patch b/queue-6.6/drm-amd-display-merge-pipes-for-validate.patch new file mode 100644 index 0000000000..6408c7e15b --- /dev/null +++ b/queue-6.6/drm-amd-display-merge-pipes-for-validate.patch @@ -0,0 +1,43 @@ +From 524886360440deeecac66f9d1e816928dcc5e0aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:48:11 -0500 +Subject: drm/amd/display: Merge pipes for validate + +From: Harry Wentland + +[ Upstream commit 606f6b171326152ef08d0ef0ad49f52034edca07 ] + +Validation expects to operate on non-split pipes. This is +seen in dcn20_fast_validate_bw, which merges pipes for +validation. We weren't doing that in the non-fast path +which lead to validation failures when operating with +4-to-1 MPC and a writeback connector. + +Co-developed by Claude Sonnet 4.5 + +Assisted-by: Claude:claude-sonnet-4.5 +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Harry Wentland +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +index de83acd12250d..881b89752aa08 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +@@ -1643,6 +1643,8 @@ noinline bool dcn30_internal_validate_bw( + if (!pipes) + return false; + ++ dcn20_merge_pipes_for_validate(dc, context); ++ + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch b/queue-6.6/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch new file mode 100644 index 0000000000..df6154b926 --- /dev/null +++ b/queue-6.6/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch @@ -0,0 +1,46 @@ +From 8f8a5e769130a925dd0180e35fc5314b98ef67c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 18:53:40 +0800 +Subject: drm/amdgpu: fix shift-out-of-bounds when updating umc active mask + +From: Hawking Zhang + +[ Upstream commit 1394a4926f4bcff0dc6ac6deea5beeb2844297f0 ] + +UMC node_inst_num can exceed 32, causing +(1 << node_inst_num) to shift a 32-bit int +out of bounds + +Signed-off-by: Hawking Zhang +Reviewed-by: Likun Gao +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index 5c4aa5ff873b6..1fd91d8689c8d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -609,7 +609,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + struct harvest_table *harvest_info; + u16 offset; + int i; +- uint32_t umc_harvest_config = 0; ++ u64 umc_harvest_config = 0; + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset); +@@ -659,7 +659,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + } + } + +- adev->umc.active_mask = ((1 << adev->umc.node_inst_num) - 1) & ++ adev->umc.active_mask = ((1ULL << adev->umc.node_inst_num) - 1ULL) & + ~umc_harvest_config; + } + +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-6.6/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..4bdc463c6b --- /dev/null +++ b/queue-6.6/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 673188075b999f9f21087b7ee90f1c4dbf699b25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 05712d322024a..742434c214243 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1735,6 +1735,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-6.6/drm-gem-dma-set-vm_dontdump-for-mmap.patch b/queue-6.6/drm-gem-dma-set-vm_dontdump-for-mmap.patch new file mode 100644 index 0000000000..3a3072d032 --- /dev/null +++ b/queue-6.6/drm-gem-dma-set-vm_dontdump-for-mmap.patch @@ -0,0 +1,49 @@ +From 2b7529411096d63eae22871f5ddeaf4f9e566ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 12:00:32 +0800 +Subject: drm/gem-dma: set VM_DONTDUMP for mmap + +From: Chen-Yu Tsai + +[ Upstream commit e3eb0e70815cc02ea15298818e37d8b0a0930ab1 ] + +When the mmap function was converted from a file op to a GEM object +function in commit f5ca8eb6f9bd ("drm/cma-helper: Implement mmap as GEM +CMA object functions") some VM flags were not lifted from drm_gem_mmap(): + + - VM_IO + - VM_DONTEXPAND + - VM_DONTDUMP + +VM_DONTEXPAND was added back in commit 59f39bfa6553 ("drm/cma-helper: +Set VM_DONTEXPAND for mmap"). VM_IO doesn't make sense since these are +memory buffers, while "IO tells people not to look at these pages +(accesses can have side effects)". + +Add back VM_DONTDUMP. This matches the behavior of most other GEM +implementations. + +Reviewed-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260317040034.617585-1-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gem_dma_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c +index 870b90b78bc4e..8128002cdb7b1 100644 +--- a/drivers/gpu/drm/drm_gem_dma_helper.c ++++ b/drivers/gpu/drm/drm_gem_dma_helper.c +@@ -530,7 +530,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct * + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); +- vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); ++ vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP); + + if (dma_obj->map_noncoherent) { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); +-- +2.53.0 + diff --git a/queue-6.6/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-6.6/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..c642e46beb --- /dev/null +++ b/queue-6.6/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From 116c979a81ab78ebcf45ca27b312e5738dc14806 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index f154b3a7c2c2d..1102c91881857 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -608,6 +608,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -667,6 +682,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -712,30 +729,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch b/queue-6.6/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch new file mode 100644 index 0000000000..f26fa46dde --- /dev/null +++ b/queue-6.6/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch @@ -0,0 +1,60 @@ +From 8e1eacaf07a2a22f7b7f80064c7fb4ab20abec00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:17:00 +0100 +Subject: drm/msm/dpu: fix vblank IRQ registration before atomic_mode_set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit 961c900628fef77ad07b4bc4c868e47b9a1269c7 ] + +dpu_encoder_toggle_vblank_for_crtc() can call control_vblank_irq() +at any time in response to a userspace vblank request, independently +of the atomic commit sequence. If this happens before the encoder's +first atomic_mode_set(), irq[INTR_IDX_RDPTR] is still zero. + +Passing irq_idx=0 to dpu_core_irq_register_callback() is treated as +invalid, and DPU_IRQ_REG(0) and DPU_IRQ_BIT(0) produce misleading +values of 134217727 and 31 respectively due to unsigned wraparound +in the (irq_idx - 1) macros, resulting in the confusing error: + + [dpu error]invalid IRQ=[134217727, 31] + +Since irq[INTR_IDX_RDPTR] will be properly populated by +atomic_mode_set() and registered by irq_enable() as part of the +normal modeset sequence, silently skip the vblank IRQ registration +when the index has not yet been initialized. This matches the +existing pattern of the master encoder check above it. + +Signed-off-by: Cédric Bellegarde +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/712752/ +Link: https://lore.kernel.org/r/20260318171700.394945-1-cedric.bellegarde@adishatz.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index fd2400c4665d2..249f7b9c1c93b 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -258,6 +258,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + ++ /* IRQ not yet initialized */ ++ if (!phys_enc->irq[INTR_IDX_RDPTR]) { ++ ret = -EINVAL; ++ goto end; ++ } ++ + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-6.6/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..2e9468427b --- /dev/null +++ b/queue-6.6/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From fb4f49ae89f033eca00aa3e367e773a28da5e4d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index 52d78521e4124..24d8031a533df 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - const: marvell,armada7040 +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch b/queue-6.6/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch new file mode 100644 index 0000000000..5b24d8b320 --- /dev/null +++ b/queue-6.6/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch @@ -0,0 +1,37 @@ +From 9c90bb6bc6338c0cd2a2b85bf233927b1a42cdfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:42 +0100 +Subject: dt-bindings: rtc: microcrystal,rv3028: Allow to specify vdd-supply + +From: Frieder Schrempf + +[ Upstream commit 10663044bee592ba049a2aa37f4431fbdf93b739 ] + +In case the VDD supply voltage regulator of the RTC needs to be +specified explicitly, allow to set vdd-supply. + +Signed-off-by: Frieder Schrempf +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20260309085749.25747-2-frieder@fris.de +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +index 5ade5dfad048a..e61f6dd9d3bb5 100644 +--- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml ++++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +@@ -29,6 +29,8 @@ properties: + - 9000 + - 15000 + ++ vdd-supply: true ++ + required: + - compatible + - reg +-- +2.53.0 + diff --git a/queue-6.6/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-6.6/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..578a9f9dd1 --- /dev/null +++ b/queue-6.6/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From 2c26323389cb1c656cc80f77178c297fc52ea7f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 2dc927ba067fe..aa1f88fa94bf5 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -573,6 +573,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-6.6/enic-add-v2-sr-iov-vf-device-id.patch b/queue-6.6/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..62cd67b708 --- /dev/null +++ b/queue-6.6/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,54 @@ +From 7dc6423e22c3f4f9cdbb3cef061a707de3e34d50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index 48701032c20c5..48d4dc307c9ea 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,6 +66,7 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + #define RX_COPYBREAK_DEFAULT 256 + +@@ -74,6 +75,7 @@ static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -309,7 +311,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-6.6/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-6.6/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..a8c68fc1c7 --- /dev/null +++ b/queue-6.6/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From 0148d10ee9293e57aec5b79a218ff1a4a79fb020 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-6.6/exfat-fix-bitwise-operation-having-different-size.patch b/queue-6.6/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..aebde9a16e --- /dev/null +++ b/queue-6.6/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From 80c266f53c4f3d53e8ffb27eaa921cddfe4b6a81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 6139a57fde70a..1bee8d7b3c361 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -267,7 +267,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-6.6/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-6.6/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..35f434c004 --- /dev/null +++ b/queue-6.6/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From 37f06512b2d9bb0713e20900effdedf1e8cdc899 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index 13329baeafbcf..378c6aedd7f78 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -614,7 +614,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-6.6/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch b/queue-6.6/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch new file mode 100644 index 0000000000..6bb98fde23 --- /dev/null +++ b/queue-6.6/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch @@ -0,0 +1,45 @@ +From cb87f72846c05d74f47ea871b6c99ebceb5235a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 02:20:52 +0000 +Subject: ext2: avoid drop_nlink() during unlink of zero-nlink inode in + ext2_unlink() + +From: Ziyi Guo + +[ Upstream commit 19134a133184fcc49c41cf42797cb2e7fef76065 ] + +ext2_unlink() calls inode_dec_link_count() unconditionally, which +invokes drop_nlink(). If the inode was loaded from a corrupted disk +image with i_links_count == 0, drop_nlink() +triggers WARN_ON(inode->i_nlink == 0) + +Follow the ext4 pattern from __ext4_unlink(): check i_nlink before +decrementing. If already zero, skip the decrement. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260211022052.973114-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/namei.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c +index 059517068adca..bf8984a96fe11 100644 +--- a/fs/ext2/namei.c ++++ b/fs/ext2/namei.c +@@ -292,7 +292,10 @@ static int ext2_unlink(struct inode *dir, struct dentry *dentry) + goto out; + + inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); +- inode_dec_link_count(inode); ++ ++ if (inode->i_nlink) ++ inode_dec_link_count(inode); ++ + err = 0; + out: + return err; +-- +2.53.0 + diff --git a/queue-6.6/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-6.6/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..e3098c1bd4 --- /dev/null +++ b/queue-6.6/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From a73bb0c08ddb4a00c88af7c6f04c256aa6a50566 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index 6eccee0336171..d23368eaf9cf8 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -638,7 +638,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-6.6/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch b/queue-6.6/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch new file mode 100644 index 0000000000..8bafdf6a74 --- /dev/null +++ b/queue-6.6/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch @@ -0,0 +1,98 @@ +From 699392b2d6967a244795349106844de216d1dd07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:29:14 +0530 +Subject: ext4: unmap invalidated folios from page tables in + mpage_release_unused_pages() + +From: Deepanshu Kartikey + +[ Upstream commit 9b25f381de6b8942645f43735cb0a4fb0ab3a6d1 ] + +When delayed block allocation fails (e.g., due to filesystem corruption +detected in ext4_map_blocks()), the writeback error handler calls +mpage_release_unused_pages(invalidate=true) which invalidates affected +folios by clearing their uptodate flag via folio_clear_uptodate(). + +However, these folios may still be mapped in process page tables. If a +subsequent operation (such as ftruncate calling ext4_block_truncate_page) +triggers a write fault, the existing page table entry allows access to +the now-invalidated folio. This leads to ext4_page_mkwrite() being called +with a non-uptodate folio, which then gets marked dirty, triggering: + + WARNING: CPU: 0 PID: 5 at mm/page-writeback.c:2960 + __folio_mark_dirty+0x578/0x880 + + Call Trace: + fault_dirty_shared_page+0x16e/0x2d0 + do_wp_page+0x38b/0xd20 + handle_pte_fault+0x1da/0x450 + +The sequence leading to this warning is: + +1. Process writes to mmap'd file, folio becomes uptodate and dirty +2. Writeback begins, but delayed allocation fails due to corruption +3. mpage_release_unused_pages(invalidate=true) is called: + - block_invalidate_folio() clears dirty flag + - folio_clear_uptodate() clears uptodate flag + - But folio remains mapped in page tables +4. Later, ftruncate triggers ext4_block_truncate_page() +5. This causes a write fault on the still-mapped folio +6. ext4_page_mkwrite() is called with folio that is !uptodate +7. block_page_mkwrite() marks buffers dirty +8. fault_dirty_shared_page() tries to mark folio dirty +9. block_dirty_folio() calls __folio_mark_dirty(warn=1) +10. WARNING triggers: WARN_ON_ONCE(warn && !uptodate && !dirty) + +Fix this by unmapping folios from page tables before invalidating them +using unmap_mapping_pages(). This ensures that subsequent accesses +trigger new page faults rather than reusing invalidated folios through +stale page table entries. + +Note that this results in data loss for any writes to the mmap'd region +that couldn't be written back, but this is expected behavior when +writeback fails due to filesystem corruption. The existing error message +already states "This should not happen!! Data will be lost". + +Reported-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Tested-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a +Suggested-by: Matthew Wilcox +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20251205055914.1393799-1-kartikey406@gmail.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d72e7f3263eaf..69c5506107412 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1628,8 +1628,22 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd, + BUG_ON(!folio_test_locked(folio)); + BUG_ON(folio_test_writeback(folio)); + if (invalidate) { +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { + folio_clear_dirty_for_io(folio); ++ /* ++ * Unmap folio from page ++ * tables to prevent ++ * subsequent accesses through ++ * stale PTEs. This ensures ++ * future accesses trigger new ++ * page faults rather than ++ * reusing the invalidated ++ * folio. ++ */ ++ unmap_mapping_pages(folio->mapping, ++ folio->index, ++ folio_nr_pages(folio), false); ++ } + block_invalidate_folio(folio, 0, + folio_size(folio)); + folio_clear_uptodate(folio); +-- +2.53.0 + diff --git a/queue-6.6/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-6.6/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..c9dd7902af --- /dev/null +++ b/queue-6.6/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From 572c7492e45c617f42fce340081b20da51247461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 5654608a11923..6ace6fe8d03d8 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -870,6 +870,9 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-6.6/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-6.6/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..a8109942b6 --- /dev/null +++ b/queue-6.6/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From f37d37a361efab8d2c7641fce4f77840f2bdc3e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index b5acad8eb2796..23e7566bb49e3 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1119,7 +1119,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-6.6/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-6.6/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..ada4ab8b67 --- /dev/null +++ b/queue-6.6/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From 62ef6d35221b76b38d1c3a74ff4ff8c9b6daad02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index 205ccbe8f1720..30a0f606ea419 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-6.6/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-6.6/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..1434f487bb --- /dev/null +++ b/queue-6.6/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From 0760e1bdc86757e492f6ee95c28f04bc4d77b2a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index beec5c8d4d083..015577966d031 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-6.6/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-6.6/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..f5914811f5 --- /dev/null +++ b/queue-6.6/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From e984690cd7cd3dd9205edc5e85c706713fd58a66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 1fef8a9b1a0fd..7b440835d2971 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-6.6/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-6.6/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..831c748d15 --- /dev/null +++ b/queue-6.6/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 38fa9cd3f0b3a8e2feb5bc6024766ae8873258ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 4a9b5e4719eea..954594a854809 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-6.6/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-6.6/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..29cf71a01a --- /dev/null +++ b/queue-6.6/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From 86023e3e68767269c24f873df5baf7886fc85f02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index a03b4bce5fbfd..2ec1011c7d1a9 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1008,7 +1008,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-6.6/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-6.6/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..d5002c1208 --- /dev/null +++ b/queue-6.6/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From afdd82ad09c8f87191fba223aa734e24391ded8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index a4cc56df549a6..bf38d2a9ff232 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1582,7 +1582,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + if (boot2) { +-- +2.53.0 + diff --git a/queue-6.6/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-6.6/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..197335bdf0 --- /dev/null +++ b/queue-6.6/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 3069e2e0792a54f17d5f20550521baf0b60e26cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 9e4394d58f9b2..641ec8199b87f 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-6.6/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-6.6/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..984b1d6b84 --- /dev/null +++ b/queue-6.6/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From 56f7204f0459b79e0fb17a29009bd6dff94274b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 722b885831b1a..030835f487fef 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -120,6 +120,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-6.6/fuse-validate-outarg-offset-and-size-in-notify-store.patch b/queue-6.6/fuse-validate-outarg-offset-and-size-in-notify-store.patch new file mode 100644 index 0000000000..8c15edff0c --- /dev/null +++ b/queue-6.6/fuse-validate-outarg-offset-and-size-in-notify-store.patch @@ -0,0 +1,81 @@ +From 92004b604447bf20a44116a2fd424d630938c877 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:44:46 -0800 +Subject: fuse: validate outarg offset and size in notify store/retrieve + +From: Joanne Koong + +[ Upstream commit 65161470f95bb579a72673bf303ecf0800b9054b ] + +Add validation checking for outarg offset and outarg size values passed +in by the server. MAX_LFS_FILESIZE is the maximum file size supported. +The fuse_notify_store_out and fuse_notify_retrieve_out structs take in +a uint64_t offset. + +Add logic to ensure: +* outarg.offset is less than MAX_LFS_FILESIZE +* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE +* potential uint64_t overflow is fixed when adding outarg.offset and + outarg.size. + +Signed-off-by: Joanne Koong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 7573dcd8f5d44..6caf7de33454b 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1589,7 +1589,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + if (size - sizeof(outarg) != outarg.size) + goto out_finish; + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + nodeid = outarg.nodeid; ++ num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset); + + down_read(&fc->killsb); + +@@ -1602,13 +1606,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + index = outarg.offset >> PAGE_SHIFT; + offset = outarg.offset & ~PAGE_MASK; + file_size = i_size_read(inode); +- end = outarg.offset + outarg.size; ++ end = outarg.offset + num; + if (end > file_size) { + file_size = end; +- fuse_write_update_attr(inode, file_size, outarg.size); ++ fuse_write_update_attr(inode, file_size, num); + } + +- num = outarg.size; + while (num) { + struct page *page; + unsigned int this_num; +@@ -1686,7 +1689,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, + num = min(outarg->size, fc->max_write); + if (outarg->offset > file_size) + num = 0; +- else if (outarg->offset + num > file_size) ++ else if (num > file_size - outarg->offset) + num = file_size - outarg->offset; + + num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -1762,6 +1765,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, + + fuse_copy_finish(cs); + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + down_read(&fc->killsb); + err = -ENOENT; + nodeid = outarg.nodeid; +-- +2.53.0 + diff --git a/queue-6.6/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-6.6/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..4481bcd14e --- /dev/null +++ b/queue-6.6/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 43bb2f747085266cd845a6aed64fb0aafbcceedf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 9a4d55f703bb5..f0faac5796bbf 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.6/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-6.6/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..1be559e47e --- /dev/null +++ b/queue-6.6/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 966c44a44920aa38054bd73e9bf7bd08f113ccd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index 49446a030f108..672f0f5b1ee79 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-6.6/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-6.6/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..f698281a84 --- /dev/null +++ b/queue-6.6/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From a064c9cc659edc7023bc7742a9e1cc556f2f0ea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 5c79ba1f229c4..6487ff529680e 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -55,7 +55,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-6.6/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-6.6/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..e7022be9eb --- /dev/null +++ b/queue-6.6/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 7163fef833e2526111bc81ee06397f6dc916be2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 8f5827554e1e8..ab17e25100d7e 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -52,7 +52,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset, +-- +2.53.0 + diff --git a/queue-6.6/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-6.6/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..6ac41fd695 --- /dev/null +++ b/queue-6.6/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From cdb0ea5f4fd77a6b336663d7cdbc40b882a4b6be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index e55d28a8a66f2..a8ab97bf49770 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -283,7 +283,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-6.6/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-6.6/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..17fcd76578 --- /dev/null +++ b/queue-6.6/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From bee19ffcf6f9298b33e861cf374d00b381318109 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 3d60ea25711fc..df2377f3fc8f3 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -701,11 +701,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -717,7 +722,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-6.6/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..9dcbfea0c1 --- /dev/null +++ b/queue-6.6/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From 36444d1b6668955a03bdc14c2ffcd29f5977ead9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-6.6/hfsplus-fix-generic-642-failure.patch b/queue-6.6/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..c7887c3d4c --- /dev/null +++ b/queue-6.6/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From c5676c564d30233256005809c1dab89aae3db5f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 1918544a78716..b26cd7504e113 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-6.6/hid-logitech-hidpp-fix-race-condition-when-accessing.patch b/queue-6.6/hid-logitech-hidpp-fix-race-condition-when-accessing.patch new file mode 100644 index 0000000000..9a86bcb96d --- /dev/null +++ b/queue-6.6/hid-logitech-hidpp-fix-race-condition-when-accessing.patch @@ -0,0 +1,112 @@ +From ceb1da03c9610a31bdf082d638be63ac25d53d92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:48:11 +0000 +Subject: HID: logitech-hidpp: fix race condition when accessing stale stack + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit e2aaf2d3ad92ac4a8afa6b69ad4c38e7747d3d6e ] + +The driver uses hidpp->send_receive_buf to point to a stack-allocated +buffer in the synchronous command path (__do_hidpp_send_message_sync). +However, this pointer is not cleared when the function returns. + +If an event is processed (e.g. by a different thread) while the +send_mutex is held by a new command, but before that command has +updated send_receive_buf, the handler (hidpp_raw_hidpp_event) will +observe that the mutex is locked and dereference the stale pointer. + +This results in an out-of-bounds access on a different thread's kernel +stack (or a NULL pointer dereference on the very first command). + +Fix this by: +1. Clearing hidpp->send_receive_buf to NULL before releasing the mutex + in the synchronous command path. +2. Moving the assignment of the local 'question' and 'answer' pointers + inside the mutex_is_locked() block in the handler, and adding + a NULL check before dereferencing. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index 339a227c457e7..99f727b2ca23c 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -305,21 +305,22 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + if (ret) { + dbg_hid("__hidpp_send_report returned err: %d\n", ret); + memset(response, 0, sizeof(struct hidpp_report)); +- return ret; ++ goto out; + } + + if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, + 5*HZ)) { + dbg_hid("%s:timeout waiting for response\n", __func__); + memset(response, 0, sizeof(struct hidpp_report)); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + + if (response->report_id == REPORT_ID_HIDPP_SHORT && + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + + if ((response->report_id == REPORT_ID_HIDPP_LONG || +@@ -327,10 +328,14 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + response->fap.feature_index == HIDPP20_ERROR) { + ret = response->fap.params[1]; + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + +- return 0; ++ ret = 0; ++ ++out: ++ hidpp->send_receive_buf = NULL; ++ return ret; + } + + /* +@@ -3868,8 +3873,7 @@ static int hidpp_input_configured(struct hid_device *hdev, + static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + int size) + { +- struct hidpp_report *question = hidpp->send_receive_buf; +- struct hidpp_report *answer = hidpp->send_receive_buf; ++ struct hidpp_report *question, *answer; + struct hidpp_report *report = (struct hidpp_report *)data; + int ret; + +@@ -3878,6 +3882,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + * previously sent command. + */ + if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { ++ question = hidpp->send_receive_buf; ++ answer = hidpp->send_receive_buf; ++ ++ if (!question) ++ return 0; ++ + /* + * Check for a correct hidpp20 answer or the corresponding + * error +-- +2.53.0 + diff --git a/queue-6.6/hid-playstation-validate-num_touch_reports-in-dualsh.patch b/queue-6.6/hid-playstation-validate-num_touch_reports-in-dualsh.patch new file mode 100644 index 0000000000..55244c63cd --- /dev/null +++ b/queue-6.6/hid-playstation-validate-num_touch_reports-in-dualsh.patch @@ -0,0 +1,64 @@ +From 89be3974dee4e392fbc566d4cbf7f69b74ebc4b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:47:37 +0000 +Subject: HID: playstation: validate num_touch_reports in DualShock 4 reports +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit 82a4fc46330910b4c1d9b189561439d468e3ff11 ] + +The DualShock 4 HID driver fails to validate the num_touch_reports field +received from the device in both USB and Bluetooth input reports. +A malicious device could set this field to a value larger than the +allocated size of the touch_reports array (3 for USB, 4 for Bluetooth), +leading to an out-of-bounds read in dualshock4_parse_report(). + +This can result in kernel memory disclosure when processing malicious +HID reports. + +Validate num_touch_reports against the array size for the respective +connection types before processing the touch data. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 4db50cacbf9af..b197f16f2546d 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -2199,6 +2199,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + size == DS4_INPUT_REPORT_USB_SIZE) { + struct dualshock4_input_report_usb *usb = (struct dualshock4_input_report_usb *)data; + ++ if (usb->num_touch_reports > ARRAY_SIZE(usb->touch_reports)) { ++ hid_err(hdev, "DualShock4 USB input report has invalid num_touch_reports=%d\n", ++ usb->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &usb->common; + num_touch_reports = min_t(u8, usb->num_touch_reports, + ARRAY_SIZE(usb->touch_reports)); +@@ -2214,6 +2220,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + return -EILSEQ; + } + ++ if (bt->num_touch_reports > ARRAY_SIZE(bt->touch_reports)) { ++ hid_err(hdev, "DualShock4 BT input report has invalid num_touch_reports=%d\n", ++ bt->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &bt->common; + num_touch_reports = min_t(u8, bt->num_touch_reports, + ARRAY_SIZE(bt->touch_reports)); +-- +2.53.0 + diff --git a/queue-6.6/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-6.6/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..56a307fb87 --- /dev/null +++ b/queue-6.6/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From 2aea2209e20b5a56c39022e027dee0f2eee35060 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index d9e33dde89899..9d396d2e534d0 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -234,7 +234,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-6.6/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-6.6/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..9219dc69f2 --- /dev/null +++ b/queue-6.6/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From 6f1d496447722a5e1b8386bda4dafbc5520cb505 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 9d396d2e534d0..7993fcabfe3a5 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -134,6 +134,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-6.6/hid-uclogic-fix-regression-of-input-name-assignment.patch b/queue-6.6/hid-uclogic-fix-regression-of-input-name-assignment.patch new file mode 100644 index 0000000000..9844755ebc --- /dev/null +++ b/queue-6.6/hid-uclogic-fix-regression-of-input-name-assignment.patch @@ -0,0 +1,44 @@ +From a078908f16b3a74f300801684e917d3289a907f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:33:16 +0200 +Subject: HID: uclogic: Fix regression of input name assignment + +From: Takashi Iwai + +[ Upstream commit 487359284509a6745e14b8c0518768bc277809b0 ] + +The previous fix for adding the devm_kasprintf() return check in the +commit bd07f751208b ("HID: uclogic: Add NULL check in +uclogic_input_configured()") changed the condition of hi->input->name +assignment, and it resulted in missing the proper input device name +when no custom suffix is defined. + +Restore the conditional to the original content to address the +regression. + +Fixes: bd07f751208b ("HID: uclogic: Add NULL check in uclogic_input_configured()") +Signed-off-by: Takashi Iwai +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-uclogic-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index 45de01dea4b1c..d4cf8846f326a 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -142,7 +142,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } else { ++ } ++ ++ if (suffix) { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); + if (!hi->input->name) +-- +2.53.0 + diff --git a/queue-6.6/i3c-master-move-bus_init-error-suppression.patch b/queue-6.6/i3c-master-move-bus_init-error-suppression.patch new file mode 100644 index 0000000000..eeea536ad5 --- /dev/null +++ b/queue-6.6/i3c-master-move-bus_init-error-suppression.patch @@ -0,0 +1,98 @@ +From 24a56977327373ed84c7f8ac87a93edadcb10784 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:31 +0100 +Subject: i3c: master: Move bus_init error suppression + +From: Jorge Marques + +[ Upstream commit 49775afa983e3e5ce8e7d00ee241791073be214d ] + +Prepare to fix improper Mx positive error propagation in later commits +by handling Mx error codes where the i3c_ccc_cmd command is allocated. +The CCC DISEC to broadcast address is invoked with +i3c_master_enec_disec_locked() and yields error I3C_ERROR_M2 if there +are no devices active on the bus. This is expected at the bus +initialization stage, where it is not known yet that there are no active +devices on the bus. Add bool suppress_m2 argument to +i3c_master_enec_disec_locked() and update the call site at +i3c_master_bus_init() with the exact corner case to not require +propagating positive Mx error codes. Other call site should not suppress +the error code, for example, if a driver requests to peripheral to +disable events and the transfer is not acknowledged, this is an error +and should not proceed. + +Reviewed-by: Frank Li +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-3-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index f74ef65d257d7..718edd8d01c11 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -945,7 +945,8 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master) + EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); + + static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, +- u8 addr, bool enable, u8 evts) ++ u8 addr, bool enable, u8 evts, ++ bool suppress_m2) + { + struct i3c_ccc_events *events; + struct i3c_ccc_cmd_dest dest; +@@ -965,6 +966,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + i3c_ccc_cmd_dest_cleanup(&dest); + ++ if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2) ++ ret = 0; ++ + return ret; + } + +@@ -985,7 +989,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, false, evts); ++ return i3c_master_enec_disec_locked(master, addr, false, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + +@@ -1006,7 +1010,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, true, evts); ++ return i3c_master_enec_disec_locked(master, addr, true, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + +@@ -1884,11 +1888,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + +- /* Disable all slave events before starting DAA. */ +- ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, +- I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +- I3C_CCC_EVENT_HJ); +- if (ret && ret != I3C_ERROR_M2) ++ /* ++ * Disable all slave events before starting DAA. When no active device ++ * is on the bus, returns Mx error code M2, this error is ignored. ++ */ ++ ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false, ++ I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | ++ I3C_CCC_EVENT_HJ, true); ++ if (ret) + goto err_bus_cleanup; + + /* +-- +2.53.0 + diff --git a/queue-6.6/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-6.6/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..38682129c1 --- /dev/null +++ b/queue-6.6/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 89d173e7e339aceeabbf450d7701861decaa6220 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index 850db8e0e6b00..14d765247d73c 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -537,14 +537,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + int ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-6.6/iio-abi-fix-current_trigger-description.patch b/queue-6.6/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..d070e388c1 --- /dev/null +++ b/queue-6.6/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From d9dfc52898dafbaf4a49d171b8b5137f75e5879e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index a2854dc9a8393..3024499deea22 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1300,7 +1300,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-6.6/io_uring-cancel-validate-opcode-for-ioring_async_can.patch b/queue-6.6/io_uring-cancel-validate-opcode-for-ioring_async_can.patch new file mode 100644 index 0000000000..afed83e85f --- /dev/null +++ b/queue-6.6/io_uring-cancel-validate-opcode-for-ioring_async_can.patch @@ -0,0 +1,53 @@ +From 1263c93d94b13c28c760363fc59b903f8495cbf4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:51:13 +0330 +Subject: io_uring/cancel: validate opcode for IORING_ASYNC_CANCEL_OP + +From: Amir Mohammad Jahangirzad + +[ Upstream commit 85a58309c0d5b5f5a4b65658312ceaf2c34c9bbf ] + +io_async_cancel_prep() reads the opcode selector from sqe->len and +stores it in cancel->opcode, which is an 8-bit field. Since sqe->len +is a 32-bit value, values larger than U8_MAX are implicitly truncated. + +This can cause unintended opcode matches when the truncated value +corresponds to a valid io_uring opcode. For example, submitting a value +such as 0x10b will be truncated to 0x0b (IORING_OP_TIMEOUT), allowing a +cancel request to match operations it did not intend to target. +Validate the opcode value before assigning it to the 8-bit field and +reject values outside the valid io_uring opcode range. + +Signed-off-by: Amir Mohammad Jahangirzad +Link: https://patch.msgid.link/20260331232113.615972-1-a.jahangirzad@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index a5d51471feebb..6346d44b51b9f 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -145,9 +145,16 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + cancel->fd = READ_ONCE(sqe->fd); + } + if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ u32 op; ++ + if (cancel->flags & IORING_ASYNC_CANCEL_ANY) + return -EINVAL; +- cancel->opcode = READ_ONCE(sqe->len); ++ ++ op = READ_ONCE(sqe->len); ++ if (op >= IORING_OP_LAST) ++ return -EINVAL; ++ ++ cancel->opcode = op; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch b/queue-6.6/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch new file mode 100644 index 0000000000..690cd4f7c6 --- /dev/null +++ b/queue-6.6/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch @@ -0,0 +1,98 @@ +From 0d496fc6550caaaaba730f62e2847c423cd04cd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:42:50 +0200 +Subject: iommu/amd: Invalidate IRT cache for DMA aliases + +From: Magnus Kalland + +[ Upstream commit 5aac28784dca6819e96e5f93e644cdee59e50f6e ] + +DMA aliasing causes interrupt remapping table entries (IRTEs) to be shared +between multiple device IDs. See commit 3c124435e8dd +("iommu/amd: Support multiple PCI DMA aliases in IRQ Remapping") for more +information on this. However, the AMD IOMMU driver currently invalidates +IRTE cache entries on a per-device basis whenever an IRTE is updated, not +for each alias. + +This approach leaves stale IRTE cache entries when an IRTE is cached under +one DMA alias but later updated and invalidated through a different alias. +In such cases, the original device ID is never invalidated, since it is +programmed via aliasing. + +This incoherency bug has been observed when IRTEs are cached for one +Non-Transparent Bridge (NTB) DMA alias, later updated via another. + +Fix this by invalidating the interrupt remapping table cache for all DMA +aliases when updating an IRTE. + +Co-developed-by: Lars B. Kristiansen +Signed-off-by: Lars B. Kristiansen +Co-developed-by: Jonas Markussen +Signed-off-by: Jonas Markussen +Co-developed-by: Tore H. Larsen +Signed-off-by: Tore H. Larsen +Signed-off-by: Magnus Kalland +Link: https://lore.kernel.org/linux-iommu/9204da81-f821-4034-b8ad-501e43383b56@amd.com/ +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 48cf9e9e15976..56b3bbe56f97e 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -2872,26 +2872,44 @@ EXPORT_SYMBOL(amd_iommu_device_info); + static struct irq_chip amd_ir_chip; + static DEFINE_SPINLOCK(iommu_table_lock); + ++static int iommu_flush_dev_irt(struct pci_dev *unused, u16 devid, void *data) ++{ ++ int ret; ++ struct iommu_cmd cmd; ++ struct amd_iommu *iommu = data; ++ ++ build_inv_irt(&cmd, devid); ++ ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ return ret; ++} ++ + static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid) + { + int ret; + u64 data; + unsigned long flags; +- struct iommu_cmd cmd, cmd2; ++ struct iommu_cmd cmd; ++ struct pci_dev *pdev = NULL; ++ struct iommu_dev_data *dev_data = search_dev_data(iommu, devid); + + if (iommu->irtcachedis_enabled) + return; + +- build_inv_irt(&cmd, devid); ++ if (dev_data && dev_data->dev && dev_is_pci(dev_data->dev)) ++ pdev = to_pci_dev(dev_data->dev); + + raw_spin_lock_irqsave(&iommu->lock, flags); + data = get_cmdsem_val(iommu); +- build_completion_wait(&cmd2, iommu, data); ++ build_completion_wait(&cmd, iommu, data); + +- ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ if (pdev) ++ ret = pci_for_each_dma_alias(pdev, iommu_flush_dev_irt, iommu); ++ else ++ ret = iommu_flush_dev_irt(NULL, devid, iommu); + if (ret) + goto out_err; +- ret = __iommu_queue_command_sync(iommu, &cmd2, false); ++ ++ ret = __iommu_queue_command_sync(iommu, &cmd, false); + if (ret) + goto out_err; + raw_spin_unlock_irqrestore(&iommu->lock, flags); +-- +2.53.0 + diff --git a/queue-6.6/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch b/queue-6.6/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch new file mode 100644 index 0000000000..5da4167e54 --- /dev/null +++ b/queue-6.6/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch @@ -0,0 +1,39 @@ +From 27ef5deff77688153daa8474376152c6aaa2159f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:58 +0800 +Subject: ipmi: ssif_bmc: cancel response timer on remove + +From: Jian Zhang + +[ Upstream commit 7fc3e2546cf3fa9a28a2acc92a512c779a8e5038 ] + +The response timer can stay armed across device teardown. If it fires after +remove, the callback dereferences the SSIF context and the i2c client after +teardown has started. + +Cancel the timer in remove so the callback cannot run after the device is +unregistered. + +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-1-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 5d5444b567a04..9f78b690de37f 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -858,6 +858,7 @@ static void ssif_bmc_remove(struct i2c_client *client) + { + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + ++ timer_delete_sync(&ssif_bmc->response_timer); + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + } +-- +2.53.0 + diff --git a/queue-6.6/ipv4-validate-ipv4_devconf-attributes-properly.patch b/queue-6.6/ipv4-validate-ipv4_devconf-attributes-properly.patch new file mode 100644 index 0000000000..a0281b10cd --- /dev/null +++ b/queue-6.6/ipv4-validate-ipv4_devconf-attributes-properly.patch @@ -0,0 +1,106 @@ +From fe6ea3f7d90093aa9cab741a38d17c300e0b225a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:26:37 +0100 +Subject: ipv4: validate IPV4_DEVCONF attributes properly + +From: Fernando Fernandez Mancera + +[ Upstream commit fa8fca88714c3a4a74f972ed37328e2f0bbef9fa ] + +As the IPV4_DEVCONF netlink attributes are not being validated, it is +possible to use netlink to set read-only values like mc_forwarding. In +addition, valid ranges are not being validated neither but that is less +relevant as they aren't in sysctl. + +To avoid similar situations in the future, define a NLA policy for +IPV4_DEVCONF attributes which are nested in IFLA_INET_CONF. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260312142637.5704-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 55 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 798497c8b1923..a5111e50b4f9c 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -2004,12 +2004,50 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { + [IFLA_INET_CONF] = { .type = NLA_NESTED }, + }; + ++static const struct nla_policy inet_devconf_policy[IPV4_DEVCONF_MAX + 1] = { ++ [IPV4_DEVCONF_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MC_FORWARDING] = { .type = NLA_REJECT }, ++ [IPV4_DEVCONF_PROXY_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SECURE_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SEND_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SHARED_MEDIA] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_RP_FILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BOOTP_RELAY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_LOG_MARTIANS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_TAG] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_ARPFILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MEDIUM_ID] = NLA_POLICY_MIN(NLA_S32, -1), ++ [IPV4_DEVCONF_NOXFRM] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_NOPOLICY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_FORCE_IGMP_VERSION] = NLA_POLICY_RANGE(NLA_U32, 0, 3), ++ [IPV4_DEVCONF_ARP_ANNOUNCE] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_IGNORE] = NLA_POLICY_RANGE(NLA_U32, 0, 8), ++ [IPV4_DEVCONF_PROMOTE_SECONDARIES] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_ACCEPT] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_NOTIFY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_LOCAL] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SRC_VMARK] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_PROXY_ARP_PVLAN] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ROUTE_LOCALNET] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BC_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_GRATUITOUS_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_EVICT_NOCARRIER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++}; ++ + static int inet_validate_link_af(const struct net_device *dev, + const struct nlattr *nla, + struct netlink_ext_ack *extack) + { +- struct nlattr *a, *tb[IFLA_INET_MAX+1]; +- int err, rem; ++ struct nlattr *tb[IFLA_INET_MAX + 1], *nested_tb[IPV4_DEVCONF_MAX + 1]; ++ int err; + + if (dev && !__in_dev_get_rtnl(dev)) + return -EAFNOSUPPORT; +@@ -2020,15 +2058,12 @@ static int inet_validate_link_af(const struct net_device *dev, + return err; + + if (tb[IFLA_INET_CONF]) { +- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { +- int cfgid = nla_type(a); ++ err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX, ++ tb[IFLA_INET_CONF], inet_devconf_policy, ++ extack); + +- if (nla_len(a) < 4) +- return -EINVAL; +- +- if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) +- return -EINVAL; +- } ++ if (err < 0) ++ return err; + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-6.6/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..1d4c1eaf02 --- /dev/null +++ b/queue-6.6/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From 92131746f636bc6f06db39ce4489ba107c1d63a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 5a2583a82f974..c64b365630227 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -60,6 +60,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -428,11 +430,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-6.6/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch b/queue-6.6/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch new file mode 100644 index 0000000000..1f0c443986 --- /dev/null +++ b/queue-6.6/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch @@ -0,0 +1,150 @@ +From fc409d0b2b8f9252a8c5a6546a6118129f313823 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:36:49 +0200 +Subject: ipv6: move IFA_F_PERMANENT percpu allocation in process scope + +From: Paolo Abeni + +[ Upstream commit 8e6405f8218b3f412d36b772318e94d589513eba ] + +Observed at boot time: + + CPU: 43 UID: 0 PID: 3595 Comm: (t-daemon) Not tainted 6.12.0 #1 + Call Trace: + + dump_stack_lvl+0x4e/0x70 + pcpu_alloc_noprof.cold+0x1f/0x4b + fib_nh_common_init+0x4c/0x110 + fib6_nh_init+0x387/0x740 + ip6_route_info_create+0x46d/0x640 + addrconf_f6i_alloc+0x13b/0x180 + addrconf_permanent_addr+0xd0/0x220 + addrconf_notify+0x93/0x540 + notifier_call_chain+0x5a/0xd0 + __dev_notify_flags+0x5c/0xf0 + dev_change_flags+0x54/0x70 + do_setlink+0x36c/0xce0 + rtnl_setlink+0x11f/0x1d0 + rtnetlink_rcv_msg+0x142/0x3f0 + netlink_rcv_skb+0x50/0x100 + netlink_unicast+0x242/0x390 + netlink_sendmsg+0x21b/0x470 + __sys_sendto+0x1dc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x7d/0x160 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + RIP: 0033:0x7f5c3852f127 + Code: 0c 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 80 3d 85 ef 0c 00 00 41 89 ca 74 10 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 71 c3 55 48 83 ec 30 44 89 4c 24 2c 4c 89 44 + RSP: 002b:00007ffe86caf4c8 EFLAGS: 00000202 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 0000556c5cd93210 RCX: 00007f5c3852f127 + RDX: 0000000000000020 RSI: 0000556c5cd938b0 RDI: 0000000000000003 + RBP: 00007ffe86caf5a0 R08: 00007ffe86caf4e0 R09: 0000000000000080 + R10: 0000000000000000 R11: 0000000000000202 R12: 0000556c5cd932d0 + R13: 00000000021d05d1 R14: 00000000021d05d1 R15: 0000000000000001 + +IFA_F_PERMANENT addresses require the allocation of a bunch of percpu +pointers, currently in atomic scope. + +Similar to commit 51454ea42c1a ("ipv6: fix locking issues with loops +over idev->addr_list"), move fixup_permanent_addr() outside the +&idev->lock scope, and do the allocations with GFP_KERNEL. With such +change fixup_permanent_addr() is invoked with the BH enabled, and the +ifp lock acquired there needs the BH variant. + +Note that we don't need to acquire a reference to the permanent +addresses before releasing the mentioned write lock, because +addrconf_permanent_addr() runs under RTNL and ifa removal always happens +under RTNL, too. + +Also the PERMANENT flag is constant in the relevant scope, as it can be +cleared only by inet6_addr_modify() under the RTNL lock. + +Reviewed-by: David Ahern +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/46a7a030727e236af2dc7752994cd4f04f4a91d2.1775658924.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 32fa6236dacdd..e2764c13e666d 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3571,15 +3571,15 @@ static int fixup_permanent_addr(struct net *net, + struct fib6_info *f6i, *prev; + + f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false, +- GFP_ATOMIC, NULL); ++ GFP_KERNEL, NULL); + if (IS_ERR(f6i)) + return PTR_ERR(f6i); + + /* ifp->rt can be accessed outside of rtnl */ +- spin_lock(&ifp->lock); ++ spin_lock_bh(&ifp->lock); + prev = ifp->rt; + ifp->rt = f6i; +- spin_unlock(&ifp->lock); ++ spin_unlock_bh(&ifp->lock); + + fib6_info_release(prev); + } +@@ -3587,7 +3587,7 @@ static int fixup_permanent_addr(struct net *net, + if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, + ifp->rt_priority, idev->dev, 0, 0, +- GFP_ATOMIC); ++ GFP_KERNEL); + } + + if (ifp->state == INET6_IFADDR_STATE_PREDAD) +@@ -3598,29 +3598,36 @@ static int fixup_permanent_addr(struct net *net, + + static void addrconf_permanent_addr(struct net *net, struct net_device *dev) + { +- struct inet6_ifaddr *ifp, *tmp; ++ struct inet6_ifaddr *ifp; ++ LIST_HEAD(tmp_addr_list); + struct inet6_dev *idev; + ++ /* Mutual exclusion with other if_list_aux users. */ ++ ASSERT_RTNL(); ++ + idev = __in6_dev_get(dev); + if (!idev) + return; + + write_lock_bh(&idev->lock); ++ list_for_each_entry(ifp, &idev->addr_list, if_list) { ++ if (ifp->flags & IFA_F_PERMANENT) ++ list_add_tail(&ifp->if_list_aux, &tmp_addr_list); ++ } ++ write_unlock_bh(&idev->lock); + +- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { +- if ((ifp->flags & IFA_F_PERMANENT) && +- fixup_permanent_addr(net, idev, ifp) < 0) { +- write_unlock_bh(&idev->lock); ++ while (!list_empty(&tmp_addr_list)) { ++ ifp = list_first_entry(&tmp_addr_list, ++ struct inet6_ifaddr, if_list_aux); ++ list_del(&ifp->if_list_aux); + ++ if (fixup_permanent_addr(net, idev, ifp) < 0) { + net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n", + idev->dev->name, &ifp->addr); + in6_ifa_hold(ifp); + ipv6_del_addr(ifp); +- write_lock_bh(&idev->lock); + } + } +- +- write_unlock_bh(&idev->lock); + } + + static int addrconf_notify(struct notifier_block *this, unsigned long event, +-- +2.53.0 + diff --git a/queue-6.6/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch b/queue-6.6/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch new file mode 100644 index 0000000000..2cba29f9f0 --- /dev/null +++ b/queue-6.6/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch @@ -0,0 +1,68 @@ +From ca7fbd0eaeb53943542abec23e2945dc29d4f3c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:32:29 +0800 +Subject: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 91840be8f710370607f949a627e070896faeddb8 ] + +On PREEMPT_RT, non-HARD irq_work runs in per-CPU kthreads via +run_irq_workd(), so irq_work_sync() uses rcuwait() to wait for BUSY==0. + +After irq_work_single() clears BUSY via atomic_cmpxchg(), it still +dereferences @work for irq_work_is_hard() and rcuwait_wake_up(). + +An irq_work_sync() caller on another CPU that enters after BUSY is cleared +can observe BUSY==0 immediately, return, and free the work before those +accesses complete — causing a use-after-free. + +Fix this by wrapping run_irq_workd() in guard(rcu)() so that the entire +irq_work_single() execution is within an RCU read-side critical +section. Then add synchronize_rcu() in irq_work_sync() after +rcuwait_wait_event() to ensure the caller waits for the RCU grace period +before returning, preventing premature frees. + +Fixes: 810979682ccc ("irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.") +Suggested-by: Sebastian Andrzej Siewior +Suggested-by: Steven Rostedt +Signed-off-by: Jiayuan Chen +Signed-off-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260330073234.303732-1-jiayuan.chen@linux.dev +Signed-off-by: Sasha Levin +--- + kernel/irq_work.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 2f4fb336dda17..188721af8eb31 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -292,6 +292,12 @@ void irq_work_sync(struct irq_work *work) + !arch_irq_work_has_interrupt()) { + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), + TASK_UNINTERRUPTIBLE); ++ /* ++ * Ensure irq_work_single() does not access @work ++ * after removing IRQ_WORK_BUSY. It is always ++ * accessed within a RCU-read section. ++ */ ++ synchronize_rcu(); + return; + } + +@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); + + static void run_irq_workd(unsigned int cpu) + { ++ guard(rcu)(); + irq_work_run_list(this_cpu_ptr(&lazy_list)); + } + +-- +2.53.0 + diff --git a/queue-6.6/irqchip-ath79-cpu-remove-unused-function.patch b/queue-6.6/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..a8ebe293fb --- /dev/null +++ b/queue-6.6/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From fd098fa91352378b77eba171884709d1c6f488b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-6.6/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-6.6/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..1363544dff --- /dev/null +++ b/queue-6.6/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From a91a92e16aa2d51d1732dd755a13fcc423940f8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index cdfa699cd7c8f..5fa6dd3a6ba28 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-6.6/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-6.6/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..ac539cd246 --- /dev/null +++ b/queue-6.6/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From d917b68c1885849227659ff098bcde6c6253af5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 93db6eec44655..8187aaceb7530 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4285,3 +4285,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index 35f3144d703b5..cad80368b0635 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-6.6/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-6.6/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..838d298f2b --- /dev/null +++ b/queue-6.6/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From db37f8ba8934eeb7c30b56c0b5197b1dfca8989d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 9b5c6a20b30c8..351d3420d348c 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -378,11 +378,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-6.6/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-6.6/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..c28c8fee7f --- /dev/null +++ b/queue-6.6/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 50c6a13e650356bc3c2c07e96a359977340e7d73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 961569c111590..36bcc9c074c7b 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -182,6 +182,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -294,7 +295,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index 42fb833ef2834..8624da023e28f 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-6.6/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-6.6/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..db97c73456 --- /dev/null +++ b/queue-6.6/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From 61846dce59baa4d10ac120a06e39d4f55985bb8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 32e589bb663ae..4a70240aa8231 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 84aa2d2539074..c5f23722bef7a 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 8ec43f53f6865..18569f1eaabdb 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-6.6/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-6.6/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..e0f07b9c12 --- /dev/null +++ b/queue-6.6/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 31acec8338ad3992f267a6f482beab6b6d376830 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index 4a70240aa8231..6ac35cf8878ca 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2179,8 +2179,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2195,12 +2193,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2224,8 +2220,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2277,8 +2272,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2289,6 +2282,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2301,9 +2295,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-6.6/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch b/queue-6.6/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch new file mode 100644 index 0000000000..1af21d8171 --- /dev/null +++ b/queue-6.6/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch @@ -0,0 +1,103 @@ +From d87f64e9808cb3c859cdbb72f30967b941047766 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist() + +From: Jianpeng Chang + +[ Upstream commit 307abfac04a254c09c5705d816b33354acee97a0 ] + +When kprobe_add_area_blacklist() iterates through a section like +.kprobes.text, the start address may not correspond to a named symbol. +On ARM64 with CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y (introduced by +commit baaf553d3bc3 ("arm64: Implement +HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")), the compiler flag +-fpatchable-function-entry=4,2 inserts 2 NOPs before each function entry +point for ftrace call_ops. These pre-function NOPs sit at the section base +address, before the first named function symbol. The compiler emits a $x +mapping symbol at offset 0x00 to mark the start of code, but +find_kallsyms_symbol() ignores mapping symbols. + +Without CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS (e.g. defconfig), no +pre-function NOPs are inserted, the first function starts at offset +0x00, and the bug does not trigger. + +This only affects modules that have a .kprobes.text section (i.e. those +using the __kprobes annotation). Modules using NOKPROBE_SYMBOL() instead +(like kretprobe_example.ko) blacklist exact function addresses via the +_kprobe_blacklist section and are not affected. + +For kprobe_example.ko on ARM64 with -fpatchable-function-entry=4,2, +the .kprobes.text section layout is: + + offset 0x00: $x + 2 NOPs (mapping symbol + ftrace preamble) + offset 0x08: handler_post (64 bytes) + offset 0x50: handler_pre (68 bytes) + +kprobe_add_area_blacklist() starts iterating from the section base +address (offset 0x00), which only has the $x mapping symbol. +kprobe_add_ksym_blacklist() then calls kallsyms_lookup_size_offset() +for this address, which goes through: + + kallsyms_lookup_size_offset() + -> module_address_lookup() + -> find_kallsyms_symbol() + +find_kallsyms_symbol() scans all module symbols to find the closest +preceding symbol. + +Since no named text symbol exists at offset 0x00, +find_kallsyms_symbol() picks __UNIQUE_ID_vermagic (a .modinfo symbol +whose address is in the temporary image) as the "best" match. The +computed "size" = next_text_symbol - modinfo_symbol spans across +these two unrelated memory regions, creating a blacklist entry with +a bogus range of tens of terabytes. + +Whether this causes a visible failure depends on address randomization, +here is what happens on Raspberry Pi 4/5: + + - On RPi5, the bogus size was ~35 TB. start + size stayed within + 64-bit range, so the blacklist entry covered the entire kernel + text. register_kprobe() in the module's own init function failed + with -EINVAL. + + - On RPi4, the bogus size was ~75 TB. start + size overflowed + 64 bits and wrapped to a small address near zero. The range + check (addr >= start && addr < end) then failed because end + wrapped around, so the bogus entry was accidentally harmless + and kprobes worked by luck. + +The same bug exists on both machines, but randomization determines whether +the integer overflow masks it or not. + +Fix this by adding notrace to the __kprobes macro. Functions in +.kprobes.text are kprobe infrastructure handlers that should never be +traced by ftrace. With notrace, the compiler stops inserting them and the +non-symbol gap at the section start disappears entirely. + +Link: https://lore.kernel.org/all/20260506012706.2785785-1-jianpeng.chang.cn@windriver.com/ + +Fixes: baaf553d3bc3 ("arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS") +Signed-off-by: Jianpeng Chang +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/asm-generic/kprobes.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/asm-generic/kprobes.h b/include/asm-generic/kprobes.h +index 060eab094e5a2..5290a2b2e15a0 100644 +--- a/include/asm-generic/kprobes.h ++++ b/include/asm-generic/kprobes.h +@@ -14,7 +14,7 @@ static unsigned long __used \ + _kbl_addr_##fname = (unsigned long)fname; + # define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) + /* Use this to forbid a kprobes attach on very low level functions */ +-# define __kprobes __section(".kprobes.text") ++# define __kprobes notrace __section(".kprobes.text") + # define nokprobe_inline __always_inline + #else + # define NOKPROBE_SYMBOL(fname) +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-6.6/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..298635fbb5 --- /dev/null +++ b/queue-6.6/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 03994c93c87f2266019aa4442931a2fcb0eabd28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index d68fe617369e0..27b3ec04e5513 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3042,7 +3042,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -3056,7 +3056,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-6.6/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..3eb0b4a7f7 --- /dev/null +++ b/queue-6.6/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From fa0b3d79c25e758999d64b893c849ccede8613a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 27b3ec04e5513..74362c7eb9190 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -7367,7 +7367,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-6.6/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-6.6/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..b9985c666a --- /dev/null +++ b/queue-6.6/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From 39f9285072a5e201984f9626201f42dc2df4c1a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 68a6daec0aef1..fab3458c54e4c 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-6.6/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-6.6/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..91f21ad209 --- /dev/null +++ b/queue-6.6/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 91d39de199d3d47b0f2bdb542959222ada164299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index fab3458c54e4c..f5ba590373907 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-6.6/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-6.6/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..8ca79d3cb9 --- /dev/null +++ b/queue-6.6/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From e22ba84390f549fd81c4a5dd522cbb116a4ea350 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index e104010345b18..d849ec73fd624 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-6.6/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-6.6/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..9be81c9c22 --- /dev/null +++ b/queue-6.6/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 8828532e454d1ae2e9fab00fb1efbdd498f89b88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 7d63e2f1555a0..37926b4b205af 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -21,6 +21,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -73,9 +80,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -99,16 +105,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-6.6/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-6.6/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..4efa037623 --- /dev/null +++ b/queue-6.6/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From 60d9cf76ab430dc82daff0a533e8058c752f920d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 6eb94e466f904..db85d2e3ed8c7 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3965,6 +3965,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-6.6/media-au0828-fix-green-screen-in-analog.patch b/queue-6.6/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..db528b6af2 --- /dev/null +++ b/queue-6.6/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From 2ff517c2e62789a39d8f9698759d998f022a78ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index fd9fc43d47e0f..d263c6fa1c384 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1676,6 +1676,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1769,8 +1790,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-6.6/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-6.6/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..738de621c8 --- /dev/null +++ b/queue-6.6/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From faa6642be0a44010a65402758817853799717fd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index 611c9823be857..0077320746e5d 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -803,9 +803,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-6.6/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-6.6/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..56d05b2b85 --- /dev/null +++ b/queue-6.6/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 27f0a3eb90a8ebd0c3c689d549a9a3d6ad71add9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index 5aec252890624..3196106429a56 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-6.6/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch b/queue-6.6/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch new file mode 100644 index 0000000000..b8118fcd05 --- /dev/null +++ b/queue-6.6/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch @@ -0,0 +1,111 @@ +From 64dc1c322b5ab04e6440647bfa9ea8200943f2db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 16:50:24 +0100 +Subject: media: dw100: Fix kernel oops with PREEMPT_RT enabled + +From: Stefan Klug + +[ Upstream commit 557ec8cc29ade6c72ea768e59389db08cb7742c9 ] + +On kernels with PREEMPT_RT enabled, a "BUG: scheduling while atomic" +kernel oops occurs inside dw100_irq_handler -> vb2_buffer_done. This is +because vb2_buffer_done takes a spinlock which is not allowed within +interrupt context on PREEMPT_RT. + +The first attempt to fix this was to just drop the IRQF_ONESHOT so that +the interrupt is handled threaded on PREEMPT_RT systems. This introduced +a new issue. The dw100 has an internal timeout counter that is gated by +the DW100_BUS_CTRL_AXI_MASTER_ENABLE bit. Depending on the time it takes +for the threaded handler to run and the geometry of the data being +processed it is possible to reach the timeout resulting in +DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT being set and "dw100 +32e30000.dwe: Interrupt error: 0x1" errors in dmesg. + +To properly fix that, split the interrupt into two halves, reset the +DW100_BUS_CTRL_AXI_MASTER_ENABLE bit in the hard interrupt handler and +do the v4l2 buffer handling in the threaded half. The IRQF_ONESHOT can +still be dropped as the interrupt gets disabled in the hard handler and +will only be reenabled on the next dw100_device_run which will not be +called before the current job has finished. + +Signed-off-by: Stefan Klug +Reviewed-by: Xavier Roumegue +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260304-sklug-v6-16-topic-dw100-v3-1-dev-v5-3-1a7e1f721b50@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/nxp/dw100/dw100.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c +index 0024d6175ad9a..9017a312265ab 100644 +--- a/drivers/media/platform/nxp/dw100/dw100.c ++++ b/drivers/media/platform/nxp/dw100/dw100.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,7 @@ struct dw100_device { + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; ++ bool frame_failed; + }; + + struct dw100_q_data { +@@ -1396,7 +1398,8 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + { + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; +- bool with_error = true; ++ ++ dw_dev->frame_failed = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; +@@ -1404,7 +1407,7 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); +- with_error = false; ++ dw_dev->frame_failed = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } +@@ -1417,7 +1420,14 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + +- dw100_job_finish(dw_dev, with_error); ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dw100_irq_thread_fn(int irq, void *dev_id) ++{ ++ struct dw100_device *dw_dev = dev_id; ++ ++ dw100_job_finish(dw_dev, dw_dev->frame_failed); + + return IRQ_HANDLED; + } +@@ -1565,8 +1575,9 @@ static int dw100_probe(struct platform_device *pdev) + + pm_runtime_put_sync(&pdev->dev); + +- ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, +- dev_name(&pdev->dev), dw_dev); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, dw100_irq_handler, ++ dw100_irq_thread_fn, 0, ++ dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_pm; +-- +2.53.0 + diff --git a/queue-6.6/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-6.6/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..0a653f5636 --- /dev/null +++ b/queue-6.6/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From 28f19e134b1e4359dcee044a8175616ae9c28524 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index bae76023cf71d..467335baea979 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2707,10 +2707,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-6.6/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch b/queue-6.6/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch new file mode 100644 index 0000000000..d546025437 --- /dev/null +++ b/queue-6.6/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch @@ -0,0 +1,55 @@ +From 0f2c1ce5e2270c2ae0d2d90b2edb07c6c9e0856b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:32 -0500 +Subject: media: em28xx: remove tuner type from Hauppauge DVB DualHD + +From: Bradford Love + +[ Upstream commit a5dcbff7d50a89bf0376e7f2fb1ba3163a6dac0a ] + +This reverts a patch which was perhaps inadvertently added. + +This was changed during the 5.15-rc4 merge. The faulty commit appears +lost in the pull request somehow, I cannot find it to check the +explanation. + +commit c52e7b855b33 ("Merge tag 'v5.15-rc4' into media_tree") + +There was nothing wrong with this device and no reason to moodify the +board profile. The DVB capabilities are added via dvb_module_probe. +Additionally, the device contains *zero* analog inputs, so I'm not +sure why one was added. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 467335baea979..0776bd07dc051 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2498,17 +2498,12 @@ const struct em28xx_board em28xx_boards[] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, +- .tuner_type = TUNER_SI2157, ++ .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .has_dual_ts = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, +- .input = { { +- .type = EM28XX_VMUX_COMPOSITE, +- .vmux = TVP5150_COMPOSITE1, +- .amux = EM28XX_AMUX_LINE_IN, +- } }, + }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. +-- +2.53.0 + diff --git a/queue-6.6/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch b/queue-6.6/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch new file mode 100644 index 0000000000..8686b03331 --- /dev/null +++ b/queue-6.6/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch @@ -0,0 +1,47 @@ +From 59799e6c5a5e6d9e5f60f061851f201596c39ecf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:18:15 +0800 +Subject: media: i2c: ar0521: Check return value of devm_gpiod_get_optional() + in ar0521_probe() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chen Ni + +[ Upstream commit 46c2891cf12c767de031a248cbb1f96d203bd3f6 ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Acked-by: Krzysztof Hałasa +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ar0521.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c +index 60ab433cafb11..cf5eb1482586e 100644 +--- a/drivers/media/i2c/ar0521.c ++++ b/drivers/media/i2c/ar0521.c +@@ -1114,6 +1114,9 @@ static int ar0521_probe(struct i2c_client *client) + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(sensor->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), ++ "failed to get reset gpio\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + +-- +2.53.0 + diff --git a/queue-6.6/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-6.6/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..df81d7a2b8 --- /dev/null +++ b/queue-6.6/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From dc3ba2f0f8e6df7d8bab2e5b218c248ce66cce36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index 348f1e1098fb8..aa8182672061d 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1197,6 +1197,10 @@ static int mt9p031_probe(struct i2c_client *client) + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-6.6/media-pulse8-cec-handle-partial-deinit.patch b/queue-6.6/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..fdb42ec325 --- /dev/null +++ b/queue-6.6/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From d496281c080ea4f4e415f2cde1226d79108dc3ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 171366fe35443..90b8a968fed77 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-6.6/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-6.6/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..be36a0b48b --- /dev/null +++ b/queue-6.6/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From 23ab8a8662cce0cdcf2865fc745f86cf4e8c4927 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +index c0f1002f4ecf1..09a05e0a95827 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +@@ -172,7 +172,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-6.6/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..22ef5df7d9 --- /dev/null +++ b/queue-6.6/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From f5824c74e0e6f8955b02633ece6c401f4ced6a9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + .../media/platform/renesas/vsp1/vsp1_rwpf.c | 28 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index e0f87c8103ca5..cf93f32ce23ed 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -182,6 +182,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *config; + struct v4l2_mbus_framefmt *format; +@@ -212,18 +214,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-6.6/media-saa7164-fix-rev2-firmware-filename.patch b/queue-6.6/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..36b5917f7a --- /dev/null +++ b/queue-6.6/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 42b118a6b4d81ae5f9dbab7b5bbbd2b59da20a1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index cc9f384f7f1e9..341cef62452f1 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-6.6/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-6.6/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..02241d30a9 --- /dev/null +++ b/queue-6.6/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From 9dc9a40fa025172c15e69b38aa059ad7b55b4248 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 32d5e974fb32b..d37d836e2b5b9 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-6.6/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-6.6/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..cf641ea1c1 --- /dev/null +++ b/queue-6.6/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From d7d0b85fefa90b6c6b49b902b5650930ca6a800e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index dae1f2153e8be..32d5e974fb32b 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -572,8 +572,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-6.6/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-6.6/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..c858c14cc1 --- /dev/null +++ b/queue-6.6/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From f50f0643040bec2c865d29c18f5f8344f1c85b75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index 8cb4fdcae1373..bfe20dd1cde88 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -448,9 +448,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-6.6/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch b/queue-6.6/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch new file mode 100644 index 0000000000..ad3ea5fa51 --- /dev/null +++ b/queue-6.6/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch @@ -0,0 +1,62 @@ +From 9d557ec70140a6aea2bfea2eedd7b899d057a7f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 16:35:00 -0800 +Subject: memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5 + +From: Florian Fainelli + +[ Upstream commit a969a0835152984a0f556434eafdee0b84213670 ] + +The same limitations that apply to LPDDR4 also apply to LPDDR5. Expand +the check and rename accordingly. + +Signed-off-by: Florian Fainelli +Link: https://patch.msgid.link/20260122003501.1191059-1-florian.fainelli@broadcom.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/brcmstb_memc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c +index 233a53f5bce1f..89ea41bd4fc89 100644 +--- a/drivers/memory/brcmstb_memc.c ++++ b/drivers/memory/brcmstb_memc.c +@@ -13,6 +13,7 @@ + + #define REG_MEMC_CNTRLR_CONFIG 0x00 + #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 ++#define CNTRLR_CONFIG_LPDDR5_SHIFT 6 + #define CNTRLR_CONFIG_MASK 0xf + #define REG_MEMC_SRPD_CFG_21 0x20 + #define REG_MEMC_SRPD_CFG_20 0x34 +@@ -33,14 +34,15 @@ struct brcmstb_memc { + u32 srpd_offset; + }; + +-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc) ++static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc) + { + void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG; + u32 reg; + + reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK; + +- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT; ++ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT || ++ reg == CNTRLR_CONFIG_LPDDR5_SHIFT; + } + + static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc, +@@ -94,7 +96,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr, + * dynamic tuning process will also get affected by the inactivity + * timeout, thus making it non functional. + */ +- if (brcmstb_memc_uses_lpddr4(memc)) ++ if (brcmstb_memc_uses_lpddr45(memc)) + return -EOPNOTSUPP; + + ret = kstrtouint(buf, 10, &val); +-- +2.53.0 + diff --git a/queue-6.6/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch b/queue-6.6/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch new file mode 100644 index 0000000000..1140333d10 --- /dev/null +++ b/queue-6.6/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch @@ -0,0 +1,64 @@ +From bd78defa665988ef89b31db26d84ab54084ab2f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:35:52 +0800 +Subject: mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus + width + +From: Luke Wang + +[ Upstream commit e98f926e5a2d8023a74ec2ba7a973b5d76610f4e ] + +UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers +that lack relevant capability registers rely on paring properties provided +by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() +has been introduced to validate such configuration violations, let's also +add checks for UHS/DDR/HS200 modes. + +This fixes an issue where, if the HS200/HS400 property is set while only +a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually +performing the mode switch. Consequently, mmc_select_timing() proceeds +without falling back to mmc_select_hs(), leaving the eMMC device operating +in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). + +Signed-off-by: Luke Wang +[Shawn: reword the commit msg and rework the code] +Signed-off-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/host.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index cf396e8f34e98..1823507caa743 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -623,12 +623,24 @@ static int mmc_validate_host_caps(struct mmc_host *host) + return -EINVAL; + } + ++ /* UHS/DDR/HS200 modes require at least 4-bit bus */ ++ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) && ++ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) { ++ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n"); ++ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR); ++ caps2 &= ~MMC_CAP2_HS200; ++ } ++ ++ /* HS400 and HS400ES modes require 8-bit bus */ + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); +- host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; ++ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400); + } + ++ host->caps = caps; ++ host->caps2 = caps2; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/module-override-eexist-module-return.patch b/queue-6.6/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..2fb4ead3f3 --- /dev/null +++ b/queue-6.6/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From db9118fac956fde7dca4466f564bcacdf71414e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index ac528fbb62824..5bbefde3ff397 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -2543,6 +2543,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-6.6/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-6.6/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..b6b38c2845 --- /dev/null +++ b/queue-6.6/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From ac75fd3a88a45b3a4c04dfb06f0a74675c2335e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 405b448bd91fe..af4f153832b45 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7054,7 +7054,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-6.6/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..dc36fd0369 --- /dev/null +++ b/queue-6.6/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From d81e34db136e1c0b1f15a47c659e925699c4466b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 0071f27d2d6c1..45a548d93e152 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1449,6 +1450,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1462,7 +1464,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1502,6 +1503,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1512,6 +1514,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1546,6 +1549,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1554,6 +1558,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1563,6 +1568,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1892,6 +1898,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-6.6/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..bdd57a5482 --- /dev/null +++ b/queue-6.6/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,53 @@ +From e3cbc8199154ce6144303cc4d683c446a0bf557b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 02beed666fa63..0071f27d2d6c1 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1498,6 +1498,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-6.6/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..ede3613c10 --- /dev/null +++ b/queue-6.6/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From 94b1324da0a7bb3c088f48223c70fb9657d8418c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index fce2ff1e1d834..02beed666fa63 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -121,6 +121,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1447,10 +1449,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1504,6 +1506,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1554,6 +1557,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1882,6 +1886,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-6.6/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..a889e3ef72 --- /dev/null +++ b/queue-6.6/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From bcf6df300e3b14f5090680e4443dbe42d46c922c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index d323c5c23521f..e6e9c8a576af4 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1271,7 +1271,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1298,7 +1297,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-6.6/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-6.6/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..dae2c1cdd6 --- /dev/null +++ b/queue-6.6/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From 23f5a9f137614a5699011b35415540f20ebd957a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 085d81576f1a4..728e09e283bb7 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2174,6 +2174,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* Stop PTP Clock driver */ + if (info->gptp) +-- +2.53.0 + diff --git a/queue-6.6/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-6.6/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..2d1ee5aa32 --- /dev/null +++ b/queue-6.6/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From 233140f0a0030844f3f7fabde4c00a46763bcdb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 83a16d10eedbc..a0c5215a12aa5 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -207,6 +207,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-6.6/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-6.6/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..5b23c92049 --- /dev/null +++ b/queue-6.6/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From 260e39ccaac6132523d9bebab4c3595f8a678b63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index a9184a78650b0..46073afb1874a 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1908,6 +1908,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-6.6/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-6.6/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..1cace13b7a --- /dev/null +++ b/queue-6.6/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From 0c8db91da6964e98c407a545edb762533ff83031 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 8e4c87a39dc87..9e60f8f6f442e 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2418,6 +2418,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-6.6/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch b/queue-6.6/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch new file mode 100644 index 0000000000..0980bfd3b9 --- /dev/null +++ b/queue-6.6/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch @@ -0,0 +1,82 @@ +From 4a9aa57eeae3e7d823b5d2061cd07ce1907886c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 12:02:28 +0530 +Subject: net: lan743x: fix SGMII detection on PCI1xxxx B0+ during warm reset + +From: Thangaraj Samynathan + +[ Upstream commit e783e40fb689381caca31e03d28c39e10c82e722 ] + +A warm reset on boards using an EEPROM-only strap configuration (where +no MAC address is set in the image) can cause the driver to incorrectly +revert to RGMII mode. This occurs because the ENET_CONFIG_LOAD_STARTED +bit may not persist or behave as expected. + +Update pci11x1x_strap_get_status() to use revision-specific validation: + +- For PCI11x1x A0: Continue using the legacy check (config load started + or reset protection) to validate the SGMII strap. +- For PCI11x1x B0 and later: Use the newly available + STRAP_READ_USE_SGMII_EN_ bit in the upper strap register to validate + the lower SGMII_EN bit. + +This ensures the SGMII interface is correctly identified even after a +warm reboot. + +Signed-off-by: Thangaraj Samynathan +Link: https://patch.msgid.link/20260318063228.17110-1-thangaraj.s@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 15 +++++++++++---- + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 8910928b38498..72e78bc6a5eb0 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -27,6 +27,12 @@ + + #define RFE_RD_FIFO_TH_3_DWORDS 0x3 + ++static bool pci11x1x_is_a0(struct lan743x_adapter *adapter) ++{ ++ u32 dev_rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_; ++ return dev_rev == ID_REV_CHIP_REV_PCI11X1X_A0_; ++} ++ + static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + { + u32 chip_rev; +@@ -46,10 +52,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); + lan743x_hs_syslock_release(adapter); + hw_cfg = lan743x_csr_read(adapter, HW_CFG); +- +- if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || +- hw_cfg & HW_CFG_RST_PROTECT_) { +- strap = lan743x_csr_read(adapter, STRAP_READ); ++ strap = lan743x_csr_read(adapter, STRAP_READ); ++ if ((pci11x1x_is_a0(adapter) && ++ (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || ++ hw_cfg & HW_CFG_RST_PROTECT_)) || ++ (strap & STRAP_READ_USE_SGMII_EN_)) { + if (strap & STRAP_READ_SGMII_EN_) + adapter->is_sgmii_en = true; + else +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index b6c83c68241e6..dc25f56e98a9d 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -26,6 +26,7 @@ + #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) + #define ID_REV_CHIP_REV_A0_ (0x00000000) + #define ID_REV_CHIP_REV_B0_ (0x00000010) ++#define ID_REV_CHIP_REV_PCI11X1X_A0_ (0x000000A0) + #define ID_REV_CHIP_REV_PCI11X1X_B0_ (0x000000B0) + + #define FPGA_REV (0x04) +-- +2.53.0 + diff --git a/queue-6.6/net-lan966x-avoid-unregistering-netdev-on-register-f.patch b/queue-6.6/net-lan966x-avoid-unregistering-netdev-on-register-f.patch new file mode 100644 index 0000000000..7aec2b1876 --- /dev/null +++ b/queue-6.6/net-lan966x-avoid-unregistering-netdev-on-register-f.patch @@ -0,0 +1,65 @@ +From 72bc4cd6bc2605c470d6f36cfea37ba36c2baa5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 21:43:11 +0900 +Subject: net: lan966x: avoid unregistering netdev on register failure + +From: Myeonghun Pak + +[ Upstream commit c4f3d6eb1fcf6cd9ce4644f604d5aad1ce594dfc ] + +lan966x_probe_port() stores the newly allocated net_device in the +port before calling register_netdev(). If register_netdev() fails, +the probe error path calls lan966x_cleanup_ports(), which sees +port->dev and calls unregister_netdev() for a device that was never +registered. + +Destroy the phylink instance created for this port and clear port->dev +before returning the registration error. The common cleanup path now skips +ports without port->dev before reaching the registered netdev cleanup, so +it only handles ports that reached the registered-netdev lifetime. + +This also avoids treating an uninitialized FDMA netdev and the failed port +as a NULL == NULL match in the common cleanup path. + +Fixes: d28d6d2e37d1 ("net: lan966x: add port module support") +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260506124331.31945-1-mhun512@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index 5466f14e000ce..ce48685a50b20 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -750,11 +750,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) + + for (p = 0; p < lan966x->num_phys_ports; p++) { + port = lan966x->ports[p]; +- if (!port) ++ if (!port || !port->dev) + continue; + +- if (port->dev) +- unregister_netdev(port->dev); ++ unregister_netdev(port->dev); + + lan966x_xdp_port_deinit(port); + if (lan966x->fdma && lan966x->fdma_ndev == port->dev) +@@ -875,6 +874,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, + err = register_netdev(dev); + if (err) { + dev_err(lan966x->dev, "register_netdev failed\n"); ++ phylink_destroy(phylink); ++ port->phylink = NULL; ++ port->dev = NULL; + return err; + } + +-- +2.53.0 + diff --git a/queue-6.6/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch b/queue-6.6/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch new file mode 100644 index 0000000000..5b943a1e51 --- /dev/null +++ b/queue-6.6/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch @@ -0,0 +1,41 @@ +From 4f413f283d5cdee28069f25c7ef5ff1abe41c3fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:09:23 +0300 +Subject: net/mlx5e: XSK, Increase size for chunk_size param + +From: Dragos Tatulea + +[ Upstream commit 1047e14b44edecbbab02a86514a083b8db9fde4d ] + +When 64K pages are used, chunk_size can take the 64K value +which doesn't fit in u16. This results in overflows that +are detected in mlx5e_mpwrq_log_wqe_sz(). + +Increase the type to u32 to fix this. + +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260403090927.139042-2-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/params.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +index 6800949dafbc9..7f91688fb388c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +@@ -8,7 +8,7 @@ + + struct mlx5e_xsk_param { + u16 headroom; +- u16 chunk_size; ++ u32 chunk_size; + bool unaligned; + }; + +-- +2.53.0 + diff --git a/queue-6.6/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-6.6/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..64c4b44db9 --- /dev/null +++ b/queue-6.6/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From 7d31f4cc4c43359d3a34591a0c93d15be2bfd5ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index 2941721b65152..d9f5de74dbfbf 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5587,6 +5587,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5722,6 +5724,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-6.6/net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch b/queue-6.6/net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch new file mode 100644 index 0000000000..eea93dffc3 --- /dev/null +++ b/queue-6.6/net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch @@ -0,0 +1,192 @@ +From 2cce2c2774c7af5a79125544bbb512212f214a05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Dec 2023 06:41:43 +0100 +Subject: net: phy: c45: add genphy_c45_pma_read_ext_abilities() function + +From: Oleksij Rempel + +[ Upstream commit 0c476157085fe2ad13b9bec70ea672e86647fa1a ] + +Move part of the genphy_c45_pma_read_abilities() code to a separate +function. + +Some PHYs do not implement PMA/PMD status 2 register (Register 1.8) but +do implement PMA/PMD extended ability register (Register 1.11). To make +use of it, we need to be able to access this part of code separately. + +Signed-off-by: Oleksij Rempel +Reviewed-by: Andrew Lunn +Reviewed-by: Russell King (Oracle) +Link: https://lore.kernel.org/r/20231212054144.87527-2-o.rempel@pengutronix.de +Signed-off-by: Jakub Kicinski +Stable-dep-of: c78bdba7b966 ("net: phy: DP83TC811: add reading of abilities") +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy-c45.c | 129 ++++++++++++++++++++++---------------- + include/linux/phy.h | 1 + + 2 files changed, 75 insertions(+), 55 deletions(-) + +diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c +index 8e6fd4962c486..747d14bf152c3 100644 +--- a/drivers/net/phy/phy-c45.c ++++ b/drivers/net/phy/phy-c45.c +@@ -919,6 +919,79 @@ int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev) + } + EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities); + ++/** ++ * genphy_c45_pma_read_ext_abilities - read supported link modes from PMA ++ * @phydev: target phy_device struct ++ * ++ * Read the supported link modes from the PMA/PMD extended ability register ++ * (Register 1.11). ++ */ ++int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev) ++{ ++ int val; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10GBLRM); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10GBT); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10GBKX4); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10GBKR); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_1000BT); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_1000BKX); ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_100BTX); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_100BTX); ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10BT); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, ++ phydev->supported, ++ val & MDIO_PMA_EXTABLE_10BT); ++ ++ if (val & MDIO_PMA_EXTABLE_NBT) { ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, ++ MDIO_PMA_NG_EXTABLE); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_NG_EXTABLE_2_5GBT); ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++ phydev->supported, ++ val & MDIO_PMA_NG_EXTABLE_5GBT); ++ } ++ ++ if (val & MDIO_PMA_EXTABLE_BT1) { ++ val = genphy_c45_pma_baset1_read_abilities(phydev); ++ if (val < 0) ++ return val; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(genphy_c45_pma_read_ext_abilities); ++ + /** + * genphy_c45_pma_read_abilities - read supported link modes from PMA + * @phydev: target phy_device struct +@@ -962,63 +1035,9 @@ int genphy_c45_pma_read_abilities(struct phy_device *phydev) + val & MDIO_PMA_STAT2_10GBER); + + if (val & MDIO_PMA_STAT2_EXTABLE) { +- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); ++ val = genphy_c45_pma_read_ext_abilities(phydev); + if (val < 0) + return val; +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10GBLRM); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10GBT); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10GBKX4); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10GBKR); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_1000BT); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_1000BKX); +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_100BTX); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_100BTX); +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10BT); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, +- phydev->supported, +- val & MDIO_PMA_EXTABLE_10BT); +- +- if (val & MDIO_PMA_EXTABLE_NBT) { +- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, +- MDIO_PMA_NG_EXTABLE); +- if (val < 0) +- return val; +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_NG_EXTABLE_2_5GBT); +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +- phydev->supported, +- val & MDIO_PMA_NG_EXTABLE_5GBT); +- } +- +- if (val & MDIO_PMA_EXTABLE_BT1) { +- val = genphy_c45_pma_baset1_read_abilities(phydev); +- if (val < 0) +- return val; +- } + } + + /* This is optional functionality. If not supported, we may get an error +diff --git a/include/linux/phy.h b/include/linux/phy.h +index a57e799b1de18..586973404ad47 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -1857,6 +1857,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev); + int genphy_c45_an_disable_aneg(struct phy_device *phydev); + int genphy_c45_read_mdix(struct phy_device *phydev); + int genphy_c45_pma_read_abilities(struct phy_device *phydev); ++int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev); + int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev); + int genphy_c45_read_eee_abilities(struct phy_device *phydev); + int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev); +-- +2.53.0 + diff --git a/queue-6.6/net-phy-dp83tc811-add-reading-of-abilities.patch b/queue-6.6/net-phy-dp83tc811-add-reading-of-abilities.patch new file mode 100644 index 0000000000..98b67ac0b2 --- /dev/null +++ b/queue-6.6/net-phy-dp83tc811-add-reading-of-abilities.patch @@ -0,0 +1,40 @@ +From 7cab8bba8bd45a8b23defb920bbf1640ec155685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 09:19:47 +0200 +Subject: net: phy: DP83TC811: add reading of abilities + +From: Sven Schuchmann + +[ Upstream commit c78bdba7b9666020c0832150a4fc4c0aebc7c6ac ] + +At this time the driver is not listing any speeds +it supports. This should be ETHTOOL_LINK_MODE_100baseT1_Full_BIT +for DP83TC811. Add the missing call for phylib to read the abilities. + +Fixes: b753a9faaf9a ("net: phy: DP83TC811: Introduce support for the DP83TC811 phy") +Suggested-by: Andrew Lunn +Signed-off-by: Sven Schuchmann +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260512071949.6218-1-schuchmann@schleissheimer.de +[pabeni@redhat.com: dropped revision history] +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83tc811.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c +index 7ea32fb77190c..5425a95352f9f 100644 +--- a/drivers/net/phy/dp83tc811.c ++++ b/drivers/net/phy/dp83tc811.c +@@ -393,6 +393,7 @@ static struct phy_driver dp83811_driver[] = { + .config_init = dp83811_config_init, + .config_aneg = dp83811_config_aneg, + .soft_reset = dp83811_phy_reset, ++ .get_features = genphy_c45_pma_read_ext_abilities, + .get_wol = dp83811_get_wol, + .set_wol = dp83811_set_wol, + .config_intr = dp83811_config_intr, +-- +2.53.0 + diff --git a/queue-6.6/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-6.6/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..9c708e0d93 --- /dev/null +++ b/queue-6.6/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From 4a72a925d3229bc777fa63accb35f546feb0b3c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c645853..4cbf5f934cde1 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -361,7 +361,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -462,7 +462,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-6.6/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-6.6/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..300c127bd0 --- /dev/null +++ b/queue-6.6/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 6855a24eb9bc1e72b89f842daf5c24c8cdf5b3ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 7caae93937ee9..0b272eaa88739 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -270,6 +270,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch b/queue-6.6/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch new file mode 100644 index 0000000000..070a7cffc9 --- /dev/null +++ b/queue-6.6/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch @@ -0,0 +1,58 @@ +From 776f58469409dcfe21acc068835ce7cdd653405f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 20:39:16 +0800 +Subject: net: sched: cls_u32: Avoid memcpy() false-positive warning in + u32_init_knode() + +From: Jiayuan Chen + +[ Upstream commit 34bd3c6b0bd383a76d987c8c45c4f309b681b255 ] + +Syzbot reported a warning in u32_init_knode() [1]. + +Similar to commit 7cba18332e36 ("net: sched: cls_u32: Avoid memcpy() +false-positive warning") which addressed the same issue in u32_change(), +use unsafe_memcpy() in u32_init_knode() to work around the compiler's +inability to see into composite flexible array structs. + +This silences the false-positive reported by syzbot: + + memcpy: detected field-spanning write (size 32) of single field + "&new->sel" at net/sched/cls_u32.c:855 (size 16) + +Since the memory is correctly allocated with kzalloc_flex() using +s->nkeys, this is purely a false positive and does not need a Fixes tag. + +[1] https://syzkaller.appspot.com/bug?extid=d5ace703ed883df56e42 + +Reported-by: syzbot+d5ace703ed883df56e42@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69a811b9.a70a0220.b118c.0019.GAE@google.com/T/ +Reviewed-by: Simon Horman +Acked-by: Gustavo A. R. Silva +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260309123917.402183-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_u32.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 1338d9b4c03a4..8260fb67c4124 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -852,7 +852,10 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, + /* Similarly success statistics must be moved as pointers */ + new->pcpu_success = n->pcpu_success; + #endif +- memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); ++ unsafe_memcpy(&new->sel, s, struct_size(s, keys, s->nkeys), ++ /* A composite flex-array structure destination, ++ * which was correctly sized with kzalloc_flex(), ++ * above. */); + + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { + kfree(new); +-- +2.53.0 + diff --git a/queue-6.6/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch b/queue-6.6/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch new file mode 100644 index 0000000000..d85d13e5af --- /dev/null +++ b/queue-6.6/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch @@ -0,0 +1,65 @@ +From c4e6a5d6e901e03577233f84c162609fd7906fc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 15:26:40 -0700 +Subject: net/smc: avoid NULL deref of conn->lnk in smc_msg_event tracepoint + +From: Xiang Mei + +[ Upstream commit 7bf563badd37cb796df5477d2b78bb64148a1268 ] + +The smc_msg_event tracepoint class, shared by smc_tx_sendmsg and +smc_rx_recvmsg, unconditionally dereferences smc->conn.lnk: + + __string(name, smc->conn.lnk->ibname) + +conn->lnk is only set for SMC-R; for SMC-D it is NULL. Other code on +these paths already handles this (e.g. !conn->lnk in +SMC_STAT_RMB_TX_SIZE_SMALL()). With the tracepoint enabled, the first +sendmsg()/recvmsg() on an SMC-D socket crashes: + + Oops: general protection fault, probably for non-canonical address + KASAN: null-ptr-deref in range [...] + RIP: 0010:strlen+0x1e/0xa0 + Call Trace: + trace_event_raw_event_smc_msg_event (net/smc/smc_tracepoint.h:44) + smc_rx_recvmsg (net/smc/smc_rx.c:515) + smc_recvmsg (net/smc/af_smc.c:2859) + __sys_recvfrom (net/socket.c:2315) + __x64_sys_recvfrom (net/socket.c:2326) + do_syscall_64 + +The faulting address 0x3e0 is offsetof(struct smc_link, ibname), +confirming the NULL ->lnk deref. Enabling the tracepoint requires +root, but the trigger itself is unprivileged: socket(AF_SMC, ...) has +no capability check, and SMC-D negotiation needs no admin step on +s390 or on x86 with the loopback ISM device loaded. + +Log an empty device name for SMC-D instead of dereferencing NULL. + +Fixes: aff3083f10bf ("net/smc: Introduce tracepoints for tx and rx msg") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Dust Li +Reviewed-by: Sidraya Jayagond +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/smc_tracepoint.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/smc/smc_tracepoint.h b/net/smc/smc_tracepoint.h +index 9fc5e586d24ab..380451912c4f1 100644 +--- a/net/smc/smc_tracepoint.h ++++ b/net/smc/smc_tracepoint.h +@@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(smc_msg_event, + __field(const void *, smc) + __field(u64, net_cookie) + __field(size_t, len) +- __string(name, smc->conn.lnk->ibname) ++ __string(name, smc->conn.lnk ? smc->conn.lnk->ibname : "") + ), + + TP_fast_assign( +-- +2.53.0 + diff --git a/queue-6.6/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch b/queue-6.6/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch new file mode 100644 index 0000000000..06b4fa5778 --- /dev/null +++ b/queue-6.6/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch @@ -0,0 +1,63 @@ +From 473d745f690da44b0c61426410e01f09cba1037c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 23:21:38 -0700 +Subject: net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot + +From: Xiang Mei + +[ Upstream commit 277740023def559a4a2ddc3e8e784ee37a0f16a9 ] + +On the SMC-D client, slot 0 of ini->ism_dev[]/ini->ism_chid[] is +reserved for an SMC-Dv1 device. smc_find_ism_v2_device_clnt() +populates V2 entries starting at index 1, so when no V1 device is +selected slot 0 is left in its kzalloc()'ed state with ism_dev[0] == +NULL and ism_chid[0] == 0. + +smc_v2_determine_accepted_chid() then matches the peer's CHID against +the array starting from index 0 using the CHID alone. A malicious +peer replying to a SMC-Dv2-only proposal with d1.chid == 0 matches +the empty slot, ini->ism_selected becomes 0, and the subsequent +ism_dev[0]->lgr_lock dereference in smc_conn_create() faults at +offsetof(struct smcd_dev, lgr_lock) == 0x68: + + BUG: KASAN: null-ptr-deref in _raw_spin_lock_bh+0x79/0xe0 + Write of size 4 at addr 0000000000000068 by task exploit/144 + Call Trace: + _raw_spin_lock_bh + smc_conn_create (net/smc/smc_core.c:1997) + __smc_connect (net/smc/af_smc.c:1447) + smc_connect (net/smc/af_smc.c:1720) + __sys_connect + __x64_sys_connect + do_syscall_64 + +Require ism_dev[i] to be non-NULL before accepting a CHID match. + +Fixes: a7c9c5f4af7f ("net/smc: CLC accept / confirm V2") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260511062138.2839584-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 0e9a3b8da6a63..6629fd61be06a 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1378,7 +1378,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc, + int i; + + for (i = 0; i < ini->ism_offered_cnt + 1; i++) { +- if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) { ++ if (ini->ism_dev[i] && ++ ini->ism_chid[i] == ntohs(aclc->d1.chid)) { + ini->ism_selected = i; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-6.6/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..d371cffa28 --- /dev/null +++ b/queue-6.6/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 18d61841db03e6e387addb10ab90160ff8b6e0ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 937aa78eed0e4..5ada6e54fb328 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -800,11 +800,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-6.6/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-6.6/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..d87d6f729b --- /dev/null +++ b/queue-6.6/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From acf157e6af3c99aa5af05d8b5f28d97bea9cbf60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 5ada6e54fb328..0c2e9724083ee 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -789,21 +789,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-arptables-allow-xtables-nft-only-builds.patch b/queue-6.6/netfilter-arptables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..97cc5b846f --- /dev/null +++ b/queue-6.6/netfilter-arptables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,82 @@ +From 5895395b8cb394a667c581134557a5f8f4073504 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Jan 2024 16:42:48 +0100 +Subject: netfilter: arptables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 4654467dc7e111e84f43ed1b70322873ae77e7be ] + +Allows to build kernel that supports the arptables mangle target +via nftables' compat infra but without the arptables get/setsockopt +interface or the old arptables filter interpreter. + +IOW, setting IP_NF_ARPFILTER=n will break arptables-legacy, but +arptables-nft will continue to work as long as nftables compat +support is enabled. + +Signed-off-by: Florian Westphal +Reviewed-by: Phil Sutter +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index f71a7e9a7de6d..070475392236f 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -309,36 +309,34 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate "ARP tables support" +- select NETFILTER_XTABLES +- select NETFILTER_FAMILY_ARP +- depends on NETFILTER_ADVANCED +- help +- arptables is a general, extensible packet identification framework. +- The ARP packet filtering and mangling (manipulation)subsystems +- use this: say Y or M here if you want to use either of those. +- +- To compile it as a module, choose M here. If unsure, say N. ++ tristate + +-if IP_NF_ARPTABLES ++config NFT_COMPAT_ARP ++ tristate ++ depends on NF_TABLES_ARP && NFT_COMPAT ++ default m if NFT_COMPAT=m ++ default y if NFT_COMPAT=y + + config IP_NF_ARPFILTER +- tristate "ARP packet filtering" ++ tristate "arptables-legacy packet filtering support" ++ select IP_NF_ARPTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +- local output. On a bridge, you can also specify filtering rules +- for forwarded ARP packets. See the man page for arptables(8). ++ local output. This is only needed for arptables-legacy(8). ++ Neither arptables-nft nor nftables need this to work. + + To compile it as a module, choose M here. If unsure, say N. + + config IP_NF_ARP_MANGLE + tristate "ARP payload mangling" ++ depends on IP_NF_ARPTABLES || NFT_COMPAT_ARP + help + Allows altering the ARP packet payload: source and destination + hardware and network addresses. + +-endif # IP_NF_ARPTABLES ++ This option is needed by both arptables-legacy and arptables-nft. ++ It is not used by nftables. + + endmenu + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-arptables-select-netfilter_family_arp-when.patch b/queue-6.6/netfilter-arptables-select-netfilter_family_arp-when.patch new file mode 100644 index 0000000000..951af9cde2 --- /dev/null +++ b/queue-6.6/netfilter-arptables-select-netfilter_family_arp-when.patch @@ -0,0 +1,112 @@ +From b40b9b868ac7e6b5ec25a44c82b8f46ea066b6df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Mar 2024 21:15:52 -0700 +Subject: netfilter: arptables: Select NETFILTER_FAMILY_ARP when building + arp_tables.c + +From: Kuniyuki Iwashima + +[ Upstream commit 15fba562f7a9f04322b8bfc8f392e04bb93d81be ] + +syzkaller started to report a warning below [0] after consuming the +commit 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only +builds"). + +The change accidentally removed the dependency on NETFILTER_FAMILY_ARP +from IP_NF_ARPTABLES. + +If NF_TABLES_ARP is not enabled on Kconfig, NETFILTER_FAMILY_ARP will +be removed and some code necessary for arptables will not be compiled. + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + CONFIG_NETFILTER_FAMILY_ARP=y + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + + $ make olddefconfig + + $ grep -E "(NETFILTER_FAMILY_ARP|IP_NF_ARPTABLES|NF_TABLES_ARP)" .config + # CONFIG_NF_TABLES_ARP is not set + CONFIG_IP_NF_ARPTABLES=y + +So, when nf_register_net_hooks() is called for arptables, it will +trigger the splat below. + +Now IP_NF_ARPTABLES is only enabled by IP_NF_ARPFILTER, so let's +restore the dependency on NETFILTER_FAMILY_ARP in IP_NF_ARPFILTER. + +[0]: +WARNING: CPU: 0 PID: 242 at net/netfilter/core.c:316 nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Modules linked in: +CPU: 0 PID: 242 Comm: syz-executor.0 Not tainted 6.8.0-12821-g537c2e91d354 #10 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 +RIP: 0010:nf_hook_entry_head+0x1e1/0x2c0 net/netfilter/core.c:316 +Code: 83 fd 04 0f 87 bc 00 00 00 e8 5b 84 83 fd 4d 8d ac ec a8 0b 00 00 e8 4e 84 83 fd 4c 89 e8 5b 5d 41 5c 41 5d c3 e8 3f 84 83 fd <0f> 0b e8 38 84 83 fd 45 31 ed 5b 5d 4c 89 e8 41 5c 41 5d c3 e8 26 +RSP: 0018:ffffc90000b8f6e8 EFLAGS: 00010293 +RAX: 0000000000000000 RBX: 0000000000000003 RCX: ffffffff83c42164 +RDX: ffff888106851180 RSI: ffffffff83c42321 RDI: 0000000000000005 +RBP: 0000000000000000 R08: 0000000000000005 R09: 000000000000000a +R10: 0000000000000003 R11: ffff8881055c2f00 R12: ffff888112b78000 +R13: 0000000000000000 R14: ffff8881055c2f00 R15: ffff8881055c2f00 +FS: 00007f377bd78800(0000) GS:ffff88811b000000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000496068 CR3: 000000011298b003 CR4: 0000000000770ef0 +PKRU: 55555554 +Call Trace: + + __nf_register_net_hook+0xcd/0x7a0 net/netfilter/core.c:428 + nf_register_net_hook+0x116/0x170 net/netfilter/core.c:578 + nf_register_net_hooks+0x5d/0xc0 net/netfilter/core.c:594 + arpt_register_table+0x250/0x420 net/ipv4/netfilter/arp_tables.c:1553 + arptable_filter_table_init+0x41/0x60 net/ipv4/netfilter/arptable_filter.c:39 + xt_find_table_lock+0x2e9/0x4b0 net/netfilter/x_tables.c:1260 + xt_request_find_table_lock+0x2b/0xe0 net/netfilter/x_tables.c:1285 + get_info+0x169/0x5c0 net/ipv4/netfilter/arp_tables.c:808 + do_arpt_get_ctl+0x3f9/0x830 net/ipv4/netfilter/arp_tables.c:1444 + nf_getsockopt+0x76/0xd0 net/netfilter/nf_sockopt.c:116 + ip_getsockopt+0x17d/0x1c0 net/ipv4/ip_sockglue.c:1777 + tcp_getsockopt+0x99/0x100 net/ipv4/tcp.c:4373 + do_sock_getsockopt+0x279/0x360 net/socket.c:2373 + __sys_getsockopt+0x115/0x1e0 net/socket.c:2402 + __do_sys_getsockopt net/socket.c:2412 [inline] + __se_sys_getsockopt net/socket.c:2409 [inline] + __x64_sys_getsockopt+0xbd/0x150 net/socket.c:2409 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0x4f/0x110 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x46/0x4e +RIP: 0033:0x7f377beca6fe +Code: 1f 44 00 00 48 8b 15 01 97 0a 00 f7 d8 64 89 02 b8 ff ff ff ff eb b8 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 37 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 0a c3 66 0f 1f 84 00 00 00 00 00 48 8b 15 c9 +RSP: 002b:00000000005df728 EFLAGS: 00000246 ORIG_RAX: 0000000000000037 +RAX: ffffffffffffffda RBX: 00000000004966e0 RCX: 00007f377beca6fe +RDX: 0000000000000060 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 000000000042938a R08: 00000000005df73c R09: 00000000005df800 +R10: 00000000004966e8 R11: 0000000000000246 R12: 0000000000000003 +R13: 0000000000496068 R14: 0000000000000003 R15: 00000000004bc9d8 + + +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Reported-by: syzkaller +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Simon Horman +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 8f6e950163a79..1b991b889506a 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -329,6 +329,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ select NETFILTER_FAMILY_ARP + depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of +-- +2.53.0 + diff --git a/queue-6.6/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-6.6/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..b706592212 --- /dev/null +++ b/queue-6.6/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From d5f39f98114b46dec26170ebd68ef79b2970fd97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index ec286e54229b7..ca426e49ea1a1 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2583,19 +2583,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-ebtables-allow-xtables-nft-only-builds.patch b/queue-6.6/netfilter-ebtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..ed6eda39ad --- /dev/null +++ b/queue-6.6/netfilter-ebtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,84 @@ +From 30b4aa9ad56ffd9b0beb4e8e3e96b8f9fd030e92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:12 +0100 +Subject: netfilter: ebtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit 7ad269787b6615ca56bb161063331991fce51abf ] + +Same patch as previous one, but for ebtables. + +To build a kernel that only supports ebtables-nft, the builtin tables +need to be disabled, i.e.: + +CONFIG_BRIDGE_EBT_BROUTE=n +CONFIG_BRIDGE_EBT_T_FILTER=n +CONFIG_BRIDGE_EBT_T_NAT=n + +The ebtables specific extensions can then be used nftables' +NFT_COMPAT interface. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 7 +++++++ + net/bridge/netfilter/Makefile | 2 +- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 7f304a19ac1bf..104c0125e32e8 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -39,6 +39,10 @@ config NF_CONNTRACK_BRIDGE + + To compile it as a module, choose M here. If unsure, say N. + ++# old sockopt interface and eval loop ++config BRIDGE_NF_EBTABLES_LEGACY ++ tristate ++ + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" + depends on BRIDGE && NETFILTER && NETFILTER_XTABLES +@@ -55,6 +59,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -65,6 +70,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -74,6 +80,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" ++ select BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile +index 1c9ce49ab6513..b9a1303da9771 100644 +--- a/net/bridge/netfilter/Makefile ++++ b/net/bridge/netfilter/Makefile +@@ -9,7 +9,7 @@ obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o + # connection tracking + obj-$(CONFIG_NF_CONNTRACK_BRIDGE) += nf_conntrack_bridge.o + +-obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o ++obj-$(CONFIG_BRIDGE_NF_EBTABLES_LEGACY) += ebtables.o + + # tables + obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o +-- +2.53.0 + diff --git a/queue-6.6/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-6.6/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..75917a6e94 --- /dev/null +++ b/queue-6.6/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From 6ee07ea3923ea2fe4fc98e4210aad5028f5d6499 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 33d8640d21ac1..43c808e525e87 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index fdb988c24916a..f76d45dfe9b46 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -93,18 +93,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 8b981b2041b5d..af0732e2f889d 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -93,16 +93,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.6/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-6.6/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..11b02aeaff --- /dev/null +++ b/queue-6.6/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From 5105aed495bd3aa36f522ded7188574f021b5b77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 8f19253024b0a..33d8640d21ac1 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 278f324e67524..fdb988c24916a 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 9066f7f376d57..8b981b2041b5d 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index f99e348c8f37f..ec286e54229b7 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2556,11 +2560,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-exclude-legacy-tables-on-preempt_rt.patch b/queue-6.6/netfilter-exclude-legacy-tables-on-preempt_rt.patch new file mode 100644 index 0000000000..4de7e9aa90 --- /dev/null +++ b/queue-6.6/netfilter-exclude-legacy-tables-on-preempt_rt.patch @@ -0,0 +1,335 @@ +From 39ab7c7b5aac4e9aec4e451a172ed854f3ddbfad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Jun 2025 17:44:23 +0200 +Subject: netfilter: Exclude LEGACY TABLES on PREEMPT_RT. + +From: Pablo Neira Ayuso + +[ Upstream commit 9fce66583f06c212e95e4b76dd61d8432ffa56b6 ] + +The seqcount xt_recseq is used to synchronize the replacement of +xt_table::private in xt_replace_table() against all readers such as +ipt_do_table() + +To ensure that there is only one writer, the writing side disables +bottom halves. The sequence counter can be acquired recursively. Only the +first invocation modifies the sequence counter (signaling that a writer +is in progress) while the following (recursive) writer does not modify +the counter. +The lack of a proper locking mechanism for the sequence counter can lead +to live lock on PREEMPT_RT if the high prior reader preempts the +writer. Additionally if the per-CPU lock on PREEMPT_RT is removed from +local_bh_disable() then there is no synchronisation for the per-CPU +sequence counter. + +The affected code is "just" the legacy netfilter code which is replaced +by "netfilter tables". That code can be disabled without sacrificing +functionality because everything is provided by the newer +implementation. This will only requires the usage of the "-nft" tools +instead of the "-legacy" ones. +The long term plan is to remove the legacy code so lets accelerate the +progress. + +Relax dependencies on iptables legacy, replace select with depends on, +this should cause no harm to existing kernel configs and users can still +toggle IP{6}_NF_IPTABLES_LEGACY in any case. +Make EBTABLES_LEGACY, IPTABLES_LEGACY and ARPTABLES depend on +NETFILTER_XTABLES_LEGACY. Hide xt_recseq and its users, +xt_register_table() and xt_percpu_counter_alloc() behind +NETFILTER_XTABLES_LEGACY. Let NETFILTER_XTABLES_LEGACY depend on +!PREEMPT_RT. + +This will break selftest expecing the legacy options enabled and will be +addressed in a following patch. + +Co-developed-by: Florian Westphal +Co-developed-by: Sebastian Andrzej Siewior +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 10 +++++----- + net/ipv4/netfilter/Kconfig | 24 ++++++++++++------------ + net/ipv6/netfilter/Kconfig | 19 +++++++++---------- + net/netfilter/Kconfig | 10 ++++++++++ + net/netfilter/x_tables.c | 16 +++++++++++----- + 5 files changed, 47 insertions(+), 32 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index f16bbbbb94817..60f28e4fb5c0a 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -42,8 +42,8 @@ config NF_CONNTRACK_BRIDGE + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY + tristate "Legacy EBTABLES support" +- depends on BRIDGE && NETFILTER_XTABLES +- default n ++ depends on BRIDGE && NETFILTER_XTABLES_LEGACY ++ default n + help + Legacy ebtables packet/frame classifier. + This is not needed if you are using ebtables over nftables +@@ -65,7 +65,7 @@ if BRIDGE_NF_EBTABLES + # + config BRIDGE_EBT_BROUTE + tristate "ebt: broute table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables broute table is used to define rules that decide between + bridging and routing frames, giving Linux the functionality of a +@@ -76,7 +76,7 @@ config BRIDGE_EBT_BROUTE + + config BRIDGE_EBT_T_FILTER + tristate "ebt: filter table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables filter table is used to define frame filtering rules at + local input, forwarding and local output. See the man page for +@@ -86,7 +86,7 @@ config BRIDGE_EBT_T_FILTER + + config BRIDGE_EBT_T_NAT + tristate "ebt: nat table support" +- select BRIDGE_NF_EBTABLES_LEGACY ++ depends on BRIDGE_NF_EBTABLES_LEGACY + help + The ebtables nat table is used to define rules that alter the MAC + source address (MAC SNAT) or the MAC destination address (MAC DNAT). +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index ef8009281da5c..2c438b140e88f 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -13,8 +13,8 @@ config NF_DEFRAG_IPV4 + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY + tristate "Legacy IP tables support" +- default n +- select NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + iptables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -182,8 +182,8 @@ config IP_NF_MATCH_TTL + # `filter', generic and specific targets + config IP_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -220,10 +220,10 @@ config IP_NF_TARGET_SYNPROXY + config IP_NF_NAT + tristate "iptables NAT support" + depends on NF_CONNTRACK ++ depends on IP_NF_IPTABLES_LEGACY + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -263,8 +263,8 @@ endif # IP_NF_NAT + # mangle + specific targets + config IP_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -299,7 +299,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -313,7 +313,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP_NF_IPTABLES_LEGACY ++ depends on IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -325,8 +325,8 @@ endif # IP_NF_IPTABLES + # ARP tables + config IP_NF_ARPTABLES + tristate "Legacy ARPTABLES support" +- depends on NETFILTER_XTABLES +- default n ++ depends on NETFILTER_XTABLES_LEGACY ++ default n + help + arptables is a legacy packet classifier. + This is not needed if you are using arptables over nftables +@@ -342,7 +342,7 @@ config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES + select NETFILTER_FAMILY_ARP +- depends on NETFILTER_XTABLES ++ depends on NETFILTER_XTABLES_LEGACY + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index e087a8e97ba78..276860f65baae 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -9,9 +9,8 @@ menu "IPv6: Netfilter Configuration" + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY + tristate "Legacy IP6 tables support" +- depends on INET && IPV6 +- select NETFILTER_XTABLES +- default n ++ depends on INET && IPV6 && NETFILTER_XTABLES_LEGACY ++ default m if NETFILTER_XTABLES_LEGACY + help + ip6tables is a legacy packet classifier. + This is not needed if you are using iptables over nftables +@@ -196,8 +195,8 @@ config IP6_NF_TARGET_HL + + config IP6_NF_FILTER + tristate "Packet filtering" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + tristate + help + Packet filtering defines a table `filter', which has a series of +@@ -233,8 +232,8 @@ config IP6_NF_TARGET_SYNPROXY + + config IP6_NF_MANGLE + tristate "Packet mangling" +- default m if NETFILTER_ADVANCED=n +- select IP6_NF_IPTABLES_LEGACY ++ default m if NETFILTER_ADVANCED=n || IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -244,7 +243,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -258,7 +257,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED +- select IP6_NF_IPTABLES_LEGACY ++ depends on IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -269,8 +268,8 @@ config IP6_NF_NAT + tristate "ip6tables NAT support" + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED ++ depends on IP6_NF_IPTABLES_LEGACY + select NF_NAT +- select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index df2dc21304efb..0d1d997abe191 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -762,6 +762,16 @@ config NETFILTER_XTABLES_COMPAT + + If unsure, say N. + ++config NETFILTER_XTABLES_LEGACY ++ bool "Netfilter legacy tables support" ++ depends on !PREEMPT_RT ++ help ++ Say Y here if you still require support for legacy tables. This is ++ required by the legacy tools (iptables-legacy) and is not needed if ++ you use iptables over nftables (iptables-nft). ++ Legacy support is not limited to IP, it also includes EBTABLES and ++ ARPTABLES. ++ + comment "Xtables combined modules" + + config NETFILTER_XT_MARK +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index c1ab85fb8c46d..98384bb17bbe3 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1339,12 +1339,13 @@ void xt_compat_unlock(u_int8_t af) + EXPORT_SYMBOL_GPL(xt_compat_unlock); + #endif + +-DEFINE_PER_CPU(seqcount_t, xt_recseq); +-EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); +- + struct static_key xt_tee_enabled __read_mostly; + EXPORT_SYMBOL_GPL(xt_tee_enabled); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY ++DEFINE_PER_CPU(seqcount_t, xt_recseq); ++EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); ++ + static int xt_jumpstack_alloc(struct xt_table_info *i) + { + unsigned int size; +@@ -1536,6 +1537,7 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++#endif + + #ifdef CONFIG_PROC_FS + static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) +@@ -1919,6 +1921,7 @@ void xt_proto_fini(struct net *net, u_int8_t af) + } + EXPORT_SYMBOL_GPL(xt_proto_fini); + ++#ifdef CONFIG_NETFILTER_XTABLES_LEGACY + /** + * xt_percpu_counter_alloc - allocate x_tables rule counter + * +@@ -1973,6 +1976,7 @@ void xt_percpu_counter_free(struct xt_counters *counters) + free_percpu((void __percpu *)pcnt); + } + EXPORT_SYMBOL_GPL(xt_percpu_counter_free); ++#endif + + static int __net_init xt_net_init(struct net *net) + { +@@ -2005,8 +2009,10 @@ static int __init xt_init(void) + unsigned int i; + int rv; + +- for_each_possible_cpu(i) { +- seqcount_init(&per_cpu(xt_recseq, i)); ++ if (IS_ENABLED(CONFIG_NETFILTER_XTABLES_LEGACY)) { ++ for_each_possible_cpu(i) { ++ seqcount_init(&per_cpu(xt_recseq, i)); ++ } + } + + xt = kcalloc(NFPROTO_NUMPROTO, sizeof(struct xt_af), GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-6.6/netfilter-make-legacy-configs-user-selectable.patch b/queue-6.6/netfilter-make-legacy-configs-user-selectable.patch new file mode 100644 index 0000000000..e0f729a033 --- /dev/null +++ b/queue-6.6/netfilter-make-legacy-configs-user-selectable.patch @@ -0,0 +1,104 @@ +From cbc16a2f74d7876483b5435b22b99f8a06db6e8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 02:58:54 -0700 +Subject: netfilter: Make legacy configs user selectable + +From: Breno Leitao + +[ Upstream commit 6c959fd5e17387201dba3619b2e6af213939a0a7 ] + +This option makes legacy Netfilter Kconfig user selectable, giving users +the option to configure iptables without enabling any other config. + +Make the following KConfig entries user selectable: + * BRIDGE_NF_EBTABLES_LEGACY + * IP_NF_ARPTABLES + * IP_NF_IPTABLES_LEGACY + * IP6_NF_IPTABLES_LEGACY + +Signed-off-by: Breno Leitao +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/Kconfig | 8 +++++++- + net/ipv4/netfilter/Kconfig | 16 ++++++++++++++-- + net/ipv6/netfilter/Kconfig | 9 ++++++++- + 3 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig +index 104c0125e32e8..f16bbbbb94817 100644 +--- a/net/bridge/netfilter/Kconfig ++++ b/net/bridge/netfilter/Kconfig +@@ -41,7 +41,13 @@ config NF_CONNTRACK_BRIDGE + + # old sockopt interface and eval loop + config BRIDGE_NF_EBTABLES_LEGACY +- tristate ++ tristate "Legacy EBTABLES support" ++ depends on BRIDGE && NETFILTER_XTABLES ++ default n ++ help ++ Legacy ebtables packet/frame classifier. ++ This is not needed if you are using ebtables over nftables ++ (iptables-nft). + + menuconfig BRIDGE_NF_EBTABLES + tristate "Ethernet Bridge tables (ebtables) support" +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 1b991b889506a..ef8009281da5c 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -12,7 +12,13 @@ config NF_DEFRAG_IPV4 + + # old sockopt interface and eval loop + config IP_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP tables support" ++ default n ++ select NETFILTER_XTABLES ++ help ++ iptables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" +@@ -318,7 +324,13 @@ endif # IP_NF_IPTABLES + + # ARP tables + config IP_NF_ARPTABLES +- tristate ++ tristate "Legacy ARPTABLES support" ++ depends on NETFILTER_XTABLES ++ default n ++ help ++ arptables is a legacy packet classifier. ++ This is not needed if you are using arptables over nftables ++ (iptables-nft). + + config NFT_COMPAT_ARP + tristate +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index f3c8e2d918e13..e087a8e97ba78 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -8,7 +8,14 @@ menu "IPv6: Netfilter Configuration" + + # old sockopt interface and eval loop + config IP6_NF_IPTABLES_LEGACY +- tristate ++ tristate "Legacy IP6 tables support" ++ depends on INET && IPV6 ++ select NETFILTER_XTABLES ++ default n ++ help ++ ip6tables is a legacy packet classifier. ++ This is not needed if you are using iptables over nftables ++ (iptables-nft). + + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" +-- +2.53.0 + diff --git a/queue-6.6/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-6.6/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..3960828935 --- /dev/null +++ b/queue-6.6/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From 918516f417ff52edb3b3180e6c0e8670646c3d75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e8..c593113557333 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -78,7 +78,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -787,6 +790,9 @@ static void dump_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-6.6/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..b14ba19f67 --- /dev/null +++ b/queue-6.6/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From afd50ef07fd1eed4f190dfe08c9245253beacb88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 5897f3dbaf7c3..df2022fe440b0 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -310,6 +310,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 132b0e4a6d4df..13593391d6058 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 8b8885a73c764..c6d5b927830dd 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 564054123772a..9b905c6562313 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1581,15 +1581,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index fe89a056eb06c..8240b3b0e0260 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1789,14 +1789,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1887,7 +1879,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index c03c1a4ea7cab..fb85745793ba5 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -61,7 +61,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 6a51e61b35562..6259bcf178bba 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -95,7 +95,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 12ca666d6e2c1..ca6964b957ead 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -129,6 +129,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 33330e13ea18d..c7b91b2042dc6 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -53,7 +53,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 2b89adc1e5751..81175c20ccbe8 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -50,7 +50,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 131f7bb2110d3..c956c2bd73d59 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1795,14 +1795,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1894,7 +1886,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 16a38d56b2e54..982900920e730 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -60,7 +60,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 39f0716667131..475361aa81310 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -88,7 +88,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 52d597b16b658..bef2d309369bc 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -131,6 +131,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 01def8aa7a2e8..a99879f173b4a 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -52,7 +52,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 66018b169b010..c44834d93fc79 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -49,7 +49,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 98384bb17bbe3..670483735d225 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1537,6 +1537,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-6.6/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-6.6/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..0cce26d674 --- /dev/null +++ b/queue-6.6/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From dc06ebc5bd3e59fea1fcb3c0e7b5e15cd54f9078 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index df2022fe440b0..706f08839050a 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -309,8 +309,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 9b905c6562313..f9dd18244f251 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1583,7 +1582,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 8240b3b0e0260..02730b6ab8203 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1704,12 +1704,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1718,6 +1716,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1791,7 +1790,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index ca6964b957ead..87d934b12bcb6 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -119,8 +119,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index c956c2bd73d59..2cbf346940d29 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1713,12 +1713,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1727,6 +1725,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1797,7 +1796,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index bef2d309369bc..cf260d8ebdb70 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -121,8 +121,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 670483735d225..593eb3ebef128 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1521,23 +1524,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1547,6 +1533,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1556,6 +1550,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1566,6 +1561,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2012,8 +2051,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2022,8 +2063,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-6.6/netfilter-x_tables-close-dangling-table-module-init-.patch b/queue-6.6/netfilter-x_tables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..98ef2f2c8c --- /dev/null +++ b/queue-6.6/netfilter-x_tables-close-dangling-table-module-init-.patch @@ -0,0 +1,406 @@ +From 12788a75a0c46ade136f6b17b9b82700af9ce2b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:20 +0200 +Subject: netfilter: x_tables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 16bc4b6686b2c112c10e67d6b493adc3607256d3 ] + +Similar to the previous ebtables patch: +template add exposes the table to userspace, we must do this last to +rnsure the pernet ops are set up (contain the destructors). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_mangle.c | 25 +++++++++++++------------ + net/ipv4/netfilter/iptable_raw.c | 22 +++++++++++----------- + net/ipv4/netfilter/iptable_security.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_filter.c | 22 +++++++++++----------- + net/ipv6/netfilter/ip6table_mangle.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_raw.c | 20 ++++++++++---------- + net/ipv6/netfilter/ip6table_security.c | 23 ++++++++++++----------- + 9 files changed, 105 insertions(+), 99 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 382345567a600..370b635e3523b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = { + + static int __init arptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- arptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); +- if (IS_ERR(arpfilter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(arpfilter_ops)) + return PTR_ERR(arpfilter_ops); +- } + + ret = register_pernet_subsys(&arptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ arptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(arpfilter_ops); +- return ret; ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(arpfilter_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index fb85745793ba5..409e96c72164b 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = { + + static int __init iptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- iptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&iptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ iptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_filter_net_ops); ++ goto err_free; + } + + return 0; ++err_free: ++ kfree(filter_ops); ++ return ret; + } + + static void __exit iptable_filter_fini(void) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 6259bcf178bba..b8618bdf5fdc4 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -110,25 +110,26 @@ static struct pernet_operations iptable_mangle_net_ops = { + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); +- ret = PTR_ERR(mangle_ops); +- return ret; +- } ++ if (IS_ERR(mangle_ops)) ++ return PTR_ERR(mangle_ops); + + ret = register_pernet_subsys(&iptable_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ iptable_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index c7b91b2042dc6..94ad7fad3a1f3 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, +- iptable_raw_table_init); +- if (ret < 0) +- return ret; +- + rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&iptable_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ++ iptable_raw_table_init); + if (ret < 0) { +- xt_unregister_template(table); +- kfree(rawtable_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 81175c20ccbe8..491894511c544 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = { + + static int __init iptable_security_init(void) + { +- int ret = xt_register_template(&security_table, +- iptable_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&iptable_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ iptable_security_table_init); + if (ret < 0) { +- xt_unregister_template(&security_table); +- kfree(sectbl_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 982900920e730..f444071346859 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = { + + static int __init ip6table_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- ip6table_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&ip6table_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ip6table_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(filter_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 475361aa81310..dbc64e4428403 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -103,25 +103,26 @@ static struct pernet_operations ip6table_mangle_net_ops = { + + static int __init ip6table_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- ip6table_mangle_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); ++ if (IS_ERR(mangle_ops)) + return PTR_ERR(mangle_ops); +- } + + ret = register_pernet_subsys(&ip6table_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ ip6table_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index a99879f173b4a..1eadf553c746e 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, ip6table_raw_table_init); +- if (ret < 0) +- return ret; +- + /* Register hooks */ + rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&ip6table_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ip6table_raw_table_init); + if (ret < 0) { +- kfree(rawtable_ops); +- xt_unregister_template(table); +- return ret; ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index c44834d93fc79..4bd5d97b8ab65 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = { + + static int __init ip6table_security_init(void) + { +- int ret = xt_register_template(&security_table, +- ip6table_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&ip6table_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ ip6table_security_table_init); + if (ret < 0) { +- kfree(sectbl_ops); +- xt_unregister_template(&security_table); +- return ret; ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-x_tables-unregister-the-templates-first.patch b/queue-6.6/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..962896683c --- /dev/null +++ b/queue-6.6/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From a45abc5bdfe96632065c794deea157e96d72eaab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 78cd5ee24448f..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -82,8 +82,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index b9062f4552ace..c03c1a4ea7cab 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -101,8 +101,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 3abb430af9e6f..6a51e61b35562 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -134,8 +134,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index ca5e5b21587cd..33330e13ea18d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -100,9 +100,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index d885443cb2679..2b89adc1e5751 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -89,9 +89,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index df785ebda0ca4..16a38d56b2e54 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -100,8 +100,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index a88b2ce4a3cb8..39f0716667131 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -127,8 +127,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 08861d5d1f4db..01def8aa7a2e8 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -98,8 +98,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 4df14a9bae782..66018b169b010 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -88,8 +88,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xtables-allow-xtables-nft-only-builds.patch b/queue-6.6/netfilter-xtables-allow-xtables-nft-only-builds.patch new file mode 100644 index 0000000000..1b48904965 --- /dev/null +++ b/queue-6.6/netfilter-xtables-allow-xtables-nft-only-builds.patch @@ -0,0 +1,315 @@ +From b99eae8ebf9ef3663ac78357091f29be8e5a0693 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jan 2024 10:21:11 +0100 +Subject: netfilter: xtables: allow xtables-nft only builds + +From: Florian Westphal + +[ Upstream commit a9525c7f6219cee9284c0031c5930e8d41384677 ] + +Add hidden IP(6)_NF_IPTABLES_LEGACY symbol. + +When any of the "old" builtin tables are enabled the "old" iptables +interface will be supported. + +To disable the old set/getsockopt interface the existing options +for the builtin tables need to be turned off: + +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER is not set +CONFIG_IP_NF_NAT is not set +CONFIG_IP_NF_MANGLE is not set +CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_SECURITY is not set + +Same for CONFIG_IP6_NF_ variants. + +This allows to build a kernel that only supports ip(6)tables-nft +(iptables-over-nftables api). + +In the future the _LEGACY symbol will become visible and the select +statements will be turned into 'depends on', but for now be on safe side +so "make oldconfig" won't break things. + +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 15 ++++++++++++--- + net/ipv4/netfilter/Makefile | 2 +- + net/ipv6/netfilter/Kconfig | 20 ++++++++++++++------ + net/ipv6/netfilter/Makefile | 2 +- + net/netfilter/Kconfig | 12 ++++++------ + 5 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 070475392236f..7835230872818 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -10,6 +10,10 @@ config NF_DEFRAG_IPV4 + tristate + default n + ++# old sockopt interface and eval loop ++config IP_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV4 + tristate "IPv4 socket lookup support" + help +@@ -152,7 +156,7 @@ config IP_NF_MATCH_ECN + config IP_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP_NF_MANGLE || IP_NF_RAW ++ depends on IP_NF_MANGLE || IP_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -173,6 +177,7 @@ config IP_NF_MATCH_TTL + config IP_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -182,7 +187,7 @@ config IP_NF_FILTER + + config IP_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP_NF_FILTER ++ depends on IP_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV4 + default m if NETFILTER_ADVANCED=n + help +@@ -212,6 +217,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT ++ select IP6_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -252,6 +258,7 @@ endif # IP_NF_NAT + config IP_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -261,7 +268,7 @@ config IP_NF_MANGLE + + config IP_NF_TARGET_ECN + tristate "ECN target support" +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `ECN' target, which can be used in the iptables mangle +@@ -286,6 +293,7 @@ config IP_NF_TARGET_TTL + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to iptables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -299,6 +307,7 @@ config IP_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile +index 5a26f9de1ab92..85502d4dfbb4d 100644 +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -25,7 +25,7 @@ obj-$(CONFIG_NFT_FIB_IPV4) += nft_fib_ipv4.o + obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o + + # generic IP tables +-obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o ++obj-$(CONFIG_IP_NF_IPTABLES_LEGACY) += ip_tables.o + + # the three instances of ip_tables + obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o +diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig +index 0ba62f4868f97..f3c8e2d918e13 100644 +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -6,6 +6,10 @@ + menu "IPv6: Netfilter Configuration" + depends on INET && IPV6 && NETFILTER + ++# old sockopt interface and eval loop ++config IP6_NF_IPTABLES_LEGACY ++ tristate ++ + config NF_SOCKET_IPV6 + tristate "IPv6 socket lookup support" + help +@@ -147,7 +151,7 @@ config IP6_NF_MATCH_MH + config IP6_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +- depends on IP6_NF_MANGLE || IP6_NF_RAW ++ depends on IP6_NF_MANGLE || IP6_NF_RAW || NFT_COMPAT + help + This option allows you to match packets whose replies would + go out via the interface the packet came in. +@@ -186,6 +190,8 @@ config IP6_NF_TARGET_HL + config IP6_NF_FILTER + tristate "Packet filtering" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY ++ tristate + help + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and +@@ -195,7 +201,7 @@ config IP6_NF_FILTER + + config IP6_NF_TARGET_REJECT + tristate "REJECT target support" +- depends on IP6_NF_FILTER ++ depends on IP6_NF_FILTER || NFT_COMPAT + select NF_REJECT_IPV6 + default m if NETFILTER_ADVANCED=n + help +@@ -221,6 +227,7 @@ config IP6_NF_TARGET_SYNPROXY + config IP6_NF_MANGLE + tristate "Packet mangling" + default m if NETFILTER_ADVANCED=n ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations +@@ -230,6 +237,7 @@ config IP6_NF_MANGLE + + config IP6_NF_RAW + tristate 'raw table support (required for TRACE)' ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `raw' table to ip6tables. This table is the very + first in the netfilter framework and hooks in at the PREROUTING +@@ -243,6 +251,7 @@ config IP6_NF_SECURITY + tristate "Security table" + depends on SECURITY + depends on NETFILTER_ADVANCED ++ select IP6_NF_IPTABLES_LEGACY + help + This option adds a `security' table to iptables, for use + with Mandatory Access Control (MAC) policy. +@@ -254,6 +263,7 @@ config IP6_NF_NAT + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED + select NF_NAT ++ select IP6_NF_IPTABLES_LEGACY + select NETFILTER_XT_NAT + help + This enables the `nat' table in ip6tables. This allows masquerading, +@@ -262,25 +272,23 @@ config IP6_NF_NAT + + To compile it as a module, choose M here. If unsure, say N. + +-if IP6_NF_NAT +- + config IP6_NF_TARGET_MASQUERADE + tristate "MASQUERADE target support" + select NETFILTER_XT_TARGET_MASQUERADE ++ depends on IP6_NF_NAT + help + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE. + + config IP6_NF_TARGET_NPT + tristate "NPT (Network Prefix translation) target support" ++ depends on IP6_NF_NAT || NFT_COMPAT + help + This option adds the `SNPT' and `DNPT' target, which perform + stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. + + To compile it as a module, choose M here. If unsure, say N. + +-endif # IP6_NF_NAT +- + endif # IP6_NF_IPTABLES + endmenu + +diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile +index b8d6dc9aeeb6f..66ce6fa5b2f52 100644 +--- a/net/ipv6/netfilter/Makefile ++++ b/net/ipv6/netfilter/Makefile +@@ -4,7 +4,7 @@ + # + + # Link order matters here. +-obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o ++obj-$(CONFIG_IP6_NF_IPTABLES_LEGACY) += ip6_tables.o + obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o + obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o + obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o +diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig +index 441d1f1341100..df2dc21304efb 100644 +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -818,7 +818,7 @@ config NETFILTER_XT_TARGET_AUDIT + + config NETFILTER_XT_TARGET_CHECKSUM + tristate "CHECKSUM target support" +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `CHECKSUM' target, which can be used in the iptables mangle +@@ -869,7 +869,7 @@ config NETFILTER_XT_TARGET_CONNSECMARK + config NETFILTER_XT_TARGET_CT + tristate '"CT" target support' + depends on NF_CONNTRACK +- depends on IP_NF_RAW || IP6_NF_RAW ++ depends on IP_NF_RAW || IP6_NF_RAW || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This options adds a `CT' target, which allows to specify initial +@@ -880,7 +880,7 @@ config NETFILTER_XT_TARGET_CT + + config NETFILTER_XT_TARGET_DSCP + tristate '"DSCP" and "TOS" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a `DSCP' target, which allows you to manipulate +@@ -896,7 +896,7 @@ config NETFILTER_XT_TARGET_DSCP + + config NETFILTER_XT_TARGET_HL + tristate '"HL" hoplimit target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds the "HL" (for IPv6) and "TTL" (for IPv4) +@@ -1080,7 +1080,7 @@ config NETFILTER_XT_TARGET_TPROXY + depends on NETFILTER_ADVANCED + depends on IPV6 || IPV6=n + depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n +- depends on IP_NF_MANGLE ++ depends on IP_NF_MANGLE || NFT_COMPAT + select NF_DEFRAG_IPV4 + select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n + select NF_TPROXY_IPV4 +@@ -1147,7 +1147,7 @@ config NETFILTER_XT_TARGET_TCPMSS + + config NETFILTER_XT_TARGET_TCPOPTSTRIP + tristate '"TCPOPTSTRIP" target support' +- depends on IP_NF_MANGLE || IP6_NF_MANGLE ++ depends on IP_NF_MANGLE || IP6_NF_MANGLE || NFT_COMPAT + depends on NETFILTER_ADVANCED + help + This option adds a "TCPOPTSTRIP" target, which allows you to strip +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xtables-fix-up-kconfig-dependencies.patch b/queue-6.6/netfilter-xtables-fix-up-kconfig-dependencies.patch new file mode 100644 index 0000000000..66d9851482 --- /dev/null +++ b/queue-6.6/netfilter-xtables-fix-up-kconfig-dependencies.patch @@ -0,0 +1,58 @@ +From a8e47c49320074de11a18730554370dfe0fd9260 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Feb 2024 14:55:53 +0100 +Subject: netfilter: xtables: fix up kconfig dependencies + +From: Florian Westphal + +[ Upstream commit 749d4ef0868c5d8a98e07073791b2198178c93b4 ] + +Randy Dunlap reports arptables build failure: +arp_tables.c:(.text+0x20): undefined reference to `xt_find_table' + +... because recent change removed a 'select' on the xtables core. +Add a "depends" clause on arptables to resolve this. + +Kernel test robot reports another build breakage: +iptable_nat.c:(.text+0x8): undefined reference to `ipt_unregister_table_exit' + +... because of a typo, the nat table selected ip6tables. + +Reported-by: kernel test robot +Reported-by: Randy Dunlap +Closes: https://lore.kernel.org/netfilter-devel/d0dfbaef-046a-4c42-9daa-53636664bf6d@infradead.org/ +Fixes: a9525c7f6219 ("netfilter: xtables: allow xtables-nft only builds") +Fixes: 4654467dc7e1 ("netfilter: arptables: allow xtables-nft only builds") +Acked-by: Randy Dunlap +Tested-by: Randy Dunlap # build-tested +Signed-off-by: Florian Westphal +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig +index 7835230872818..8f6e950163a79 100644 +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -217,7 +217,7 @@ config IP_NF_NAT + default m if NETFILTER_ADVANCED=n + select NF_NAT + select NETFILTER_XT_NAT +- select IP6_NF_IPTABLES_LEGACY ++ select IP_NF_IPTABLES_LEGACY + help + This enables the `nat' table in iptables. This allows masquerading, + port forwarding and other forms of full Network Address Port +@@ -329,6 +329,7 @@ config NFT_COMPAT_ARP + config IP_NF_ARPFILTER + tristate "arptables-legacy packet filtering support" + select IP_NF_ARPTABLES ++ depends on NETFILTER_XTABLES + help + ARP packet filtering defines a table `filter', which has a series of + rules for simple ARP packet filtering at local input and +-- +2.53.0 + diff --git a/queue-6.6/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch b/queue-6.6/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch new file mode 100644 index 0000000000..3f4f8f20d3 --- /dev/null +++ b/queue-6.6/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch @@ -0,0 +1,80 @@ +From 396dfda7057becc8b3e2b9e2655321408a8cb7d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:47 +0100 +Subject: netfs: Fix overrun check in netfs_extract_user_iter() + +From: David Howells + +[ Upstream commit 0ef37eef83fad3542ee06db2940433ae1a92b39d ] + +Fix netfs_extract_user_iter() so that if iov_iter_extract_pages() overfills +pages[], then those pages don't get included in the iterator constructed at +the end of the function. If there was an overfill, memory corruption has +already happened. + +Fixes: 85dd2c8ff368 ("netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-11-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/iterator.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c +index 781ea403498e3..9a047ca863fe5 100644 +--- a/fs/netfs/iterator.c ++++ b/fs/netfs/iterator.c +@@ -72,21 +72,24 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + break; + } + +- if (ret > count) { +- pr_err("get_pages rc=%zd more than %zu\n", ret, count); ++ if (WARN(ret > count, ++ "%s: extract_pages overrun %zd > %zu bytes\n", ++ __func__, ret, count)) { ++ ret = -EIO; + break; + } + +- count -= ret; +- ret += offset; +- cur_npages = DIV_ROUND_UP(ret, PAGE_SIZE); +- +- if (npages + cur_npages > max_pages) { +- pr_err("Out of bvec array capacity (%u vs %u)\n", +- npages + cur_npages, max_pages); ++ cur_npages = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ if (WARN(cur_npages > max_pages - npages, ++ "%s: extract_pages overrun %u > %u pages\n", ++ __func__, npages + cur_npages, max_pages)) { ++ ret = -EIO; + break; + } + ++ count -= ret; ++ ret += offset; ++ + for (i = 0; i < cur_npages; i++) { + len = ret > PAGE_SIZE ? PAGE_SIZE : ret; + bvec_set_page(bv + npages + i, *pages++, len - offset, offset); +@@ -97,6 +100,11 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + npages += cur_npages; + } + ++ /* Note: Don't try to clean up after EIO. Either we got no pages, so ++ * nothing to clean up, or we got a buffer overrun, memory corruption ++ * and can't trust the stuff in the buffer (a WARN was emitted). ++ */ ++ + if (ret < 0 && (ret == -ENOMEM || npages == 0)) { + for (i = 0; i < npages; i++) + unpin_user_page(bv[i].bv_page); +-- +2.53.0 + diff --git a/queue-6.6/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch b/queue-6.6/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch new file mode 100644 index 0000000000..a9a3920be3 --- /dev/null +++ b/queue-6.6/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch @@ -0,0 +1,116 @@ +From 785141cb90d3a0a5d7088285bdd1e6c01b2b7b23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:19:27 -0500 +Subject: NFS: Use nlmclnt_shutdown_rpc_clnt() to safely shut down NLM + +From: Chuck Lever + +[ Upstream commit 840621fd2ff23ada8b9262d90477e75232566e6b ] + +A race condition exists in shutdown_store() when writing to the sysfs +"shutdown" file concurrently with nlm_shutdown_hosts_net(). Without +synchronization, the following sequence can occur: + + 1. shutdown_store() reads server->nlm_host (non-NULL) + 2. nlm_shutdown_hosts_net() acquires nlm_host_mutex, calls + rpc_shutdown_client(), sets h_rpcclnt to NULL, and potentially + frees the host via nlm_gc_hosts() + 3. shutdown_store() dereferences the now-stale or freed host + +Introduce nlmclnt_shutdown_rpc_clnt(), which acquires nlm_host_mutex +before accessing h_rpcclnt. This synchronizes with +nlm_shutdown_hosts_net() and ensures the rpc_clnt pointer remains +valid during the shutdown operation. + +This change also improves API layering: NFS client code no longer +needs to include the internal lockd header to access nlm_host fields. +The new helper resides in bind.h alongside other public lockd +interfaces. + +Reported-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 29 +++++++++++++++++++++++++++++ + fs/nfs/sysfs.c | 4 ++-- + include/linux/lockd/bind.h | 1 + + 3 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 127a728fcbc81..a2bd313c162d1 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -307,6 +307,35 @@ void nlmclnt_release_host(struct nlm_host *host) + } + } + ++/* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ ++static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) ++{ ++ return true; ++} ++ ++/** ++ * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations ++ * @host: nlm_host to shut down ++ * ++ * Cancels outstanding RPC tasks and marks the client as shut down. ++ * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent ++ * races between shutdown and host destruction. Safe to call if h_rpcclnt ++ * is NULL or already shut down. ++ */ ++void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) ++{ ++ struct rpc_clnt *clnt; ++ ++ mutex_lock(&nlm_host_mutex); ++ clnt = host->h_rpcclnt; ++ if (clnt) { ++ clnt->cl_shutdown = 1; ++ rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); ++ } ++ mutex_unlock(&nlm_host_mutex); ++} ++EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); ++ + /** + * nlmsvc_lookup_host - Find an NLM host handle matching a remote client + * @rqstp: incoming NLM request +diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c +index 53d4cdf28ee00..5a772aa490d6e 100644 +--- a/fs/nfs/sysfs.c ++++ b/fs/nfs/sysfs.c +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + + #include "internal.h" + #include "nfs4_fs.h" +@@ -285,7 +285,7 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr, + shutdown_client(server->client_acl); + + if (server->nlm_host) +- shutdown_client(server->nlm_host->h_rpcclnt); ++ nlmclnt_shutdown_rpc_clnt(server->nlm_host); + out: + shutdown_nfs_client(server->nfs_client); + return count; +diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h +index c53c81242e727..40c124f932252 100644 +--- a/include/linux/lockd/bind.h ++++ b/include/linux/lockd/bind.h +@@ -58,6 +58,7 @@ struct nlmclnt_initdata { + extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); + extern void nlmclnt_done(struct nlm_host *host); + extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); ++extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); + + /* + * NLM client operations provide a means to modify RPC processing of NLM +-- +2.53.0 + diff --git a/queue-6.6/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-6.6/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..21bffc0b99 --- /dev/null +++ b/queue-6.6/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From 2a46dded856766c13ea1f54a60ba995b05c75022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index 4330c2b39e505..5ee9e61170152 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1484,6 +1484,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-6.6/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch b/queue-6.6/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch new file mode 100644 index 0000000000..05467e542f --- /dev/null +++ b/queue-6.6/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch @@ -0,0 +1,56 @@ +From b46c660eec2c72b9c16678c222a94abd9c713c03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:57:57 +0200 +Subject: ntfs3: fix OOB write in attr_wof_frame_info() + +From: 0xkato <0xkkato@gmail.com> + +[ Upstream commit 859d777646b56dd878b136392f3d03fb8153b559 ] + +In attr_wof_frame_info(), the offset-table read range for a nonresident +WofCompressedData stream is: + + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ... + ntfs_read_run(sbi, run, addr, from, to - from); + +A crafted image sets WofCompressedData.nres.data_size to 0xfff while the +file is large enough to request frame 1024 (offset 0x400000). This gives +from=0x1000, to=0xfff. The unsigned (to - from) wraps to 0xffffffffffffffff +and ntfs_read_write_run() overflows the single-page offs_folio via memcpy. + +Triggered by pread() on a mounted NTFS image. Depending on adjacent +memory layout at the time of the overflow, KASAN reports this as +slab-out-of-bounds, use-after-free, or slab-use-after-free all at +ntfs_read_write_run(). Secondary corruption/panic paths were also observed. + +Reject the read when the offset-table page is outside the stream. + +Signed-off-by: 0xkato <0xkkato@gmail.com> +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index 8f033e30e0d79..7169e29d1682e 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1484,6 +1484,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr, + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ++ if (from >= wof_size) { ++ _ntfs_bad_inode(&ni->vfs_inode); ++ err = -EINVAL; ++ goto out1; ++ } ++ + err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME, + ARRAY_SIZE(WOF_NAME), run, + from, to); +-- +2.53.0 + diff --git a/queue-6.6/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-6.6/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..ae15bea8e8 --- /dev/null +++ b/queue-6.6/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From 0344c5838bc0f3f219ac9e352dd3caccf5ab8931 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index 787e15ba0ca40..919e902491e23 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -430,6 +430,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-6.6/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-6.6/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..7fccd861cc --- /dev/null +++ b/queue-6.6/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 55fe113c2f8a4f637bc01c5b1d08159c15ce50ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 44de1bcd0c657..132b16a89793b 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3941,3 +3941,4 @@ module_init(nvme_fc_init_module); + module_exit(nvme_fc_exit_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 8803fa04a322a..a9b5e0cf98f01 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2390,3 +2390,4 @@ module_init(nvme_rdma_init_module); + module_exit(nvme_rdma_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index f2b171c3169ba..53bef5e120822 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2744,3 +2744,4 @@ module_init(nvme_tcp_init_module); + module_exit(nvme_tcp_cleanup_module); + + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-6.6/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-6.6/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..b0bb25b459 --- /dev/null +++ b/queue-6.6/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From 1a9c06c081989846dfc9feed4d5050f9bafc7685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 87d30aaa35f10..a9775abdc4b5a 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3518,6 +3518,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-6.6/nvme-core-fix-parameter-name-in-comment.patch b/queue-6.6/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..4a6a2e97da --- /dev/null +++ b/queue-6.6/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From 62a98690812aed1f6c36b3f9ce706d09f0f4380b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 48c46c942253c..1bab281e2f6ef 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2576,7 +2576,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-6.6/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch b/queue-6.6/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch new file mode 100644 index 0000000000..0e8922510a --- /dev/null +++ b/queue-6.6/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch @@ -0,0 +1,110 @@ +From 0fb63b4c1c804d44f0c6b45769be5f2df20538dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:08:48 +0530 +Subject: nvme-loop: do not cancel I/O and admin tagset during ctrl + reset/shutdown + +From: Nilay Shroff + +[ Upstream commit 886f35201591ded7958e16fe3750871d3ca0bcdf ] + +Cancelling the I/O and admin tagsets during nvme-loop controller reset +or shutdown is unnecessary. The subsequent destruction of the I/O and +admin queues already waits for all in-flight target operations to +complete. + +Cancelling the tagsets first also opens a race window. After a request +tag has been cancelled, a late completion from the target may still +arrive before the queues are destroyed. In that case the completion path +may access a request whose tag has already been cancelled or freed, +which can lead to a kernel crash. Please see below the kernel crash +encountered while running blktests nvme/040: + +run blktests nvme/040 at 2026-03-08 06:34:27 +loop0: detected capacity change from 0 to 2097152 +nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +nvme nvme6: creating 96 I/O queues. +nvme nvme6: new ctrl: "blktests-subsystem-1" +nvme_log_error: 1 callbacks suppressed +block nvme6n1: no usable path - requeuing I/O +nvme6c6n1: Read(0x2) @ LBA 2096384, 128 blocks, Host Aborted Command (sct 0x3 / sc 0x71) +blk_print_req_error: 1 callbacks suppressed +I/O error, dev nvme6c6n1, sector 2096384 op 0x0:(READ) flags 0x2880700 phys_seg 1 prio class 2 +block nvme6n1: no usable path - requeuing I/O +Kernel attempted to read user page (236) - exploit attempt? (uid: 0) +BUG: Kernel NULL pointer dereference on read at 0x00000236 +Faulting instruction address: 0xc000000000961274 +Oops: Kernel access of bad area, sig: 11 [#1] +LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries +Modules linked in: nvme_loop nvme_fabrics loop nvmet null_blk rpadlpar_io rpaphp xsk_diag bonding rfkill nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink pseries_rng dax_pmem vmx_crypto drm drm_panel_orientation_quirks xfs mlx5_core nvme bnx2x sd_mod nd_pmem nd_btt nvme_core sg papr_scm tls libnvdimm ibmvscsi ibmveth scsi_transport_srp nvme_keyring nvme_auth mdio hkdf pseries_wdt dm_mirror dm_region_hash dm_log dm_mod fuse [last unloaded: loop] +CPU: 25 UID: 0 PID: 0 Comm: swapper/25 Kdump: loaded Not tainted 7.0.0-rc3+ #14 PREEMPT +Hardware name: IBM,9043-MRX Power11 (architected) 0x820200 0xf000007 of:IBM,FW1120.00 (RF1120_128) hv:phyp pSeries +NIP: c000000000961274 LR: c008000009af1808 CTR: c00000000096124c +REGS: c0000007ffc0f910 TRAP: 0300 Not tainted (7.0.0-rc3+) +MSR: 8000000000009033 CR: 22222222 XER: 00000000 +CFAR: c008000009af232c DAR: 0000000000000236 DSISR: 40000000 IRQMASK: 0 +GPR00: c008000009af17fc c0000007ffc0fbb0 c000000001c78100 c0000000be05cc00 +GPR04: 0000000000000001 0000000000000000 0000000000000007 0000000000000000 +GPR08: 0000000000000000 0000000000000000 0000000000000002 c008000009af2318 +GPR12: c00000000096124c c0000007ffdab880 0000000000000000 0000000000000000 +GPR16: 0000000000000010 0000000000000000 0000000000000004 0000000000000000 +GPR20: 0000000000000001 c000000002ca2b00 0000000100043bb2 000000000000000a +GPR24: 000000000000000a 0000000000000000 0000000000000000 0000000000000000 +GPR28: c000000084021d40 c000000084021d50 c0000000be05cd60 c0000000be05cc00 +NIP [c000000000961274] blk_mq_complete_request_remote+0x28/0x2d4 +LR [c008000009af1808] nvme_loop_queue_response+0x110/0x290 [nvme_loop] +Call Trace: + 0xc00000000502c640 (unreliable) + nvme_loop_queue_response+0x104/0x290 [nvme_loop] + __nvmet_req_complete+0x80/0x498 [nvmet] + nvmet_req_complete+0x24/0xf8 [nvmet] + nvmet_bio_done+0x58/0xcc [nvmet] + bio_endio+0x250/0x390 + blk_update_request+0x2e8/0x68c + blk_mq_end_request+0x30/0x5c + lo_complete_rq+0x94/0x110 [loop] + blk_complete_reqs+0x78/0x98 + handle_softirqs+0x148/0x454 + do_softirq_own_stack+0x3c/0x50 + __irq_exit_rcu+0x18c/0x1b4 + irq_exit+0x1c/0x34 + do_IRQ+0x114/0x278 + hardware_interrupt_common_virt+0x28c/0x290 + +Since the queue teardown path already guarantees that all target-side +operations have completed, cancelling the tagsets is redundant and +unsafe. So avoid cancelling the I/O and admin tagsets during controller +reset and shutdown. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Nilay Shroff +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/loop.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index bd61a1b82c4cd..00ef4ae17038e 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -408,7 +408,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + { + if (ctrl->ctrl.queue_count > 1) { + nvme_quiesce_io_queues(&ctrl->ctrl); +- nvme_cancel_tagset(&ctrl->ctrl); + nvme_loop_destroy_io_queues(ctrl); + } + +@@ -416,7 +415,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + if (ctrl->ctrl.state == NVME_CTRL_LIVE) + nvme_disable_ctrl(&ctrl->ctrl, true); + +- nvme_cancel_admin_tagset(&ctrl->ctrl); + nvme_loop_destroy_admin_queue(ctrl); + } + +-- +2.53.0 + diff --git a/queue-6.6/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch b/queue-6.6/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch new file mode 100644 index 0000000000..ca043f069a --- /dev/null +++ b/queue-6.6/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch @@ -0,0 +1,48 @@ +From c1fbe85c00f4f1bc9fd6a127bbae0fff94b2fb84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:56:58 -0400 +Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error + path + +From: Shivam Kumar + +[ Upstream commit 4606467a75cfc16721937272ed29462a750b60c8 ] + +In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, +nvmet_req_uninit() is called unconditionally. However, if the command +arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() +had returned false and percpu_ref_tryget_live() was never executed. The +unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a +refcount underflow, leading to a WARNING in +percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and +eventually a permanent workqueue deadlock. + +Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling +nvmet_req_uninit(), matching the existing pattern in +nvmet_tcp_execute_request(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Shivam Kumar +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 5f85c4a812abc..d063ab11a32ff 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1270,7 +1270,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + queue->idx, cmd->req.cmd->common.command_id, + queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), + le32_to_cpu(cmd->exp_ddgst)); +- nvmet_req_uninit(&cmd->req); ++ if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) ++ nvmet_req_uninit(&cmd->req); + nvmet_tcp_free_cmd_buffers(cmd); + nvmet_tcp_fatal_error(queue); + ret = -EPROTO; +-- +2.53.0 + diff --git a/queue-6.6/nvmet-tcp-don-t-free-sq-on-authentication-success.patch b/queue-6.6/nvmet-tcp-don-t-free-sq-on-authentication-success.patch new file mode 100644 index 0000000000..6014341d09 --- /dev/null +++ b/queue-6.6/nvmet-tcp-don-t-free-sq-on-authentication-success.patch @@ -0,0 +1,59 @@ +From dca8adbe589f616287cbcaa72e4111e075f28fe4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 15:17:53 +1000 +Subject: nvmet-tcp: Don't free SQ on authentication success + +From: Alistair Francis + +[ Upstream commit 2e6eb6b277f593b98f151ea8eff1beb558bbea3b ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +This patch ensures we don't free the TLS key on success as we might need +it again in the future. + +Signed-off-by: Alistair Francis +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Wilfred Mallawa +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/fabrics-cmd-auth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c +index c103eba96350e..50da6a7113103 100644 +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -341,9 +341,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) + goto complete; + } + /* Final states, clear up variables */ +- nvmet_auth_sq_free(req->sq); +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { ++ nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); ++ } + + complete: + nvmet_req_complete(req, status); +@@ -514,9 +515,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) + status = nvmet_copy_to_sgl(req, 0, d, al); + kfree(d); + done: +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) +- nvmet_auth_sq_free(req->sq); +- else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { + nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); + } +-- +2.53.0 + diff --git a/queue-6.6/orangefs-validate-getxattr-response-length.patch b/queue-6.6/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..17018fa42f --- /dev/null +++ b/queue-6.6/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From 1e566654e739aab56db37c47b0d63dcaefd6b256 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index 15738379f5511..4f8bb2def5af0 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-6.6/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch b/queue-6.6/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch new file mode 100644 index 0000000000..1391858f1f --- /dev/null +++ b/queue-6.6/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch @@ -0,0 +1,78 @@ +From 30c1b5ca4fd4dbd3623888932b8300e40c2bf20e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 18:07:25 -0400 +Subject: orangefs_readahead: don't overflow the bufmap slot. + +From: Mike Marshall + +[ Upstream commit 415e507cdefc510c01de8ab6644163327ee9a5d0 ] + +generic/340 showed that this caller of wait_for_direct_io was +sometimes asking for more than a bufmap slot could hold. This splits +the calls up if needed. + +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/inode.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index dd4dc70e4aaab..7e03e40aae342 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -247,6 +247,8 @@ static void orangefs_readahead(struct readahead_control *rac) + loff_t new_start = readahead_pos(rac); + int ret; + size_t new_len = 0; ++ size_t this_size; ++ size_t remaining; + + loff_t bytes_remaining = inode->i_size - readahead_pos(rac); + loff_t pages_remaining = bytes_remaining / PAGE_SIZE; +@@ -262,17 +264,33 @@ static void orangefs_readahead(struct readahead_control *rac) + offset = readahead_pos(rac); + i_pages = &rac->mapping->i_pages; + +- iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); ++ iov_iter_xarray(&iter, ITER_DEST, i_pages, ++ offset, readahead_length(rac)); + +- /* read in the pages. */ +- if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, +- &offset, &iter, readahead_length(rac), +- inode->i_size, NULL, NULL, rac->file)) < 0) +- gossip_debug(GOSSIP_FILE_DEBUG, +- "%s: wait_for_direct_io failed. \n", __func__); +- else +- ret = 0; ++ remaining = readahead_length(rac); ++ while (remaining) { ++ if (remaining > 4194304) ++ this_size = 4194304; ++ else ++ this_size = remaining; ++ ++ /* read in the pages. */ ++ if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, ++ &offset, &iter, this_size, ++ inode->i_size, NULL, NULL, rac->file)) < 0) { ++ gossip_debug(GOSSIP_FILE_DEBUG, ++ "%s: wait_for_direct_io failed. :%d: \n", ++ __func__, ret); ++ goto cleanup; ++ } else { ++ ret = 0; ++ } ++ ++ remaining -= this_size; ++ offset += this_size; ++ } + ++cleanup: + /* clean up. */ + while ((folio = readahead_folio(rac))) { + if (!ret) +-- +2.53.0 + diff --git a/queue-6.6/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-6.6/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..e6952de2e5 --- /dev/null +++ b/queue-6.6/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From 761c6e888a44769f04c41378b9c261124bec6e13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index 4042d87d539dd..73d2144e64e8d 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -78,7 +78,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index ed645c7a4e4b4..9e6d608cc85bc 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -43,6 +43,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -74,7 +83,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -167,7 +177,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -189,7 +200,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -223,6 +235,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -287,7 +309,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 052d956d3ba1f..c976e6f7fe63e 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -72,12 +72,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-6.6/pci-avoid-flr-for-amd-npu-device.patch b/queue-6.6/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..bfb6207857 --- /dev/null +++ b/queue-6.6/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From f6b1d419f72318353b57dffe98ed5d066d4babb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 5df3a6ea66018..3409dd729c1b0 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5566,6 +5566,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * +@@ -5578,6 +5579,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + +-- +2.53.0 + diff --git a/queue-6.6/pci-prevent-assignment-to-unsupported-bridge-windows.patch b/queue-6.6/pci-prevent-assignment-to-unsupported-bridge-windows.patch new file mode 100644 index 0000000000..2a0cc3d739 --- /dev/null +++ b/queue-6.6/pci-prevent-assignment-to-unsupported-bridge-windows.patch @@ -0,0 +1,76 @@ +From 1f17a0b034218bbc65dd8fc60c5b57dfc6332ce6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:53:32 +0000 +Subject: PCI: Prevent assignment to unsupported bridge windows + +From: Ahmed Naseef + +[ Upstream commit 92427ab4378faa168d6953d0f8574b8fc1edcc14 ] + +Previously, pci_read_bridge_io() and pci_read_bridge_mmio_pref() +unconditionally set resource type flags (IORESOURCE_IO or IORESOURCE_MEM | +IORESOURCE_PREFETCH) when reading bridge window registers. For windows that +are not implemented in hardware, this may cause the allocator to assign +space for a window that doesn't exist. + +For example, the EcoNET EN7528 SoC Root Port doesn't support the +prefetchable window, but since a downstream device had a prefetchable BAR, +the allocator mistakenly assigned a prefetchable window: + + pci 0001:00:01.0: [14c3:0811] type 01 class 0x060400 PCIe Root Port + pci 0001:00:01.0: PCI bridge to [bus 01-ff] + pci 0001:00:01.0: bridge window [mem 0x28000000-0x280fffff]: assigned + pci 0001:00:01.0: bridge window [mem 0x28100000-0x282fffff pref]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28100000-0x281fffff 64bit pref]: assigned + +pci_read_bridge_windows() already detects unsupported windows by testing +register writability and sets dev->io_window/pref_window accordingly. + +Check dev->io_window/pref_window so we don't set the resource flags for +unsupported windows, which prevents the allocator from assigning space to +them. + +After this commit, the prefetchable BAR is correctly allocated from the +non-prefetchable window: + + pci 0001:00:01.0: bridge window [mem 0x28000000-0x281fffff]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28000000-0x280fffff 64bit pref]: assigned + +Suggested-by: Bjorn Helgaas +Link: https://lore.kernel.org/all/20260113210259.GA715789@bhelgaas/ +Signed-off-by: Ahmed Naseef +Signed-off-by: Caleb James DeLisle +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260312165332.569772-4-cjd@cjdns.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index d90ffbb47f0e2..6ca32f653bfda 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -349,6 +349,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; + ++ if (!dev->io_window) ++ return; ++ + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; + if (dev->io_window_1k) { +@@ -410,6 +413,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, + pci_bus_addr_t base, limit; + struct pci_bus_region region; + ++ if (!dev->pref_window) ++ return; ++ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-6.6/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..fb3bcd79f6 --- /dev/null +++ b/queue-6.6/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From f98392be9dd782ee5859ae23b60fe89839400c33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 89109e380635c..37f21cbbf4c68 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -46,6 +46,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1450,6 +1451,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-6.6/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-6.6/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..737e5d9f17 --- /dev/null +++ b/queue-6.6/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 3bff480048112adc577652dd2976dcefd457a0f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/pci/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c +index 5e6b1eb54c643..877a3d22ec0ec 100644 +--- a/drivers/pci/vgaarb.c ++++ b/drivers/pci/vgaarb.c +@@ -1168,6 +1168,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1199,7 +1200,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-6.6/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-6.6/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..e55fa04291 --- /dev/null +++ b/queue-6.6/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From 0a3eaaff95a761328e6185e61ba31a6c2c3d6111 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index fac3d97111b09..ff48ea2a7bf40 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -448,6 +448,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-6.6/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..150555f337 --- /dev/null +++ b/queue-6.6/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From 520525408c2e4bd066df5a5a885de74c8d833f55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index ba38173d3ed3c..a528f1f95ebc7 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1218,6 +1218,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-6.6/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-6.6/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..dd6e8a246b --- /dev/null +++ b/queue-6.6/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From e68007b45f97f920922538339b2c6dd780af2f6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 9e4141cffbf93..49147aa2d9e1c 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-6.6/powerpc-time-remove-redundant-preempt_disable-enable.patch b/queue-6.6/powerpc-time-remove-redundant-preempt_disable-enable.patch new file mode 100644 index 0000000000..680a6cc18b --- /dev/null +++ b/queue-6.6/powerpc-time-remove-redundant-preempt_disable-enable.patch @@ -0,0 +1,98 @@ +From 94d4130d1737b855030a091b5e2b43329d2d0b45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:13 +0530 +Subject: powerpc/time: Remove redundant preempt_disable|enable() calls from + arch_irq_work_raise() + +From: Sayali Patil + +[ Upstream commit 31467b23823ffec1f6fff407f8e3ca9af8b7491a ] + +A kernel panic is observed when handling machine check exceptions from +real mode. + + BUG: Unable to handle kernel data access on read at 0xc00000006be21300 + Oops: Kernel access of bad area, sig: 11 [#1] + MSR: 8000000000001003 CR: 88222248 XER: 00000005 + CFAR: c00000000003ffc4 DAR: c00000006be21300 DSISR: 40000000 IRQMASK: 0 + NIP [c000000000029e40] arch_irq_work_raise+0x10/0x70 + LR [c00000000003ffc8] machine_check_queue_event+0xa8/0x150 + Call Trace: + [c0000000179d3c70] [c00000000003ff64] machine_check_queue_event+0x44/0x150 + [c0000000179d3d30] [c0000000000084e0] machine_check_early_common+0x1f0/0x2c0 + +The crash occurs because arch_irq_work_raise() calls preempt_disable() +from machine check exception (MCE) handlers running in real mode. In +this context, accessing the preempt_count can fault, leading to the panic. + +The preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +was originally added by commit 0fe1ac48bef0 ("powerpc/perf_event: Fix +oops due to perf_event_do_pending call") to avoid races while raising +irq work from exception context. + +Later, commit 471ba0e686cb ("irq_work: Do not raise an IPI when +queueing work on the local CPU") added preemption protection in +irq_work_queue() path, while commit 20b876918c06 ("irq_work: Use per +cpu atomics instead of regular atomics") added equivalent +protection in irq_work_queue_on() before reaching arch_irq_work_raise(): + + irq_work_queue() / irq_work_queue_on() + -> preempt_disable() + -> __irq_work_queue_local() + -> irq_work_raise() + -> arch_irq_work_raise() + +As a result, callers other than mce_irq_work_raise() already execute +with preemption disabled, making the additional +preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +redundant. + +The arch_irq_work_raise() function executes in NMI context when called +from MCE handler. Hence we will not be preempted or scheduled out since +we are in NMI context with MSR[EE]=0. Therefore, it is safe to remove +the preempt_disable()/preempt_enable() calls from here. + +Remove it to avoid accessing preempt_count from real mode context. + +Fixes: cc15ff327569 ("powerpc/mce: Avoid using irq_work_queue() in realmode") +Suggested-by: Mahesh Salgaonkar +Acked-by: Shrikanth Hegde +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Sayali Patil +[Maddy: Fixed the commit title] +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260513081413.222490-1-sayalip@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/time.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index df20cf201f74d..dda35c404a676 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -436,6 +436,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); + + #endif /* 32 vs 64 bit */ + ++/* ++ * Must be called with preemption disabled since it updates ++ * per-CPU irq_work state and programs the local CPU decrementer. ++ */ + void arch_irq_work_raise(void) + { + /* +@@ -449,10 +453,8 @@ void arch_irq_work_raise(void) + * which could get tangled up if we're messing with the same state + * here. + */ +- preempt_disable(); + set_irq_work_pending_flag(); + set_dec(1); +- preempt_enable(); + } + + static void set_dec_or_work(u64 val) +-- +2.53.0 + diff --git a/queue-6.6/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-6.6/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..2ebf19ba7b --- /dev/null +++ b/queue-6.6/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From 8e3b825b75dd7c27c94f06e4a0df7ecaf7470ef4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 2b5843d14cbb8..0d8eea992aea2 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3005,12 +3005,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-6.6/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-6.6/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..57eb6dc7fb --- /dev/null +++ b/queue-6.6/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,78 @@ +From 33299a9d6871ce5bf229a75ae6f1564535e3e7c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index d29740be4833e..ad37c0584c23b 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -204,6 +204,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-6.6/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-6.6/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..1ba0eaf58a --- /dev/null +++ b/queue-6.6/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From dbc44629345f1b94c19abf48524638be51d1c1b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 03e5f5d533eb3..c42437565cb3d 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -26,7 +26,6 @@ + #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -78,7 +77,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -149,9 +148,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -159,6 +160,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-6.6/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch b/queue-6.6/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch new file mode 100644 index 0000000000..8a2801b0bc --- /dev/null +++ b/queue-6.6/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch @@ -0,0 +1,50 @@ +From 80dd63d1b1257e881831a518914b976faef82c67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:47:40 +0530 +Subject: rtc: ti-k3: Add support to resume from IO DDR low power mode + +From: Akashdeep Kaur + +[ Upstream commit 0e9b12ee74c57617bb362deb3c82e35fe49694b5 ] + +Restore the RTC HW context which may be lost when system enters +certain low power mode (IO+DDR mode). +Check if the RTC registers are locked which would indicate loss of +context (reset) and restore the context as needed. + +Signed-off-by: Akashdeep Kaur +Reviewed-by: Vignesh Raghavendra +Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-ti-k3.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c +index ec759d8f7023c..e801f5b9d7574 100644 +--- a/drivers/rtc/rtc-ti-k3.c ++++ b/drivers/rtc/rtc-ti-k3.c +@@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) + static int __maybe_unused ti_k3_rtc_resume(struct device *dev) + { + struct ti_k3_rtc *priv = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (k3rtc_check_unlocked(priv)) { ++ /* RTC locked implies low power mode exit where RTC loses context */ ++ ret = k3rtc_configure(dev); ++ if (ret) ++ return ret; ++ } + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); +- return 0; ++ return ret; + } + + static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); +-- +2.53.0 + diff --git a/queue-6.6/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch b/queue-6.6/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch new file mode 100644 index 0000000000..71a76c7ef1 --- /dev/null +++ b/queue-6.6/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch @@ -0,0 +1,73 @@ +From 2d8301beb7e9a87d72f7bdcad3d3e986ab1bdd5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:10:06 +0100 +Subject: s390/bpf: Do not increment tailcall count when prog is NULL + +From: Ilya Leoshkevich + +[ Upstream commit e4094d56c5592dd90aa619f9480265b0689ed3d9 ] + +Currently tail calling a non-existent prog results in tailcall count +increment. This is what the interpreter is doing, but this is clearly +wrong, so replace load-and-increment and compare-and-jump with load +and compare-and-jump, conditionally followed by increment and store. + +Reported-by: Hari Bathini +Signed-off-by: Ilya Leoshkevich +Link: https://lore.kernel.org/r/20260217161058.101346-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index 491789420d7c0..3313e8a246499 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -1515,20 +1515,21 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + jit->prg); + + /* +- * if (tail_call_cnt++ >= MAX_TAIL_CALL_CNT) ++ * if (tail_call_cnt >= MAX_TAIL_CALL_CNT) + * goto out; ++ * ++ * tail_call_cnt is read into %w0, which needs to be preserved ++ * until it's incremented and flushed. + */ + + off = jit->frame_off + + offsetof(struct prog_frame, tail_call_cnt); +- /* lhi %w0,1 */ +- EMIT4_IMM(0xa7080000, REG_W0, 1); +- /* laal %w1,%w0,off(%r15) */ +- EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); +- /* clij %w1,MAX_TAIL_CALL_CNT-1,0x2,out */ ++ /* ly %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0058, REG_W0, REG_0, REG_15, off); ++ /* clij %w0,MAX_TAIL_CALL_CNT,0xa,out */ + patch_2_clij = jit->prg; +- EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT - 1, +- 2, jit->prg); ++ EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W0, MAX_TAIL_CALL_CNT, ++ 0xa, jit->prg); + + /* + * prog = array->ptrs[index]; +@@ -1547,6 +1548,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + patch_3_brc = jit->prg; + EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); + ++ /* tail_call_cnt++; */ ++ /* ahi %w0,1 */ ++ EMIT4_IMM(0xa70a0000, REG_W0, 1); ++ /* sty %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, REG_0, REG_15, off); ++ + /* + * Restore registers before calling function + */ +-- +2.53.0 + diff --git a/queue-6.6/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch b/queue-6.6/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch new file mode 100644 index 0000000000..3c43300e72 --- /dev/null +++ b/queue-6.6/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch @@ -0,0 +1,101 @@ +From f5e083a61ffbc2ded1ecc7bf220b4289dc4364d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 19:59:29 +0800 +Subject: sched: Fix incorrect schedstats for rt and dl thread + +From: Dengjun Su + +[ Upstream commit c0e1832ba6dad7057acf3f485a87e0adccc23141 ] + +For RT and DL thread, only 'set_next_task_(rt/dl)' will call +'update_stats_wait_end_(rt/dl)' to update schedstats information. +However, during the migration process, +'update_stats_wait_start_(rt/dl)' will be called twice, which +will cause the values of wait_max and wait_sum to be incorrect. +The specific output as follows: +$ cat /proc/6046/task/6046/sched | grep wait +wait_start : 0.000000 +wait_max : 496717.080029 +wait_sum : 7921540.776553 + +A complete schedstats information update flow of migrate should be +__update_stats_wait_start() [enter queue A, stage 1] -> +__update_stats_wait_end() [leave queue A, stage 2] -> +__update_stats_wait_start() [enter queue B, stage 3] -> +__update_stats_wait_end() [start running on queue B, stage 4] + + Stage 1: prev_wait_start is 0, and in the end, wait_start records the + time of entering the queue. + Stage 2: task_on_rq_migrating(p) is true, and wait_start is updated to + the waiting time on queue A. + Stage 3: prev_wait_start is the waiting time on queue A, wait_start is + the time of entering queue B, and wait_start is expected to be greater + than prev_wait_start. Under this condition, wait_start is updated to + (the moment of entering queue B) - (the waiting time on queue A). + Stage 4: the final wait time = (time when starting to run on queue B) + - (time of entering queue B) + (waiting time on queue A) = waiting + time on queue B + waiting time on queue A. + +The current problem is that stage 2 does not call __update_stats_wait_end +to update wait_start, which causes the final computed wait time = waiting +time on queue B + the moment of entering queue A, leading to incorrect +wait_max and wait_sum. + +Add 'update_stats_wait_end_(rt/dl)' in 'update_stats_dequeue_(rt/dl)' to +update schedstats information when dequeue_task. + +Signed-off-by: Dengjun Su +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260204115959.3183567-1-dengjun.su@mediatek.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 4 ++++ + kernel/sched/rt.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 91459b664014d..d593b39b06ed2 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -1578,10 +1578,14 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, + int flags) + { + struct task_struct *p = dl_task_of(dl_se); ++ struct rq *rq = rq_of_dl_rq(dl_rq); + + if (!schedstat_enabled()) + return; + ++ if (p != rq->curr) ++ update_stats_wait_end_dl(dl_rq, dl_se); ++ + if ((flags & DEQUEUE_SLEEP)) { + unsigned int state; + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 46d2250b72359..d5582e42f5384 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1401,13 +1401,18 @@ update_stats_dequeue_rt(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, + int flags) + { + struct task_struct *p = NULL; ++ struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!schedstat_enabled()) + return; + +- if (rt_entity_is_task(rt_se)) ++ if (rt_entity_is_task(rt_se)) { + p = rt_task_of(rt_se); + ++ if (p != rq->curr) ++ update_stats_wait_end_rt(rt_rq, rt_se); ++ } ++ + if ((flags & DEQUEUE_SLEEP) && p) { + unsigned int state; + +-- +2.53.0 + diff --git a/queue-6.6/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-6.6/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..063b663009 --- /dev/null +++ b/queue-6.6/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From ab7e2d7a65bfbcf231167103e61522bce7497427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-6.6/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch b/queue-6.6/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch new file mode 100644 index 0000000000..baeaab5073 --- /dev/null +++ b/queue-6.6/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch @@ -0,0 +1,117 @@ +From 094321e58204ed66a0d2963b1d7bd4b3b9cbbb9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:03 -0800 +Subject: scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in + lpfc_sli_abort_ring() + +From: Justin Tee + +[ Upstream commit 2da10bcaa58a389ca60f8e788180e0dca00739bc ] + +When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is +cleared but the phba->txcmplq_cnt is not reset to zero. This can +sometimes result in a phba->txcmplq_cnt that never reaches zero, which +hangs the cleanup process. + +Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also +ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_sli.c | 66 +++++++++++++----------------------- + 1 file changed, 24 insertions(+), 42 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index c88e224feed8a..43698738a2c4c 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -4570,59 +4570,41 @@ void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { + LIST_HEAD(tx_completions); +- LIST_HEAD(txcmplq_completions); ++ spinlock_t *plock; /* for transmit queue access */ + struct lpfc_iocbq *iocb, *next_iocb; + int offline; + +- if (pring->ringno == LPFC_ELS_RING) { ++ if (phba->sli_rev >= LPFC_SLI_REV4) ++ plock = &pring->ring_lock; ++ else ++ plock = &phba->hbalock; ++ ++ if (pring->ringno == LPFC_ELS_RING) + lpfc_fabric_abort_hba(phba); +- } ++ + offline = pci_channel_offline(phba->pcidev); + +- /* Error everything on txq and txcmplq +- * First do the txq. +- */ +- if (phba->sli_rev >= LPFC_SLI_REV4) { +- spin_lock_irq(&pring->ring_lock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; ++ /* Cancel everything on txq */ ++ spin_lock_irq(plock); ++ list_splice_init(&pring->txq, &tx_completions); ++ pring->txq_cnt = 0; + +- if (offline) { +- list_splice_init(&pring->txcmplq, +- &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&pring->ring_lock); ++ if (offline) { ++ /* Cancel everything on txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; ++ list_splice_init(&pring->txcmplq, &tx_completions); ++ pring->txcmplq_cnt = 0; + } else { +- spin_lock_irq(&phba->hbalock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; +- +- if (offline) { +- list_splice_init(&pring->txcmplq, &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&phba->hbalock); ++ /* Issue ABTS for everything on the txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + } ++ spin_unlock_irq(plock); + +- if (offline) { +- /* Cancel all the IOCBs from the completions list */ +- lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, +- IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); +- } else { +- /* Make sure HBA is alive */ ++ if (!offline) + lpfc_issue_hb_tmo(phba); +- } ++ + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); +-- +2.53.0 + diff --git a/queue-6.6/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-6.6/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..986a208ded --- /dev/null +++ b/queue-6.6/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 3d09caf6385bf51c114545a1dbd94ff1bf8cfc69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 106bccaac4276..e3363a083ba77 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1132,6 +1132,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1142,22 +1162,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-6.6/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch b/queue-6.6/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch new file mode 100644 index 0000000000..8c6c28d349 --- /dev/null +++ b/queue-6.6/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch @@ -0,0 +1,38 @@ +From 6ca2a389839edde45e7f528499d7837ad9e69163 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 13:41:34 -0500 +Subject: scsi: ufs: core: Disable timestamp for Kioxia THGJFJT0E25BAIP + +From: Aaron Kling + +[ Upstream commit e423f1c7195645e18945fba0bd8f0a32e39286e7 ] + +Kioxia has another product that does not support the qTimestamp +attribute. + +Signed-off-by: Aaron Kling +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260403-thgjfjt0e25baip-no-timestamp-v1-1-1ddb34225133@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/core/ufshcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index f6aada5150f9c..f1fcb06764dbf 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -275,6 +275,9 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGLF2G9D8KBADG", + .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE }, ++ { .wmanufacturerid = UFS_VENDOR_TOSHIBA, ++ .model = "THGJFJT0E25BAIP", ++ .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGJFJT1E45BATP", + .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, +-- +2.53.0 + diff --git a/queue-6.6/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-6.6/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..77b4d83167 --- /dev/null +++ b/queue-6.6/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From b99d6ff95857076577c6332a50e42054fd9f3383 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index e2e4fffd87e39..047078f204542 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -1110,6 +1110,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-6.6/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-6.6/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..d1737633ed --- /dev/null +++ b/queue-6.6/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From 617991ddb52440b45a3adf81c42b558f5d776a00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index f820a09cb5c39..fc972734688ec 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -134,6 +134,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + const struct qcom_geni_device_data *dev_data; +@@ -235,7 +236,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1322,11 +1323,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) { + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series new file mode 100644 index 0000000000..f4e6fd5f66 --- /dev/null +++ b/queue-6.6/series @@ -0,0 +1,225 @@ +hid-uclogic-fix-regression-of-input-name-assignment.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch +btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-arptables-allow-xtables-nft-only-builds.patch +netfilter-xtables-allow-xtables-nft-only-builds.patch +netfilter-ebtables-allow-xtables-nft-only-builds.patch +netfilter-xtables-fix-up-kconfig-dependencies.patch +netfilter-arptables-select-netfilter_family_arp-when.patch +netfilter-make-legacy-configs-user-selectable.patch +netfilter-exclude-legacy-tables-on-preempt_rt.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-x_tables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch +test_kprobes-clear-kprobes-between-test-runs.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +net-lan966x-avoid-unregistering-netdev-on-register-f.patch +irqchip-ath79-cpu-remove-unused-function.patch +irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch +netfs-fix-overrun-check-in-netfs_extract_user_iter.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch +net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +powerpc-time-remove-redundant-preempt_disable-enable.patch +net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch +net-phy-dp83tc811-add-reading-of-abilities.patch +x86-xen-fix-xen_e820_swap_entry_with_ram.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +nvmet-tcp-don-t-free-sq-on-authentication-success.patch +nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch +blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch +io_uring-cancel-validate-opcode-for-ioring_async_can.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +wifi-mac80211-set-band-information-only-for-non-mld-.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch +wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch +ipv4-validate-ipv4_devconf-attributes-properly.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch +wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch +wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch +wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-mlx5e-xsk-increase-size-for-chunk_size-param.patch +wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch +bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch +bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +pci-avoid-flr-for-amd-npu-device.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch +drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch +drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +drm-gem-dma-set-vm_dontdump-for-mmap.patch +pci-prevent-assignment-to-unsupported-bridge-windows.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +drm-amd-display-merge-pipes-for-validate.patch +asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +iommu-amd-invalidate-irt-cache-for-dma-aliases.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch +alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-validate-outarg-offset-and-size-in-notify-store.patch +fuse-mark-dax-inode-releases-as-blocking.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-validate-getxattr-response-length.patch +orangefs_readahead-don-t-overflow-the-bufmap-slot.patch +ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +hid-logitech-hidpp-fix-race-condition-when-accessing.patch +hid-playstation-validate-num_touch_reports-in-dualsh.patch +bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +ipmi-ssif_bmc-cancel-response-timer-on-remove.patch +i3c-master-move-bus_init-error-suppression.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +thunderbolt-disable-clx-on-titan-ridge-based-devices.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +ntfs3-fix-oob-write-in-attr_wof_frame_info.patch +scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch +um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +iio-abi-fix-current_trigger-description.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch +dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch +nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +rculist-add-list_splice_rcu-for-private-lists.patch +btrfs-apply-first-key-check-for-readahead-when-possi.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch diff --git a/queue-6.6/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-6.6/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..c0a70e64c1 --- /dev/null +++ b/queue-6.6/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From 7a4b1241bda51e508c4f48d3a24e728897a4789b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index c16ed08d62af0..40e2f0d5907de 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -4814,6 +4814,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + goto free_dw; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + dw->len = len; +-- +2.53.0 + diff --git a/queue-6.6/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-6.6/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..ea5aa4ec3b --- /dev/null +++ b/queue-6.6/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From 49aee9cd8097543c5641a558cbc2a80a52353064 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 207d578547cd9..b4883c365ba33 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -375,7 +375,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-6.6/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-6.6/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..637416c3d4 --- /dev/null +++ b/queue-6.6/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From d6ced843172b5cde90eceb8dac843cde3b838d66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 965330eec80a8..d0b43d50b83ce 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-6.6/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-6.6/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..839b0b0e95 --- /dev/null +++ b/queue-6.6/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From 0aeda42fd02ad6fa40f1b944d8801e4c7bdba389 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index a6f9192b4e53c..c7a1f763e464e 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1115,7 +1115,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-6.6/test_kprobes-clear-kprobes-between-test-runs.patch b/queue-6.6/test_kprobes-clear-kprobes-between-test-runs.patch new file mode 100644 index 0000000000..0df0d5eb5a --- /dev/null +++ b/queue-6.6/test_kprobes-clear-kprobes-between-test-runs.patch @@ -0,0 +1,128 @@ +From 9f86d8dbab25c765b946910ae2baa8087cb52e06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: test_kprobes: clear kprobes between test runs + +From: Martin Kaiser + +[ Upstream commit ef5581bb30efb939cc2bf093475c6cc85258e5cd ] + +Running the kprobes sanity tests twice makes all tests fail and +eventually crashes the kernel. + +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # Totals: pass:5 fail:0 skip:0 total:5 + ok 1 kprobes_test +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # test_kprobe: EXPECTATION FAILED at lib/tests/test_kprobes.c:64 + Expected 0 == register_kprobe(&kp), but + register_kprobe(&kp) == -22 (0xffffffffffffffea) +... + Unable to handle kernel paging request ... + +The testsuite defines several kprobes and kretprobes as static variables +that are preserved across test runs. + +After register_kprobe and unregister_kprobe, a kprobe contains some +leftover data that must be cleared before the kprobe can be registered +again. The tests are setting symbol_name to define the probe location. +Address and flags must be cleared. + +The existing code clears some of the probes between subsequent tests, but +not between two test runs. The leftover data from a previous test run +makes the registrations fail in the next run. + +Move the cleanups for all kprobes into kprobes_test_init, this function +is called before each single test (including the first test of a test +run). + +Link: https://lore.kernel.org/all/20260507134615.1010905-1-martin@kaiser.cx/ + +Fixes: e44e81c5b90f ("kprobes: convert tests to kunit") +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + lib/test_kprobes.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/lib/test_kprobes.c b/lib/test_kprobes.c +index 0648f7154f5c4..cd7a452ab3032 100644 +--- a/lib/test_kprobes.c ++++ b/lib/test_kprobes.c +@@ -12,6 +12,12 @@ + + #define div_factor 3 + ++#define KP_CLEAR(_kp) \ ++do { \ ++ (_kp).addr = NULL; \ ++ (_kp).flags = 0; \ ++} while (0) ++ + static u32 rand1, preh_val, posth_val; + static u32 (*target)(u32 value); + static u32 (*recursed_target)(u32 value); +@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test) + + current_test = test; + +- /* addr and flags should be cleard for reusing kprobe. */ +- kp.addr = NULL; +- kp.flags = 0; +- + KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2)); + preh_val = 0; + posth_val = 0; +@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test) + struct kretprobe *rps[2] = {&rp, &rp2}; + + current_test = test; +- /* addr and flags should be cleard for reusing kprobe. */ +- rp.kp.addr = NULL; +- rp.kp.flags = 0; + KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2)); + + krph_val = 0; +@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test) + unsigned long myretaddr = (unsigned long)__builtin_return_address(0); + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + /* + * Run the stacktrace_driver() to record correct return address in +@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + struct kretprobe *rps[2] = {&rp3, &rp4}; + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + //KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver()); + +@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + + static int kprobes_test_init(struct kunit *test) + { ++ KP_CLEAR(kp); ++ KP_CLEAR(kp2); ++ KP_CLEAR(kp_missed); ++#ifdef CONFIG_KRETPROBES ++ KP_CLEAR(rp.kp); ++ KP_CLEAR(rp2.kp); ++#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE ++ KP_CLEAR(rp3.kp); ++ KP_CLEAR(rp4.kp); ++#endif ++#endif ++ + target = kprobe_target; + target2 = kprobe_target2; + recursed_target = kprobe_recursed_target; +-- +2.53.0 + diff --git a/queue-6.6/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch b/queue-6.6/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch new file mode 100644 index 0000000000..e0dcfa1306 --- /dev/null +++ b/queue-6.6/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch @@ -0,0 +1,53 @@ +From 9a3ef3a9595f79a117c6d752aa45f6c7da57332d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:25:57 -0800 +Subject: thunderbolt: Disable CLx on Titan Ridge-based devices with old + firmware + +From: Rene Sapiens + +[ Upstream commit 59b03d12b1f6d14d936a3ebec225f8d914dc3b70 ] + +Thunderbolt 3 devices based on Titan Ridge routers with NVM firmware +version < 0x65 have been observed to become unstable when CL states are +enabled. This can lead to link disconnect events and the device failing +to enumerate. + +Enable CLx on Titan Ridge only when the running NVM firmware version +is >= 0x65. + +Signed-off-by: Rene Sapiens +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +--- + drivers/thunderbolt/quirks.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c +index e81de9c30eac9..9f7914ac2f48c 100644 +--- a/drivers/thunderbolt/quirks.c ++++ b/drivers/thunderbolt/quirks.c +@@ -23,6 +23,9 @@ static void quirk_dp_credit_allocation(struct tb_switch *sw) + + static void quirk_clx_disable(struct tb_switch *sw) + { ++ if (tb_switch_is_titan_ridge(sw) && sw->nvm && sw->nvm->major >= 0x65) ++ return; ++ + sw->quirks |= QUIRK_NO_CLX; + tb_sw_dbg(sw, "disabling CL states\n"); + } +@@ -61,6 +64,10 @@ static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link }, + { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link }, ++ ++ /* Intel Titan Ridge CLx is unstable on early firmware versions */ ++ { 0x8086, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE, 0x0000, 0x0000, ++ quirk_clx_disable }, + /* + * Intel Goshen Ridge NVM 27 and before report wrong number of + * DP buffers. +-- +2.53.0 + diff --git a/queue-6.6/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-6.6/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..32b414f268 --- /dev/null +++ b/queue-6.6/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 138f9e2e82f005e18abe4a4e0d03cc2cc306eacc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index a5d512866a940..98261296d668d 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1639,6 +1639,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1646,7 +1649,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-6.6/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-6.6/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..854713e560 --- /dev/null +++ b/queue-6.6/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From 708ed84deb177ec564bbc394c2548085f01a84af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index 60d48d857b1c0..1dabb9e20d5cc 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1434,9 +1434,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1557,8 +1557,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-6.6/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch b/queue-6.6/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch new file mode 100644 index 0000000000..b1b5c36c50 --- /dev/null +++ b/queue-6.6/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch @@ -0,0 +1,60 @@ +From 695cfe853b0826e54d8e63b08e4ac949f8474bf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:20:42 -0700 +Subject: um: Disable GCOV_PROFILE_ALL on 32-bit UML with Clang 20/21 + +From: Kees Cook + +[ Upstream commit 6522fe5c1b007c376fc5f2de1016c99a18b0af8e ] + +Clang 20 and 21 miscompute __builtin_object_size() when -fprofile-arcs +is active on 32-bit UML targets, which passes incorrect object size +calculations for local variables through always_inline copy_to_user() +and check_copy_size(), causing spurious compile-time errors: + + include/linux/ucopysize.h:52:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small + +The regression was introduced in LLVM commit 02b8ee281947 ("[llvm] +Improve llvm.objectsize computation by computing GEP, alloca and malloc +parameters bound"), which shipped in Clang 20. It was fixed in LLVM +by commit 45b697e610fd ("[MemoryBuiltins] Consider index type size +when aggregating gep offsets"), which was backported to the LLVM 22.x +release branch. + +The bug requires 32-bit UML + GCOV_PROFILE_ALL (which uses -fprofile-arcs), +though the exact trigger depends on optimizer decisions influenced by other +enabled configs. + +Prevent the bad combination by disabling UML's ARCH_HAS_GCOV_PROFILE_ALL +on 32-bit when using Clang 20.x or 21.x. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604030531.O6FveVgn-lkp@intel.com/ +Suggested-by: Nathan Chancellor +Assisted-by: Claude:claude-opus-4-6[1m] +Signed-off-by: Kees Cook +Link: https://patch.msgid.link/20260409052038.make.995-kees@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/Kconfig | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/um/Kconfig b/arch/um/Kconfig +index b5e1793605346..f24278644bb39 100644 +--- a/arch/um/Kconfig ++++ b/arch/um/Kconfig +@@ -7,7 +7,9 @@ config UML + default y + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +- select ARCH_HAS_GCOV_PROFILE_ALL ++ # Clang 20 & 21 miscompute __builtin_object_size() under -fprofile-arcs ++ # on 32-bit, causing spurious compile-time errors in check_copy_size(). ++ select ARCH_HAS_GCOV_PROFILE_ALL if !(!64BIT && CLANG_VERSION >= 200000 && CLANG_VERSION < 220100) + select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER +-- +2.53.0 + diff --git a/queue-6.6/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-6.6/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..7c5d63b002 --- /dev/null +++ b/queue-6.6/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From 8e113f61405a75380f6c3cd8f372bc4e580f7979 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index fa88f210ecd57..fd0fde581bd08 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1648,6 +1648,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-6.6/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-6.6/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..184400e94c --- /dev/null +++ b/queue-6.6/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From 005e3d365c141828a024fca5cf512c17f80ef72b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8f47a3b87871..f8d1d1167ef4b 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -674,7 +674,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -682,11 +682,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.6/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-6.6/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..df064bef4e --- /dev/null +++ b/queue-6.6/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From 1761da5474d93c85cd75d0594804837bad43dd01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8d1d1167ef4b..a5837c0feb058 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -782,6 +782,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-6.6/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-6.6/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..954fe63f12 --- /dev/null +++ b/queue-6.6/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From 204a7d2ddb94de7f6f4be8d397158448fcb844d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index ba9e7c616e129..f8f47a3b87871 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -677,7 +677,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -708,14 +708,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-6.6/virtiofs-add-fuse-protocol-validation.patch b/queue-6.6/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..9e46762cb3 --- /dev/null +++ b/queue-6.6/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From 8436019c8e4edd70e728a0be0e580579136789e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index a6814bea0e0ad..16158028a00ae 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -564,6 +564,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -574,10 +595,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct page *page; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -633,6 +650,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-6.6/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-6.6/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..7207df2f0f --- /dev/null +++ b/queue-6.6/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From 505f07643886675a153b5b47e63b262e4ffbc7aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 68b8e458a88f6..b7ab9a79e3b44 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -2175,10 +2175,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-6.6/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch b/queue-6.6/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch new file mode 100644 index 0000000000..575435735a --- /dev/null +++ b/queue-6.6/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch @@ -0,0 +1,45 @@ +From 5923fc51f78121be368abc0c59a274c3c64eba1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:43 +0200 +Subject: wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending + +From: Emmanuel Grumbach + +[ Upstream commit 5562b3bbeede8be25092064720e4a942e9fd3e3e ] + +Otherwise we may send garbage. + +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.2d494b0f4692.I9afd0fa6b2ea5a27118144ac4e3bbbedc2089c10@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index c597492668fad..5e46f9a5a46cc 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -869,7 +869,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) + + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + { +- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; ++ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; + struct iwl_geo_tx_power_profiles_resp *resp; + u16 len; + int ret; +@@ -921,7 +921,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) + { + u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); +- union iwl_geo_tx_power_profiles_cmd cmd; ++ union iwl_geo_tx_power_profiles_cmd cmd = {}; + u16 len; + u32 n_bands; + u32 n_profiles; +-- +2.53.0 + diff --git a/queue-6.6/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch b/queue-6.6/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch new file mode 100644 index 0000000000..ad4fc05e4e --- /dev/null +++ b/queue-6.6/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch @@ -0,0 +1,53 @@ +From 2e6996e0543d592a5f32f9f86a942b871a7eb128 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:28:28 +0100 +Subject: wifi: mac80211: Remove deleted sta links in + ieee80211_ml_reconf_work() + +From: Lorenzo Bianconi + +[ Upstream commit 84674b03d8bf3a850f023a98136c27909f0a2b61 ] + +Delete stale station links announced in the reconfiguration IE +transmitted by the AP in the beacon frames. + +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260309-mac80211-reconf-remove-sta-link-v2-1-1582aac720c6@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 496f2b36a0bed..def845d33ead9 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -5749,6 +5749,7 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + container_of(work, struct ieee80211_sub_if_data, + u.mgd.ml_reconf_work.work); + u16 new_valid_links, new_active_links, new_dormant_links; ++ struct sta_info *sta; + int ret; + + sdata_lock(sdata); +@@ -5790,6 +5791,16 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + } + } + ++ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); ++ if (sta) { ++ unsigned long removed_links = sdata->u.mgd.removed_links; ++ unsigned int link_id; ++ ++ for_each_set_bit(link_id, &removed_links, ++ IEEE80211_MLD_MAX_NUM_LINKS) ++ ieee80211_sta_free_link(sta, link_id); ++ } ++ + new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links; + + ret = ieee80211_vif_set_links(sdata, new_valid_links, +-- +2.53.0 + diff --git a/queue-6.6/wifi-mac80211-set-band-information-only-for-non-mld-.patch b/queue-6.6/wifi-mac80211-set-band-information-only-for-non-mld-.patch new file mode 100644 index 0000000000..8e25af188d --- /dev/null +++ b/queue-6.6/wifi-mac80211-set-band-information-only-for-non-mld-.patch @@ -0,0 +1,78 @@ +From 62d7356c1ba093022e7a55f138021e0a1deb5358 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 15:31:25 +0530 +Subject: wifi: mac80211: set band information only for non-MLD when probing + stations using NULL frame + +From: Suraj P Kizhakkethil + +[ Upstream commit 73e7df69edb6f1271ea0fa876794761e6c73e76a ] + +Currently, when sending a NULL frame to probe a station, the band +information is derived from the chanctx_conf in the mac80211 vif's +bss_conf. However, for AP MLD, chanctx_conf is not assigned to the +vif's bss_conf; instead it is assigned on a per-link basis. As a result, +for AP MLD, sending a NULL packet to probe will trigger a warning. + +WARNING: net/mac80211/cfg.c:4635 at ieee80211_probe_client+0x1a8/0x1d8 [mac80211], CPU#2: hostapd/244 +Call trace: + ieee80211_probe_client+0x1a8/0x1d8 [mac80211] (P) + nl80211_probe_client+0xac/0x170 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + genl_rcv_msg+0x200/0x280 + netlink_rcv_skb+0x38/0xf0 + genl_rcv+0x34/0x48 + netlink_unicast+0x314/0x3a0 + netlink_sendmsg+0x150/0x390 + ____sys_sendmsg+0x1f4/0x21c + ___sys_sendmsg+0x98/0xc0 + __sys_sendmsg+0x74/0xcc + __arm64_sys_sendmsg+0x20/0x34 + invoke_syscall.constprop.0+0x4c/0xd0 + do_el0_svc+0x3c/0xd0 + el0_svc+0x28/0xc0 + el0t_64_sync_handler+0x98/0xdc + el0t_64_sync+0x154/0x158 +---[ end trace 0000000000000000 ]--- + +For NULL packets sent to probe stations, set the band information only +for non-MLD, since MLD transmissions does not rely on band. + +Signed-off-by: Suraj P Kizhakkethil +Link: https://patch.msgid.link/20260213100126.1414398-2-suraj.kizhakkethil@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/cfg.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 16270bea49a2f..da5dc22e2cf25 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4143,12 +4143,17 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, + + qos = sta->sta.wme; + +- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- ret = -EINVAL; +- goto unlock; ++ if (ieee80211_vif_is_mld(&sdata->vif)) { ++ /* MLD transmissions must not rely on the band */ ++ band = 0; ++ } else { ++ chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ ret = -EINVAL; ++ goto unlock; ++ } ++ band = chanctx_conf->def.chan->band; + } +- band = chanctx_conf->def.chan->band; + + if (qos) { + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | +-- +2.53.0 + diff --git a/queue-6.6/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch b/queue-6.6/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch new file mode 100644 index 0000000000..b2f9fa85a4 --- /dev/null +++ b/queue-6.6/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch @@ -0,0 +1,51 @@ +From c55741a441e7bdb67f473c17575d7f1b53dd20a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:17:22 +0530 +Subject: wifi: mac80211: use ap_addr for 4-address NULL frame destination + +From: Tamizh Chelvam Raja + +[ Upstream commit 594be50a3f0a6b7389f40f7acbf0dd731beb5204 ] + +Currently ieee80211_send_4addr_nullfunc() uses deflink.u.mgd.bssid +for addr1 and addr3 fields. In MLO configurations, deflink.u.mgd.bssid +represents link 0's BSSID and is not updated when link 0 is not an +assoc link. This causes 4-address NULL frames to be sent to the +wrong address, preventing WDS AP_VLAN interface creation on the peer AP. + +To fix this use sdata->vif.cfg.ap_addr instead, which contains the AP's MLD +address populated during authentication/association and remains +valid regardless of which links are active. + +This ensures 4-address NULL frames reach the correct AP, allowing +proper WDS operation over MLO connections. + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Tamizh Chelvam Raja +Link: https://patch.msgid.link/20260326164723.553927-3-tamizh.raja@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index def845d33ead9..285ab6b906de4 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -1664,9 +1664,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; +- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch b/queue-6.6/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch new file mode 100644 index 0000000000..2447a740f0 --- /dev/null +++ b/queue-6.6/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch @@ -0,0 +1,54 @@ +From f94a4140c5b5f2bf225372e01335723491a1d42f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:10:32 -0800 +Subject: wifi: mt76: fix list corruption in mt76_wcid_cleanup + +From: Zac Bowling + +[ Upstream commit 34163942195410372fb138bea806c9b34e2f5257 ] + +mt76_wcid_cleanup() was not removing wcid entries from sta_poll_list +before mt76_reset_device() reinitializes the master list. This leaves +stale pointers in wcid->poll_list, causing list corruption when +mt76_wcid_add_poll() later checks list_empty() and tries to add the +entry back. + +The fix adds proper cleanup of poll_list in mt76_wcid_cleanup(), +matching how tx_list is already handled. This is similar to what +mt7996_mac_sta_deinit_link() already does correctly. + +Fixes list corruption warnings like: + list_add corruption. prev->next should be next (ffffffff...) + +Signed-off-by: Zac Bowling +Link: https://patch.msgid.link/20260120201043.38225-3-zac@zacbowling.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index bf4541e76ba22..aaf1f8c3923b5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1514,6 +1514,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) + + idr_destroy(&wcid->pktid); + ++ /* Remove from sta_poll_list to prevent list corruption after reset. ++ * Without this, mt76_reset_device() reinitializes sta_poll_list but ++ * leaves wcid->poll_list with stale pointers, causing list corruption ++ * when mt76_wcid_add_poll() checks list_empty(). ++ */ ++ spin_lock_bh(&dev->sta_poll_lock); ++ if (!list_empty(&wcid->poll_list)) ++ list_del_init(&wcid->poll_list); ++ spin_unlock_bh(&dev->sta_poll_lock); ++ + spin_lock_bh(&phy->tx_lock); + + if (!list_empty(&wcid->tx_list)) +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-6.6/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..51b7d7e98b --- /dev/null +++ b/queue-6.6/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From cadb83f73595fa7a67e3c95dd1b8c23b8f480388 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index e9c5e85ec07c2..35ab3d2ac4c72 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -525,6 +525,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch b/queue-6.6/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch new file mode 100644 index 0000000000..2886a33b10 --- /dev/null +++ b/queue-6.6/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch @@ -0,0 +1,49 @@ +From 0768e73076d5783db0caaef1cd74e6af8d9105b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:22:31 +0800 +Subject: wifi: mt76: mt792x: Fix a potential deadlock in high-load situations + +From: Leon Yen + +[ Upstream commit bb2f07819d063a58756186cac6465341956ac0a4 ] + +A deadlock may occur between two works, ps_work and mac_work, if their work +functions run simultaneously as they attempt to cancel each other by +calling cancel_delayed_work_sync(). + +mt792x_mac_work() -> ... -> cancel_delayed_work_sync(&pm->ps_work); +mt792x_pm_power_save_work() -> cancel_delayed_work_sync(&mphy->mac_work); + +In high-load situations, they are queued but may not have chance to be +executed until the CPUs are released. Once the CPUs are available, there +is a high possibility that the ps_work function and mac_work function will +be executed simultaneously, resulting in a possible deadlock. + +This patch replaces cancel_delayed_work_sync() with cancel_delayed_work() +in ps_work to eliminate the deadlock and make the code easier to maintain. + +Signed-off-by: Leon Yen +Tested-by: Chia-Lin Kao (AceLan) +Link: https://patch.msgid.link/20251215122231.3180648-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +index 5d1f8229fdc1d..bbde4ceb7621f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +@@ -376,7 +376,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) + } + + if (!mt792x_mcu_fw_pmctrl(dev)) { +- cancel_delayed_work_sync(&mphy->mac_work); ++ cancel_delayed_work(&mphy->mac_work); + return; + } + out: +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch b/queue-6.6/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch new file mode 100644 index 0000000000..263ba93035 --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch @@ -0,0 +1,66 @@ +From c082ceb9e1e3206dcc53993be4ef56ee715e5efb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:24:00 +0000 +Subject: wifi: mt76: mt7996: reset device after MCU message timeout + +From: Chad Monroe + +[ Upstream commit d2b860454ea2df8f336e9b859da7ffb27f43444d ] + +Trigger a full reset after MCU message timeout. + +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/6e05ed063f3763ad3457633c56b60a728a49a6f0.1765203753.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 +++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 9270a68e6a38d..a0f24d192c0b1 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2005,6 +2005,11 @@ void mt7996_reset(struct mt7996_dev *dev) + return; + } + ++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { ++ set_bit(MT76_MCU_RESET, &dev->mphy.state); ++ wake_up(&dev->mt76.mcu.wait); ++ } ++ + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 9f8c312b64d75..d9547bb74e11f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -180,6 +180,7 @@ static int + mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) + { ++ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_mcu_rxd *rxd; + struct mt7996_mcu_uni_event *event; + int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); +@@ -188,6 +189,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + if (!skb) { + dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", + cmd, seq); ++ ++ if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { ++ dev->recovery.restart = true; ++ wake_up(&dev->mt76.mcu.wait); ++ queue_work(dev->mt76.wq, &dev->reset_work); ++ wake_up(&dev->reset_wait); ++ } ++ + return -ETIMEDOUT; + } + +-- +2.53.0 + diff --git a/queue-6.6/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-6.6/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..49a2b6da75 --- /dev/null +++ b/queue-6.6/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From 6660d54d233ee43608d5458130c66f7274f334a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index d7ad5329e525d..a48b1a4639871 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -421,7 +437,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index 10a465686439e..d6a9510f76e59 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-6.6/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-6.6/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..7d66d1a065 --- /dev/null +++ b/queue-6.6/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From d3310e98e5eed9e127b16d25ae6c5ed453ec8243 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index f63900b6621d9..36015ba11705d 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -411,7 +411,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + vif = si->vif; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-6.6/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch b/queue-6.6/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch new file mode 100644 index 0000000000..8c4d961e2e --- /dev/null +++ b/queue-6.6/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch @@ -0,0 +1,78 @@ +From cfd4bc19c4398ec37e4cac0727b3eca66e89e434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:21:55 +0000 +Subject: wifi: rtw89: retry efuse physical map dump on transient failure + +From: Christian Hewitt + +[ Upstream commit d92f6ad6483e6d430c8273eeb7be97ce85244bd5 ] + +On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse +physical map dump intermittently fails with -EBUSY during probe. +The failure occurs in rtw89_dump_physical_efuse_map_ddv() where +read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY +bit after 1 second. + +The root cause is a timing race during boot: the WiFi driver's +chip initialization (firmware download via PCIe) overlaps with +Bluetooth firmware download to the same combo chip via USB. This +can leave the efuse controller temporarily unavailable when the +WiFi driver attempts to read the efuse map. + +The firmware download path retries up to 5 times, but the efuse +read that follows has no similar logic. Address this by adding +retry loop logic (also up to 5 attempts) around physical efuse +map dump. + +Signed-off-by: Christian Hewitt +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260317112155.1939569-1-christianshewitt@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/efuse.c | 23 ++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c +index 2aaf4d013e464..12c0181bde7f4 100644 +--- a/drivers/net/wireless/realtek/rtw89/efuse.c ++++ b/drivers/net/wireless/realtek/rtw89/efuse.c +@@ -157,8 +157,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + +-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, +- u32 dump_addr, u32 dump_size, bool dav) ++static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) + { + int ret; + +@@ -180,6 +180,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + ++static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) ++{ ++ int retry; ++ int ret; ++ ++ for (retry = 0; retry < 5; retry++) { ++ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr, ++ dump_size, dav); ++ if (!ret) ++ return 0; ++ ++ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n", ++ dav, retry); ++ } ++ ++ return ret; ++} ++ + #define invalid_efuse_header(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) + #define invalid_efuse_content(word_en, i) \ +-- +2.53.0 + diff --git a/queue-6.6/x86-xen-fix-xen_e820_swap_entry_with_ram.patch b/queue-6.6/x86-xen-fix-xen_e820_swap_entry_with_ram.patch new file mode 100644 index 0000000000..7506bdc34c --- /dev/null +++ b/queue-6.6/x86-xen-fix-xen_e820_swap_entry_with_ram.patch @@ -0,0 +1,39 @@ +From 883ee543ebf35a793607f8d5c36d0a1a52dcad94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 12:24:17 +0200 +Subject: x86/xen: Fix xen_e820_swap_entry_with_ram() + +From: Juergen Gross + +[ Upstream commit 28e03f78e69cf6628b81f24777799778528a84c1 ] + +When swapping a not page-aligned E820 map entry with RAM, the start +address of the modified entry is calculated wrong (the offset into the +page is subtracted instead of being added to the page address). + +Fixes: be35d91c8880 ("xen: tolerate ACPI NVS memory overlapping with Xen allocated memory") +Reported-by: Jan Beulich +Reviewed-by: Jan Beulich +Signed-off-by: Juergen Gross +Message-ID: <20260505102417.208138-1-jgross@suse.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index ec3ffb94807d3..3d5236fa54dd6 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -656,7 +656,7 @@ static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry) + /* Fill new entry (keep size and page offset). */ + entry->type = swap_entry->type; + entry->addr = entry_end - swap_size + +- swap_addr - swap_entry->addr; ++ swap_entry->addr - swap_addr; + entry->size = swap_entry->size; + + /* Convert old entry to RAM, align to pages. */ +-- +2.53.0 + diff --git a/queue-7.0/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch b/queue-7.0/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch new file mode 100644 index 0000000000..b84a05a0c7 --- /dev/null +++ b/queue-7.0/9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch @@ -0,0 +1,117 @@ +From 4f47dad245d5ceb1427827c684a320a04fa51693 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 23:30:22 +0800 +Subject: 9p/trans_xen: make cleanup idempotent after dataring alloc errors + +From: Yufan Chen + +[ Upstream commit 72cb9ee4f6d80962df17c9763b14e62e28fd85a2 ] + +xen_9pfs_front_alloc_dataring() tears down resources on failure but +leaves ring fields stale. If xen_9pfs_front_init() later jumps to the +common error path, xen_9pfs_front_free() may touch the same resources +again, causing duplicate/invalid gnttab_end_foreign_access() calls and +potentially dereferencing a freed intf pointer. + +Initialize dataring sentinels before allocation, gate teardown on those +sentinels, and clear ref/intf/data/irq immediately after each release. + +This keeps cleanup idempotent for partially initialized rings and +prevents repeated teardown during init failure handling. + +Signed-off-by: Yufan Chen +Reviewed-by: Stefano Stabellini +Message-ID: <20260324153023.86853-2-ericterminal@gmail.com> +Signed-off-by: Dominique Martinet +Signed-off-by: Sasha Levin +--- + net/9p/trans_xen.c | 51 +++++++++++++++++++++++++++++++++------------- + 1 file changed, 37 insertions(+), 14 deletions(-) + +diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c +index 47af5a10e9212..85b9ebfaa17a6 100644 +--- a/net/9p/trans_xen.c ++++ b/net/9p/trans_xen.c +@@ -283,25 +283,33 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv) + + cancel_work_sync(&ring->work); + +- if (!priv->rings[i].intf) ++ if (!ring->intf) + break; +- if (priv->rings[i].irq > 0) +- unbind_from_irqhandler(priv->rings[i].irq, ring); +- if (priv->rings[i].data.in) { +- for (j = 0; +- j < (1 << priv->rings[i].intf->ring_order); ++ if (ring->irq >= 0) { ++ unbind_from_irqhandler(ring->irq, ring); ++ ring->irq = -1; ++ } ++ if (ring->data.in) { ++ for (j = 0; j < (1 << ring->intf->ring_order); + j++) { + grant_ref_t ref; + +- ref = priv->rings[i].intf->ref[j]; ++ ref = ring->intf->ref[j]; + gnttab_end_foreign_access(ref, NULL); ++ ring->intf->ref[j] = INVALID_GRANT_REF; + } +- free_pages_exact(priv->rings[i].data.in, +- 1UL << (priv->rings[i].intf->ring_order + +- XEN_PAGE_SHIFT)); ++ free_pages_exact(ring->data.in, ++ 1UL << (ring->intf->ring_order + ++ XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; + } +- gnttab_end_foreign_access(priv->rings[i].ref, NULL); +- free_page((unsigned long)priv->rings[i].intf); ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } + kfree(priv->rings); + } +@@ -334,6 +342,12 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + int ret = -ENOMEM; + void *bytes = NULL; + ++ ring->intf = NULL; ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ ring->ref = INVALID_GRANT_REF; ++ ring->irq = -1; ++ + init_waitqueue_head(&ring->wq); + spin_lock_init(&ring->lock); + INIT_WORK(&ring->work, p9_xen_response); +@@ -379,9 +393,18 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev, + for (i--; i >= 0; i--) + gnttab_end_foreign_access(ring->intf->ref[i], NULL); + free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT)); ++ ring->data.in = NULL; ++ ring->data.out = NULL; ++ } ++ if (ring->ref != INVALID_GRANT_REF) { ++ gnttab_end_foreign_access(ring->ref, NULL); ++ ring->ref = INVALID_GRANT_REF; ++ } ++ if (ring->intf) { ++ free_page((unsigned long)ring->intf); ++ ring->intf = NULL; + } +- gnttab_end_foreign_access(ring->ref, NULL); +- free_page((unsigned long)ring->intf); ++ ring->irq = -1; + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch b/queue-7.0/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch new file mode 100644 index 0000000000..00da9599a7 --- /dev/null +++ b/queue-7.0/accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch @@ -0,0 +1,78 @@ +From f56dfad066cc49d222a6b2dbf9b4cd0135b36bc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 12:39:01 -0700 +Subject: accel/qaic: Add overflow check to remap_pfn_range during mmap + +From: Zack McKevitt + +[ Upstream commit aa16b2bc0f02709919e2435f531406531e5bcc69 ] + +The call to remap_pfn_range in qaic_gem_object_mmap is susceptible to +(re)mapping beyond the VMA if the BO is too large. This can cause use +after free issues when munmap() unmaps only the VMA region and not the +additional mappings. To prevent this, check the remaining size of the +VMA before remapping and truncate the remapped length if sg->length is +too large. + +Reported-by: Lukas Maar +Fixes: ff13be830333 ("accel/qaic: Add datapath") +Reviewed-by: Karol Wachowski +Signed-off-by: Zack McKevitt +Reviewed-by: Jeff Hugo +[jhugo: fix braces from checkpatch --strict] +Signed-off-by: Jeff Hugo +Link: https://patch.msgid.link/20260430193858.1178641-1-zachary.mckevitt@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/accel/qaic/qaic_data.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c +index 95300c2f7d8af..1e4c579d27256 100644 +--- a/drivers/accel/qaic/qaic_data.c ++++ b/drivers/accel/qaic/qaic_data.c +@@ -606,8 +606,11 @@ static const struct vm_operations_struct drm_vm_ops = { + static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) + { + struct qaic_bo *bo = to_qaic_bo(obj); ++ unsigned long remap_start; + unsigned long offset = 0; ++ unsigned long remap_end; + struct scatterlist *sg; ++ unsigned long length; + int ret = 0; + + if (drm_gem_is_imported(obj)) +@@ -615,11 +618,27 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc + + for (sg = bo->sgt->sgl; sg; sg = sg_next(sg)) { + if (sg_page(sg)) { ++ /* if sg is too large for the VMA, so truncate it to fit */ ++ if (check_add_overflow(vma->vm_start, offset, &remap_start)) ++ return -EINVAL; ++ if (check_add_overflow(remap_start, sg->length, &remap_end)) ++ return -EINVAL; ++ ++ if (remap_end > vma->vm_end) { ++ if (check_sub_overflow(vma->vm_end, remap_start, &length)) ++ return -EINVAL; ++ } else { ++ length = sg->length; ++ } ++ ++ if (length == 0) ++ goto out; ++ + ret = remap_pfn_range(vma, vma->vm_start + offset, page_to_pfn(sg_page(sg)), +- sg->length, vma->vm_page_prot); ++ length, vma->vm_page_prot); + if (ret) + goto out; +- offset += sg->length; ++ offset += length; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/acpi-processor-idle-add-missing-bounds-check-in-flat.patch b/queue-7.0/acpi-processor-idle-add-missing-bounds-check-in-flat.patch new file mode 100644 index 0000000000..22333655cf --- /dev/null +++ b/queue-7.0/acpi-processor-idle-add-missing-bounds-check-in-flat.patch @@ -0,0 +1,47 @@ +From a884778bfbcc4d6786c2e9842452f185e226efc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 21:38:31 +0000 +Subject: ACPI: processor: idle: Add missing bounds check in + flatten_lpi_states() + +From: Jingkai Tan + +[ Upstream commit 638a95168fd53a911201681cd5e55c7965b20733 ] + +The inner loop in flatten_lpi_states() that combines composite LPI +states can increment flat_state_cnt multiple times within the loop. + +The condition that guards this (checks bounds against ACPI_PROCESSOR +_MAX_POWER) occurs at the top of the outer loop. flat_state_cnt might +exceed ACPI_PROCESSOR_MAX_POWER if it is incremented multiple times +within the inner loop between outer loop iterations. + +Add a bounds check after the increment inside the inner loop so that +it breaks out when flat_state_cnt reaches ACPI_PROCESSOR_MAX_POWER. +The existing check in the outer loop will then handle the warning. + +Signed-off-by: Jingkai Tan +Reviewed-by: Sudeep Holla +Link: https://patch.msgid.link/20260305213831.53985-1-contact@jingk.ai +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index f6c72e3a2be1b..d4753420ae0b7 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1068,6 +1068,8 @@ static unsigned int flatten_lpi_states(struct acpi_processor *pr, + stash_composite_state(curr_level, flpi); + flat_state_cnt++; + flpi++; ++ if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) ++ break; + } + } + } +-- +2.53.0 + diff --git a/queue-7.0/acpi-processor-idle-fix-null-pointer-dereference-in-.patch b/queue-7.0/acpi-processor-idle-fix-null-pointer-dereference-in-.patch new file mode 100644 index 0000000000..eaf3ab19e1 --- /dev/null +++ b/queue-7.0/acpi-processor-idle-fix-null-pointer-dereference-in-.patch @@ -0,0 +1,50 @@ +From 128fc92bd1c6ed71d996315b9463ffdbc4a90d4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:02:53 +0800 +Subject: ACPI: processor: idle: Fix NULL pointer dereference in hotplug path + +From: Huisong Li + +[ Upstream commit 47e6a863a88034be102bde11197f2ca1bc18cbaf ] + +A cpuidle_device might fail to register during boot, but the system can +continue to run. In such cases, acpi_processor_hotplug() can trigger +a NULL pointer dereference when accessing the per-cpu acpi_cpuidle_device. + +So add NULL pointer check for the per-cpu acpi_cpuidle_device in +acpi_processor_hotplug. + +Signed-off-by: Huisong Li +Link: https://patch.msgid.link/20260403090253.998322-1-lihuisong@huawei.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/processor_idle.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index d4753420ae0b7..74ea25091923f 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1275,16 +1275,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) + + int acpi_processor_hotplug(struct acpi_processor *pr) + { ++ struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); + int ret = 0; +- struct cpuidle_device *dev; + + if (disabled_by_idle_boot_param()) + return 0; + +- if (!pr->flags.power_setup_done) ++ if (!pr->flags.power_setup_done || !dev) + return -ENODEV; + +- dev = per_cpu(acpi_cpuidle_device, pr->id); + cpuidle_pause_and_lock(); + cpuidle_disable_device(dev); + ret = acpi_processor_get_power_info(pr); +-- +2.53.0 + diff --git a/queue-7.0/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch b/queue-7.0/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch new file mode 100644 index 0000000000..49ca2429bf --- /dev/null +++ b/queue-7.0/affs-bound-hash_pos-before-table-lookup-in-affs_read.patch @@ -0,0 +1,38 @@ +From 87ed14dc35f94452a7a22d06d7c144822df8be1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:29:43 +0900 +Subject: affs: bound hash_pos before table lookup in affs_readdir + +From: Hyungjung Joo + +[ Upstream commit 6fa253b38b9b293a0de2a361de400557ca7666ca ] + +affs_readdir() decodes ctx->pos into hash_pos and chain_pos and then +dereferences AFFS_HEAD(dir_bh)->table[hash_pos] before validating +that hash_pos is within the runtime table bound. Treat out-of-range +positions as end-of-directory before the first table lookup. + +Signed-off-by: Hyungjung Joo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/affs/dir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/affs/dir.c b/fs/affs/dir.c +index 5c8d83387a394..075c18c4ccde6 100644 +--- a/fs/affs/dir.c ++++ b/fs/affs/dir.c +@@ -119,6 +119,8 @@ affs_readdir(struct file *file, struct dir_context *ctx) + pr_debug("readdir() left off=%d\n", ino); + goto inside; + } ++ if (hash_pos >= AFFS_SB(sb)->s_hashsize) ++ goto done; + + ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); + for (i = 0; ino && i < chain_pos; i++) { +-- +2.53.0 + diff --git a/queue-7.0/afs-fix-the-locking-used-by-afs_get_link.patch b/queue-7.0/afs-fix-the-locking-used-by-afs_get_link.patch new file mode 100644 index 0000000000..301f8cc15f --- /dev/null +++ b/queue-7.0/afs-fix-the-locking-used-by-afs_get_link.patch @@ -0,0 +1,815 @@ +From 890247f05b98f92a56364bd89959d89af89b3dd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:34:01 +0100 +Subject: afs: Fix the locking used by afs_get_link() + +From: David Howells + +[ Upstream commit c0410adf3da6db46f3513411fcf95e63c2f1d1ad ] + +The afs filesystem in the kernel doesn't do locking correctly for symbolic +links. There are a number of problems: + + (1) It doesn't do any locking around afs_read_single() to prevent races + between multiple ->get_link() calls, thereby allowing the possibility + of leaks. + + (2) It doesn't use RCU barriering when accessing the buffer pointers + during RCU pathwalk. + + (3) It can race with another thread updating the contents of the symlink + if a third party updated it on the server. + +Fix this by the following means: + + (0) Move symlink handling into its own file as this makes it more + complicated. + + (1) Take the validate_lock around afs_read_single() to prevent races + between multiple ->get_link() calls. + + (2) Keep a separate copy of the symlink contents with an rcu_head. This + is always going to be a lot smaller than a page, so it can be + kmalloc'd and save quite a bit of memory. It also needs a refcount + for non-RCU pathwalk. + + (3) Split the symlink read and write-to-cache routines in afs from those + for directories. + + (4) Discard the I/O buffer as soon as the write-to-cache completes as this + is a full page (plus a folio_queue). + + (5) If there's no cache, discard the I/O buffer immediately after reading + and copying if there is no cache. + +Fixes: eae9e78951bb ("afs: Use netfslib for symlinks, allowing them to be cached") +Fixes: 6698c02d64b2 ("afs: Locally initialise the contents of a new symlink on creation") +Closes: https://sashiko.dev/#/patchset/20260326104544.509518-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-25-dhowells@redhat.com +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/afs/Makefile | 1 + + fs/afs/dir.c | 68 +++++------ + fs/afs/fsclient.c | 4 +- + fs/afs/inode.c | 96 +-------------- + fs/afs/internal.h | 34 ++++-- + fs/afs/symlink.c | 278 ++++++++++++++++++++++++++++++++++++++++++++ + fs/afs/validation.c | 14 ++- + fs/afs/yfsclient.c | 4 +- + 8 files changed, 357 insertions(+), 142 deletions(-) + create mode 100644 fs/afs/symlink.c + +diff --git a/fs/afs/Makefile b/fs/afs/Makefile +index b49b8fe682f39..0d8f1982d596c 100644 +--- a/fs/afs/Makefile ++++ b/fs/afs/Makefile +@@ -30,6 +30,7 @@ kafs-y := \ + server.o \ + server_list.o \ + super.o \ ++ symlink.o \ + validation.o \ + vlclient.o \ + vl_alias.o \ +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index 068a892d39c4e..99ad0058694c9 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -44,6 +44,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, + static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir, + struct dentry *old_dentry, struct inode *new_dir, + struct dentry *new_dentry, unsigned int flags); ++static int afs_dir_writepages(struct address_space *mapping, ++ struct writeback_control *wbc); + + const struct file_operations afs_dir_file_operations = { + .open = afs_dir_open, +@@ -68,7 +70,7 @@ const struct inode_operations afs_dir_inode_operations = { + }; + + const struct address_space_operations afs_dir_aops = { +- .writepages = afs_single_writepages, ++ .writepages = afs_dir_writepages, + }; + + const struct dentry_operations afs_fs_dentry_operations = { +@@ -233,22 +235,13 @@ static ssize_t afs_do_read_single(struct afs_vnode *dvnode, struct file *file) + struct iov_iter iter; + ssize_t ret; + loff_t i_size; +- bool is_dir = (S_ISDIR(dvnode->netfs.inode.i_mode) && +- !test_bit(AFS_VNODE_MOUNTPOINT, &dvnode->flags)); + + i_size = i_size_read(&dvnode->netfs.inode); +- if (is_dir) { +- if (i_size < AFS_DIR_BLOCK_SIZE) +- return afs_bad(dvnode, afs_file_error_dir_small); +- if (i_size > AFS_DIR_BLOCK_SIZE * 1024) { +- trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); +- return -EFBIG; +- } +- } else { +- if (i_size > AFSPATHMAX) { +- trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); +- return -EFBIG; +- } ++ if (i_size < AFS_DIR_BLOCK_SIZE) ++ return afs_bad(dvnode, afs_file_error_dir_small); ++ if (i_size > AFS_DIR_BLOCK_SIZE * 1024) { ++ trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); ++ return -EFBIG; + } + + /* Expand the storage. TODO: Shrink the storage too. */ +@@ -277,24 +270,18 @@ static ssize_t afs_do_read_single(struct afs_vnode *dvnode, struct file *file) + * buffer. + */ + ret = -ESTALE; +- } else if (is_dir) { ++ } else { + int ret2 = afs_dir_check(dvnode); + + if (ret2 < 0) + ret = ret2; +- } else if (i_size < folioq_folio_size(dvnode->directory, 0)) { +- /* NUL-terminate a symlink. */ +- char *symlink = kmap_local_folio(folioq_folio(dvnode->directory, 0), 0); +- +- symlink[i_size] = 0; +- kunmap_local(symlink); + } + } + + return ret; + } + +-ssize_t afs_read_single(struct afs_vnode *dvnode, struct file *file) ++static ssize_t afs_read_single(struct afs_vnode *dvnode, struct file *file) + { + ssize_t ret; + +@@ -1763,13 +1750,20 @@ static int afs_link(struct dentry *from, struct inode *dir, + return ret; + } + ++static void afs_symlink_put(struct afs_operation *op) ++{ ++ kfree(op->create.symlink); ++ op->create.symlink = NULL; ++ afs_create_put(op); ++} ++ + static const struct afs_operation_ops afs_symlink_operation = { + .issue_afs_rpc = afs_fs_symlink, + .issue_yfs_rpc = yfs_fs_symlink, + .success = afs_create_success, + .aborted = afs_check_for_remote_deletion, + .edit_dir = afs_create_edit_dir, +- .put = afs_create_put, ++ .put = afs_symlink_put, + }; + + /* +@@ -1779,7 +1773,9 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, const char *content) + { + struct afs_operation *op; ++ struct afs_symlink *symlink; + struct afs_vnode *dvnode = AFS_FS_I(dir); ++ size_t clen = strlen(content); + int ret; + + _enter("{%llx:%llu},{%pd},%s", +@@ -1791,12 +1787,20 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, + goto error; + + ret = -EINVAL; +- if (strlen(content) >= AFSPATHMAX) ++ if (clen >= AFSPATHMAX) ++ goto error; ++ ++ ret = -ENOMEM; ++ symlink = kmalloc_flex(struct afs_symlink, content, clen + 1, GFP_KERNEL); ++ if (!symlink) + goto error; ++ refcount_set(&symlink->ref, 1); ++ memcpy(symlink->content, content, clen + 1); + + op = afs_alloc_operation(NULL, dvnode->volume); + if (IS_ERR(op)) { + ret = PTR_ERR(op); ++ kfree(symlink); + goto error; + } + +@@ -1808,7 +1812,7 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, + op->dentry = dentry; + op->ops = &afs_symlink_operation; + op->create.reason = afs_edit_dir_for_symlink; +- op->create.symlink = content; ++ op->create.symlink = symlink; + op->mtime = current_time(dir); + ret = afs_do_sync_operation(op); + afs_dir_unuse_cookie(dvnode, ret); +@@ -2192,15 +2196,13 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir, + } + + /* +- * Write the file contents to the cache as a single blob. ++ * Write the directory contents to the cache as a single blob. + */ +-int afs_single_writepages(struct address_space *mapping, +- struct writeback_control *wbc) ++static int afs_dir_writepages(struct address_space *mapping, ++ struct writeback_control *wbc) + { + struct afs_vnode *dvnode = AFS_FS_I(mapping->host); + struct iov_iter iter; +- bool is_dir = (S_ISDIR(dvnode->netfs.inode.i_mode) && +- !test_bit(AFS_VNODE_MOUNTPOINT, &dvnode->flags)); + int ret = 0; + + /* Need to lock to prevent the folio queue and folios from being thrown +@@ -2215,9 +2217,7 @@ int afs_single_writepages(struct address_space *mapping, + down_read(&dvnode->validate_lock); + } + +- if (is_dir ? +- test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) : +- atomic64_read(&dvnode->cb_expires_at) != AFS_NO_CB_PROMISE) { ++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { + iov_iter_folio_queue(&iter, ITER_SOURCE, dvnode->directory, 0, 0, + i_size_read(&dvnode->netfs.inode)); + ret = netfs_writeback_single(mapping, wbc, &iter); +diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c +index 95494d5f2b8a9..a2ffd60889f89 100644 +--- a/fs/afs/fsclient.c ++++ b/fs/afs/fsclient.c +@@ -886,7 +886,7 @@ void afs_fs_symlink(struct afs_operation *op) + namesz = name->len; + padsz = (4 - (namesz & 3)) & 3; + +- c_namesz = strlen(op->create.symlink); ++ c_namesz = strlen(op->create.symlink->content); + c_padsz = (4 - (c_namesz & 3)) & 3; + + reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); +@@ -910,7 +910,7 @@ void afs_fs_symlink(struct afs_operation *op) + bp = (void *) bp + padsz; + } + *bp++ = htonl(c_namesz); +- memcpy(bp, op->create.symlink, c_namesz); ++ memcpy(bp, op->create.symlink->content, c_namesz); + bp = (void *) bp + c_namesz; + if (c_padsz > 0) { + memset(bp, 0, c_padsz); +diff --git a/fs/afs/inode.c b/fs/afs/inode.c +index df95b39ed308e..de72256f00db5 100644 +--- a/fs/afs/inode.c ++++ b/fs/afs/inode.c +@@ -25,96 +25,6 @@ + #include "internal.h" + #include "afs_fs.h" + +-void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op) +-{ +- size_t size = strlen(op->create.symlink) + 1; +- size_t dsize = 0; +- char *p; +- +- if (netfs_alloc_folioq_buffer(NULL, &vnode->directory, &dsize, size, +- mapping_gfp_mask(vnode->netfs.inode.i_mapping)) < 0) +- return; +- +- vnode->directory_size = dsize; +- p = kmap_local_folio(folioq_folio(vnode->directory, 0), 0); +- memcpy(p, op->create.symlink, size); +- kunmap_local(p); +- set_bit(AFS_VNODE_DIR_READ, &vnode->flags); +- netfs_single_mark_inode_dirty(&vnode->netfs.inode); +-} +- +-static void afs_put_link(void *arg) +-{ +- struct folio *folio = virt_to_folio(arg); +- +- kunmap_local(arg); +- folio_put(folio); +-} +- +-const char *afs_get_link(struct dentry *dentry, struct inode *inode, +- struct delayed_call *callback) +-{ +- struct afs_vnode *vnode = AFS_FS_I(inode); +- struct folio *folio; +- char *content; +- ssize_t ret; +- +- if (!dentry) { +- /* RCU pathwalk. */ +- if (!test_bit(AFS_VNODE_DIR_READ, &vnode->flags) || !afs_check_validity(vnode)) +- return ERR_PTR(-ECHILD); +- goto good; +- } +- +- if (test_bit(AFS_VNODE_DIR_READ, &vnode->flags)) +- goto fetch; +- +- ret = afs_validate(vnode, NULL); +- if (ret < 0) +- return ERR_PTR(ret); +- +- if (!test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && +- test_bit(AFS_VNODE_DIR_READ, &vnode->flags)) +- goto good; +- +-fetch: +- ret = afs_read_single(vnode, NULL); +- if (ret < 0) +- return ERR_PTR(ret); +- set_bit(AFS_VNODE_DIR_READ, &vnode->flags); +- +-good: +- folio = folioq_folio(vnode->directory, 0); +- folio_get(folio); +- content = kmap_local_folio(folio, 0); +- set_delayed_call(callback, afs_put_link, content); +- return content; +-} +- +-int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen) +-{ +- DEFINE_DELAYED_CALL(done); +- const char *content; +- int len; +- +- content = afs_get_link(dentry, d_inode(dentry), &done); +- if (IS_ERR(content)) { +- do_delayed_call(&done); +- return PTR_ERR(content); +- } +- +- len = umin(strlen(content), buflen); +- if (copy_to_user(buffer, content, len)) +- len = -EFAULT; +- do_delayed_call(&done); +- return len; +-} +- +-static const struct inode_operations afs_symlink_inode_operations = { +- .get_link = afs_get_link, +- .readlink = afs_readlink, +-}; +- + static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode) + { + static unsigned long once_only; +@@ -214,7 +124,7 @@ static int afs_inode_init_from_status(struct afs_operation *op, + inode->i_mode = S_IFLNK | status->mode; + inode->i_op = &afs_symlink_inode_operations; + } +- inode->i_mapping->a_ops = &afs_dir_aops; ++ inode->i_mapping->a_ops = &afs_symlink_aops; + inode_nohighmem(inode); + mapping_set_release_always(inode->i_mapping); + break; +@@ -769,12 +679,14 @@ void afs_evict_inode(struct inode *inode) + .range_end = LLONG_MAX, + }; + +- afs_single_writepages(inode->i_mapping, &wbc); ++ inode->i_mapping->a_ops->writepages(inode->i_mapping, &wbc); + } + + netfs_wait_for_outstanding_io(inode); + truncate_inode_pages_final(&inode->i_data); + netfs_free_folioq_buffer(vnode->directory); ++ if (vnode->symlink) ++ afs_evict_symlink(vnode); + + afs_set_cache_aux(vnode, &aux); + netfs_clear_inode_writeback(inode, &aux); +diff --git a/fs/afs/internal.h b/fs/afs/internal.h +index fb0449d024ff2..dc89c3c602032 100644 +--- a/fs/afs/internal.h ++++ b/fs/afs/internal.h +@@ -711,6 +711,7 @@ struct afs_vnode { + #define AFS_VNODE_DIR_READ 11 /* Set if we've read a dir's contents */ + + struct folio_queue *directory; /* Directory contents */ ++ struct afs_symlink __rcu *symlink; /* Symlink content */ + struct list_head wb_keys; /* List of keys available for writeback */ + struct list_head pending_locks; /* locks waiting to be granted */ + struct list_head granted_locks; /* locks granted on this file */ +@@ -777,6 +778,15 @@ struct afs_permits { + struct afs_permit permits[] __counted_by(nr_permits); /* List of permits sorted by key pointer */ + }; + ++/* ++ * Copy of symlink content for normal use. ++ */ ++struct afs_symlink { ++ struct rcu_head rcu; ++ refcount_t ref; ++ char content[]; ++}; ++ + /* + * Error prioritisation and accumulation. + */ +@@ -888,7 +898,7 @@ struct afs_operation { + struct { + int reason; /* enum afs_edit_dir_reason */ + mode_t mode; +- const char *symlink; ++ struct afs_symlink *symlink; + } create; + struct { + bool need_rehash; +@@ -1099,13 +1109,10 @@ extern const struct inode_operations afs_dir_inode_operations; + extern const struct address_space_operations afs_dir_aops; + extern const struct dentry_operations afs_fs_dentry_operations; + +-ssize_t afs_read_single(struct afs_vnode *dvnode, struct file *file); + ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file) + __acquires(&dvnode->validate_lock); + extern void afs_d_release(struct dentry *); + extern void afs_check_for_remote_deletion(struct afs_operation *); +-int afs_single_writepages(struct address_space *mapping, +- struct writeback_control *wbc); + + /* + * dir_edit.c +@@ -1248,10 +1255,6 @@ extern void afs_fs_probe_cleanup(struct afs_net *); + */ + extern const struct afs_operation_ops afs_fetch_status_operation; + +-void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op); +-const char *afs_get_link(struct dentry *dentry, struct inode *inode, +- struct delayed_call *callback); +-int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen); + extern void afs_vnode_commit_status(struct afs_operation *, struct afs_vnode_param *); + extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *); + extern int afs_ilookup5_test_by_fid(struct inode *, void *); +@@ -1601,6 +1604,21 @@ void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server + extern int __init afs_fs_init(void); + extern void afs_fs_exit(void); + ++/* ++ * symlink.c ++ */ ++extern const struct inode_operations afs_symlink_inode_operations; ++extern const struct address_space_operations afs_symlink_aops; ++ ++void afs_invalidate_symlink(struct afs_vnode *vnode); ++void afs_evict_symlink(struct afs_vnode *vnode); ++void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op); ++const char *afs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *callback); ++int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen); ++int afs_symlink_writepages(struct address_space *mapping, ++ struct writeback_control *wbc); ++ + /* + * validation.c + */ +diff --git a/fs/afs/symlink.c b/fs/afs/symlink.c +new file mode 100644 +index 0000000000000..ed5868369f372 +--- /dev/null ++++ b/fs/afs/symlink.c +@@ -0,0 +1,278 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* AFS filesystem symbolic link handling ++ * ++ * Copyright (C) 2026 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static void afs_put_symlink(struct afs_symlink *symlink) ++{ ++ if (refcount_dec_and_test(&symlink->ref)) ++ kfree_rcu(symlink, rcu); ++} ++ ++static void afs_replace_symlink(struct afs_vnode *vnode, struct afs_symlink *symlink) ++{ ++ struct afs_symlink *old; ++ ++ old = rcu_replace_pointer(vnode->symlink, symlink, ++ lockdep_is_held(&vnode->validate_lock)); ++ if (old) ++ afs_put_symlink(old); ++} ++ ++/* ++ * In the event that a third-party update of a symlink occurs, dispose of the ++ * copy of the old contents. Called under ->validate_lock. ++ */ ++void afs_invalidate_symlink(struct afs_vnode *vnode) ++{ ++ afs_replace_symlink(vnode, NULL); ++} ++ ++/* ++ * Dispose of a symlink copy during inode deletion. ++ */ ++void afs_evict_symlink(struct afs_vnode *vnode) ++{ ++ struct afs_symlink *old; ++ ++ old = rcu_replace_pointer(vnode->symlink, NULL, true); ++ if (old) ++ afs_put_symlink(old); ++ ++} ++ ++/* ++ * Set up a locally created symlink inode for immediate write to the cache. ++ */ ++void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op) ++{ ++ struct afs_symlink *symlink = op->create.symlink; ++ size_t dsize = 0; ++ size_t size = strlen(symlink->content) + 1; ++ char *p; ++ ++ rcu_assign_pointer(vnode->symlink, symlink); ++ op->create.symlink = NULL; ++ ++ if (!fscache_cookie_enabled(netfs_i_cookie(&vnode->netfs))) ++ return; ++ ++ if (netfs_alloc_folioq_buffer(NULL, &vnode->directory, &dsize, size, ++ mapping_gfp_mask(vnode->netfs.inode.i_mapping)) < 0) ++ return; ++ ++ vnode->directory_size = dsize; ++ p = kmap_local_folio(folioq_folio(vnode->directory, 0), 0); ++ memcpy(p, symlink->content, size); ++ kunmap_local(p); ++ netfs_single_mark_inode_dirty(&vnode->netfs.inode); ++} ++ ++/* ++ * Read a symlink in a single download. ++ */ ++static ssize_t afs_do_read_symlink(struct afs_vnode *vnode) ++{ ++ struct afs_symlink *symlink; ++ struct iov_iter iter; ++ ssize_t ret; ++ loff_t i_size; ++ ++ i_size = i_size_read(&vnode->netfs.inode); ++ if (i_size > PAGE_SIZE - 1) { ++ trace_afs_file_error(vnode, -EFBIG, afs_file_error_dir_big); ++ return -EFBIG; ++ } ++ ++ if (!vnode->directory) { ++ size_t cur_size = 0; ++ ++ ret = netfs_alloc_folioq_buffer(NULL, ++ &vnode->directory, &cur_size, PAGE_SIZE, ++ mapping_gfp_mask(vnode->netfs.inode.i_mapping)); ++ vnode->directory_size = PAGE_SIZE - 1; ++ if (ret < 0) ++ return ret; ++ } ++ ++ iov_iter_folio_queue(&iter, ITER_DEST, vnode->directory, 0, 0, PAGE_SIZE); ++ ++ /* AFS requires us to perform the read of a symlink as a single unit to ++ * avoid issues with the content being changed between reads. ++ */ ++ ret = netfs_read_single(&vnode->netfs.inode, NULL, &iter); ++ if (ret >= 0) { ++ i_size = ret; ++ if (i_size > PAGE_SIZE - 1) { ++ trace_afs_file_error(vnode, -EFBIG, afs_file_error_dir_big); ++ return -EFBIG; ++ } ++ vnode->directory_size = i_size; ++ ++ /* Copy the symlink. */ ++ symlink = kmalloc_flex(struct afs_symlink, content, i_size + 1, ++ GFP_KERNEL); ++ if (!symlink) ++ return -ENOMEM; ++ ++ refcount_set(&symlink->ref, 1); ++ symlink->content[i_size] = 0; ++ ++ const char *s = kmap_local_folio(folioq_folio(vnode->directory, 0), 0); ++ ++ memcpy(symlink->content, s, i_size); ++ kunmap_local(s); ++ ++ afs_replace_symlink(vnode, symlink); ++ } ++ ++ if (!fscache_cookie_enabled(netfs_i_cookie(&vnode->netfs))) { ++ netfs_free_folioq_buffer(vnode->directory); ++ vnode->directory = NULL; ++ vnode->directory_size = 0; ++ } ++ ++ return ret; ++} ++ ++static ssize_t afs_read_symlink(struct afs_vnode *vnode) ++{ ++ ssize_t ret; ++ ++ fscache_use_cookie(afs_vnode_cache(vnode), false); ++ ret = afs_do_read_symlink(vnode); ++ fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL); ++ return ret; ++} ++ ++static void afs_put_link(void *arg) ++{ ++ afs_put_symlink(arg); ++} ++ ++const char *afs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *callback) ++{ ++ struct afs_symlink *symlink; ++ struct afs_vnode *vnode = AFS_FS_I(inode); ++ ssize_t ret; ++ ++ if (!dentry) { ++ /* RCU pathwalk. */ ++ symlink = rcu_dereference(vnode->symlink); ++ if (!symlink || !afs_check_validity(vnode)) ++ return ERR_PTR(-ECHILD); ++ set_delayed_call(callback, NULL, NULL); ++ return symlink->content; ++ } ++ ++ if (vnode->symlink) { ++ ret = afs_validate(vnode, NULL); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ down_read(&vnode->validate_lock); ++ if (vnode->symlink) ++ goto good; ++ up_read(&vnode->validate_lock); ++ } ++ ++ if (down_write_killable(&vnode->validate_lock) < 0) ++ return ERR_PTR(-ERESTARTSYS); ++ if (!vnode->symlink) { ++ ret = afs_read_symlink(vnode); ++ if (ret < 0) { ++ up_write(&vnode->validate_lock); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ downgrade_write(&vnode->validate_lock); ++ ++good: ++ symlink = rcu_dereference_protected(vnode->symlink, ++ lockdep_is_held(&vnode->validate_lock)); ++ refcount_inc(&symlink->ref); ++ up_read(&vnode->validate_lock); ++ ++ set_delayed_call(callback, afs_put_link, symlink); ++ return symlink->content; ++} ++ ++int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen) ++{ ++ DEFINE_DELAYED_CALL(done); ++ const char *content; ++ int len; ++ ++ content = afs_get_link(dentry, d_inode(dentry), &done); ++ if (IS_ERR(content)) { ++ do_delayed_call(&done); ++ return PTR_ERR(content); ++ } ++ ++ len = umin(strlen(content), buflen); ++ if (copy_to_user(buffer, content, len)) ++ len = -EFAULT; ++ do_delayed_call(&done); ++ return len; ++} ++ ++/* ++ * Write the symlink contents to the cache as a single blob. We then throw ++ * away the page we used to receive it. ++ */ ++int afs_symlink_writepages(struct address_space *mapping, ++ struct writeback_control *wbc) ++{ ++ struct afs_vnode *vnode = AFS_FS_I(mapping->host); ++ struct iov_iter iter; ++ int ret = 0; ++ ++ if (!down_read_trylock(&vnode->validate_lock)) { ++ if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* The VFS will have undirtied the inode. */ ++ netfs_single_mark_inode_dirty(&vnode->netfs.inode); ++ return 0; ++ } ++ down_read(&vnode->validate_lock); ++ } ++ ++ if (vnode->directory && ++ atomic64_read(&vnode->cb_expires_at) != AFS_NO_CB_PROMISE) { ++ iov_iter_folio_queue(&iter, ITER_SOURCE, vnode->directory, 0, 0, ++ i_size_read(&vnode->netfs.inode)); ++ ret = netfs_writeback_single(mapping, wbc, &iter); ++ } ++ ++ if (ret == 0) { ++ mutex_lock(&vnode->netfs.wb_lock); ++ netfs_free_folioq_buffer(vnode->directory); ++ vnode->directory = NULL; ++ vnode->directory_size = 0; ++ mutex_unlock(&vnode->netfs.wb_lock); ++ } else if (ret == 1) { ++ ret = 0; /* Skipped write due to lock conflict. */ ++ } ++ ++ up_read(&vnode->validate_lock); ++ return ret; ++} ++ ++const struct inode_operations afs_symlink_inode_operations = { ++ .get_link = afs_get_link, ++ .readlink = afs_readlink, ++}; ++ ++const struct address_space_operations afs_symlink_aops = { ++ .writepages = afs_symlink_writepages, ++}; +diff --git a/fs/afs/validation.c b/fs/afs/validation.c +index 0ba8336c90250..e997563af658b 100644 +--- a/fs/afs/validation.c ++++ b/fs/afs/validation.c +@@ -465,11 +465,17 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) + vnode->cb_ro_snapshot = cb_ro_snapshot; + vnode->cb_scrub = cb_scrub; + +- /* if the vnode's data version number changed then its contents are +- * different */ ++ /* If the vnode's data version number changed then its contents are ++ * different. Note that afs_apply_status() doesn't set ZAP_DATA on ++ * directories. ++ */ + zap |= test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); +- if (zap) +- afs_zap_data(vnode); ++ if (zap) { ++ if (S_ISREG(vnode->netfs.inode.i_mode)) ++ afs_zap_data(vnode); ++ else if (S_ISLNK(vnode->netfs.inode.i_mode)) ++ afs_invalidate_symlink(vnode); ++ } + up_write(&vnode->validate_lock); + _leave(" = 0"); + return 0; +diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c +index 24fb562ebd33a..d941179730a98 100644 +--- a/fs/afs/yfsclient.c ++++ b/fs/afs/yfsclient.c +@@ -960,7 +960,7 @@ void yfs_fs_symlink(struct afs_operation *op) + + _enter(""); + +- contents_sz = strlen(op->create.symlink); ++ contents_sz = strlen(op->create.symlink->content); + call = afs_alloc_flat_call(op->net, &yfs_RXYFSSymlink, + sizeof(__be32) + + sizeof(struct yfs_xdr_RPCFlags) + +@@ -981,7 +981,7 @@ void yfs_fs_symlink(struct afs_operation *op) + bp = xdr_encode_u32(bp, 0); /* RPC flags */ + bp = xdr_encode_YFSFid(bp, &dvp->fid); + bp = xdr_encode_name(bp, name); +- bp = xdr_encode_string(bp, op->create.symlink, contents_sz); ++ bp = xdr_encode_string(bp, op->create.symlink->content, contents_sz); + bp = xdr_encode_YFSStoreStatus(bp, &mode, &op->mtime); + yfs_check_req(call, bp); + +-- +2.53.0 + diff --git a/queue-7.0/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch b/queue-7.0/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..c3223a90df --- /dev/null +++ b/queue-7.0/alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,40 @@ +From 669410b19f489b79baabb8246d74adf47856f09b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 09:47:36 +0800 +Subject: ALSA: aoa/onyx: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit e5d5aef802a5f41283084f7d443ef4fd4b65d86d ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260403014736.33014-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/onyx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c +index 04961c456d2c5..da0eebf5dfbc2 100644 +--- a/sound/aoa/codecs/onyx.c ++++ b/sound/aoa/codecs/onyx.c +@@ -980,10 +980,12 @@ static int onyx_i2c_probe(struct i2c_client *client) + onyx->codec.node = of_node_get(node); + + if (aoa_codec_register(&onyx->codec)) { +- goto fail; ++ goto fail_put; + } + printk(KERN_DEBUG PFX "created and attached onyx instance\n"); + return 0; ++ fail_put: ++ of_node_put(onyx->codec.node); + fail: + kfree(onyx); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-7.0/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch b/queue-7.0/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch new file mode 100644 index 0000000000..7985a48794 --- /dev/null +++ b/queue-7.0/alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch @@ -0,0 +1,34 @@ +From c6ea9ce7ac31e2cb1afc2d64669a7b45da68cbb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 10:36:04 +0800 +Subject: ALSA: aoa/tas: Fix OF node leak on probe failure + +From: wangdicheng + +[ Upstream commit 1558905669e4da922fbaa7cf6507eb14779bffbd ] + +Add missing of_node_put() in the error path. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260402023604.54682-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/aoa/codecs/tas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c +index 13da2b159ad0d..25214d3da65d1 100644 +--- a/sound/aoa/codecs/tas.c ++++ b/sound/aoa/codecs/tas.c +@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client) + return 0; + fail: + mutex_destroy(&tas->mtx); ++ of_node_put(tas->codec.node); + kfree(tas); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-7.0/alsa-asihpi-detect-truncated-control-names.patch b/queue-7.0/alsa-asihpi-detect-truncated-control-names.patch new file mode 100644 index 0000000000..d756d64fbe --- /dev/null +++ b/queue-7.0/alsa-asihpi-detect-truncated-control-names.patch @@ -0,0 +1,93 @@ +From c0af7eb6638abc51ada369317248dfc741b01065 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 18:28:08 +0800 +Subject: ALSA: asihpi: detect truncated control names + +From: Pengpeng Hou + +[ Upstream commit 18d4969e22cc3ff738257e1d7738aafc65a6d2d2 ] + +asihpi_ctl_init() builds mixer control names in the fixed 44-byte +hpi_ctl->name buffer with sprintf(). + +This is not only a defensive cleanup. The current in-tree name tables and +format strings can already exceed 44 bytes. For example, + + "Bitstream 0 Internal 0 Monitor Playback Volume" + +is 46 characters before the trailing NUL, so the current sprintf() call +writes past the end of hpi_ctl->name. + +The generated control name is used as the ALSA control element key, so +blindly truncating it is not sufficient. Switch the formatting to +snprintf() and emit an error if truncation happens, showing the +truncated name while still keeping the write bounded to hpi_ctl->name. + +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260328102808.33969-1-pengpeng@iscas.ac.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/asihpi/asihpi.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c +index 3a64d05628030..b1c7ed7f1604e 100644 +--- a/sound/pci/asihpi/asihpi.c ++++ b/sound/pci/asihpi/asihpi.c +@@ -1362,6 +1362,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + struct hpi_control *hpi_ctl, + char *name) + { ++ int len; + char *dir; + memset(snd_control, 0, sizeof(*snd_control)); + snd_control->name = hpi_ctl->name; +@@ -1384,23 +1385,30 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, + dir = "Playback "; /* PCM Playback source, or output node */ + + if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) +- sprintf(hpi_ctl->name, "%s %d %s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + else if (hpi_ctl->dst_node_type) { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_dst_names[hpi_ctl->dst_node_type], +- hpi_ctl->dst_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_dst_names[hpi_ctl->dst_node_type], ++ hpi_ctl->dst_node_index, ++ dir, name); + } else { +- sprintf(hpi_ctl->name, "%s %d %s%s", +- asihpi_src_names[hpi_ctl->src_node_type], +- hpi_ctl->src_node_index, +- dir, name); ++ len = snprintf(hpi_ctl->name, sizeof(hpi_ctl->name), ++ "%s %d %s%s", ++ asihpi_src_names[hpi_ctl->src_node_type], ++ hpi_ctl->src_node_index, ++ dir, name); + } ++ ++ if (len >= sizeof(hpi_ctl->name)) ++ pr_err("asihpi: truncated control name: %s\n", ++ hpi_ctl->name); + } + + /*------------------------------------------------------------ +-- +2.53.0 + diff --git a/queue-7.0/alsa-compress-refuse-to-update-timestamps-for-unconf.patch b/queue-7.0/alsa-compress-refuse-to-update-timestamps-for-unconf.patch new file mode 100644 index 0000000000..8eb30dc3c9 --- /dev/null +++ b/queue-7.0/alsa-compress-refuse-to-update-timestamps-for-unconf.patch @@ -0,0 +1,48 @@ +From f9e55c2f07aa077ccec3f2843df4b606af72f5fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:57:34 +0100 +Subject: ALSA: compress: Refuse to update timestamps for unconfigured streams + +From: Mark Brown + +[ Upstream commit cf6c18cf83e48986ac40a053d09d3c33624135f6 ] + +There are a number of mechanisms, including the userspace accessible +timestamp and buffer availability ioctl()s, which allow us to trigger +a timestamp update on a stream before it has been configured. Since +drivers might rely on stream configuration for reporting of pcm_io_frames, +including potentially doing a division by the number of channels, and +these operations are not meaningful for an unconfigured stream reject +attempts to read timestamps before any configuration is done. + +Signed-off-by: Mark Brown +Acked-by: Vinod Koul +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260401-alsa-unconfigured-tstamp-v1-1-694c2cb5f71d@kernel.org +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 5a0308eb4e31d..db9f516df8422 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -185,6 +185,14 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, + { + if (!stream->ops->pointer) + return -ENOTSUPP; ++ ++ switch (stream->runtime->state) { ++ case SNDRV_PCM_STATE_OPEN: ++ return -EBADFD; ++ default: ++ break; ++ } ++ + stream->ops->pointer(stream, tstamp); + pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset, + tstamp->copied_total); +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch b/queue-7.0/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch new file mode 100644 index 0000000000..3d8735d9c6 --- /dev/null +++ b/queue-7.0/alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch @@ -0,0 +1,51 @@ +From 8c56f6975b0681810d1e5d2ce7216ca40507d910 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:17:56 +0200 +Subject: ALSA: hda: Avoid WARN_ON() for HDMI chmap slot checks + +From: Takashi Iwai + +[ Upstream commit 077c593dacf7ee33511468e4f29417d795cf07a4 ] + +At parsing the channel mapping for HDMI, the current code may spew +WARN_ON() unnecessarily for the case where only invalid (zero) channel +maps are given from the hardware. Drop WARN_ON() and reorganize the +code a bit for avoiding the hdmi_slot over the array size. + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221390 +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428061800.80527-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/core/hdmi_chmap.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/core/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c +index 7b276047f85a7..c897fc443467c 100644 +--- a/sound/hda/core/hdmi_chmap.c ++++ b/sound/hda/core/hdmi_chmap.c +@@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ +- for (i = 0; i < ch_alloc->channels; i++) { +- while (!WARN_ON(hdmi_slot >= 8) && +- !ch_alloc->speakers[7 - hdmi_slot]) +- hdmi_slot++; /* skip zero slots */ ++ for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { ++ while (!ch_alloc->speakers[7 - hdmi_slot]) { ++ /* skip zero slots */ ++ if (++hdmi_slot >= 8) ++ goto out; ++ } + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } ++ out: + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-ca0132-disable-auto-detect-on-manual-output.patch b/queue-7.0/alsa-hda-ca0132-disable-auto-detect-on-manual-output.patch new file mode 100644 index 0000000000..d07e06f53b --- /dev/null +++ b/queue-7.0/alsa-hda-ca0132-disable-auto-detect-on-manual-output.patch @@ -0,0 +1,118 @@ +From 512f7f63a5e1a855e3c27433f4d861935bceaa80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 09:58:41 -0500 +Subject: ALSA: hda/ca0132: Disable auto-detect on manual output select + +From: Matt DeVillier + +[ Upstream commit 6fd9f6e870ea285f05102e8e00e6a7f4495a9a02 ] + +Commit 778031e1658d ("ALSA: hda/ca0132: Set HP/Speaker +auto-detect default from headphone pin verb") enables HP/Speaker +auto-detect by default when the headphone pin supports presence detect. + +With auto-detect enabled, ca0132_select_out() and ca0132_alt_select_out() +choose the output from jack presence instead of the manual HP/Speaker +selection. This means selecting speaker output while headphones are +plugged in updates the control state, but audio still routes to the +headphones. + +Treat an explicit manual output selection as a request to leave +auto-detect mode. Clear the HP/Speaker auto-detect switch before applying +the manual selection, and notify userspace so the auto-detect control +state is updated in mixers. Do this for both the normal HP/Speaker +Playback Switch and the alternate Output Select control used by desktop +cards. + +This keeps auto-detect enabled by default for devices with jack presence +detection, while preserving the expected behavior that a manual output +choice takes effect immediately. + +Fixes: 778031e1658d ("ALSA: hda/ca0132: Set HP/Speaker auto-detect default from headphone pin verb") +Signed-off-by: Matt DeVillier +Link: https://lore.kernel.org/CAFTm+6AfeXKf=b2frG4xC5yC4jjM9TkD6c8+dOWWFw6BDjDESw@mail.gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/ca0132.c | 44 +++++++++++++++++++++++++++------------ + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c +index a0677d7da8e2d..b4e10957ac6db 100644 +--- a/sound/hda/codecs/ca0132.c ++++ b/sound/hda/codecs/ca0132.c +@@ -5508,6 +5508,30 @@ static int zxr_headphone_gain_set(struct hda_codec *codec, long val) + return 0; + } + ++/* ++ * Manual output selection (HP/Speaker Playback Switch or alt Output Select) ++ * is meaningful only when HP/Speaker auto-detect is disabled, since the ++ * select_out path always prefers jack presence when auto-detect is on. When ++ * the user explicitly chooses an output, turn auto-detect off so the manual ++ * choice actually takes effect, and notify userspace so the auto-detect ++ * control reflects the new state. ++ */ ++static void ca0132_disable_hp_auto_detect(struct hda_codec *codec) ++{ ++ struct ca0132_spec *spec = codec->spec; ++ struct snd_kcontrol *kctl; ++ ++ if (!spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]) ++ return; ++ ++ spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID] = 0; ++ kctl = snd_hda_find_mixer_ctl(codec, ++ "HP/Speaker Auto Detect Playback Switch"); ++ if (kctl) ++ snd_ctl_notify(codec->card, SNDRV_CTL_EVENT_MASK_VALUE, ++ &kctl->id); ++} ++ + static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -5520,14 +5544,11 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, + int auto_jack; + + if (nid == VNID_HP_SEL) { +- auto_jack = +- spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; +- if (!auto_jack) { +- if (ca0132_use_alt_functions(spec)) +- ca0132_alt_select_out(codec); +- else +- ca0132_select_out(codec); +- } ++ ca0132_disable_hp_auto_detect(codec); ++ if (ca0132_use_alt_functions(spec)) ++ ca0132_alt_select_out(codec); ++ else ++ ca0132_select_out(codec); + return 1; + } + +@@ -5988,7 +6009,6 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol, + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = NUM_OF_OUTPUTS; +- unsigned int auto_jack; + + if (sel >= items) + return 0; +@@ -5998,10 +6018,8 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol, + + spec->out_enum_val = sel; + +- auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; +- +- if (!auto_jack) +- ca0132_alt_select_out(codec); ++ ca0132_disable_hp_auto_detect(codec); ++ ca0132_alt_select_out(codec); + + return 1; + } +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch b/queue-7.0/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch new file mode 100644 index 0000000000..e7293769be --- /dev/null +++ b/queue-7.0/alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch @@ -0,0 +1,62 @@ +From 175d7300663d058a0dab9f0540eef631a05181a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:25:15 +0000 +Subject: ALSA: hda: cs35l41: Fix boost type for HP Dragonfly 13.5 inch G4 + +From: Leonard Lausen + +[ Upstream commit 6389dbd5c4a2d819ec342f89bd65883ab021278e ] + +The HP Dragonfly 13.5 inch G4 (SSID 103C8B63) has _DSD properties in +ACPI firmware with valid reset-gpios and cs-gpios for the four CS35L41 +amplifiers on SPI. + +However, the _DSD specifies cirrus,boost-type as Internal (0), while +the hardware requires External Boost. With Internal Boost configured, +the amplifiers trigger "Amp short error" when audio is played at +moderate-to-high volume, eventually shutting down entirely. + +Add a configuration table entry to override the boost type to +External, similar to the existing workaround for 103C89C6. All GPIO +indices are set to -1 since the _DSD provides valid reset-gpios and +cs-gpios. + +Confirmed on BIOS V90 01.11.00 (January 2026), the latest available. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=219520 +Originally-by: Nicholas Wang +Signed-off-by: Leonard Lausen +Link: https://patch.msgid.link/db84dcf91bc8dbd217b35572b177d967655ff903@lausen.nl +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l41_hda_property.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c +index 16d5ea77192f0..732ae534db360 100644 +--- a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c ++++ b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c +@@ -55,6 +55,11 @@ static const struct cs35l41_config cs35l41_config_table[] = { + { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 }, ++/* ++ * Device 103C8B63 has _DSD with valid reset-gpios and cs-gpios, however the ++ * boost type is incorrectly set to Internal. Override to External Boost. ++ */ ++ { "103C8B63", 4, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, -1, -1, -1, 0, 0, 0 }, + { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, +@@ -475,6 +480,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { + { "CSC3551", "103C8A30", generic_dsd_config }, + { "CSC3551", "103C8A31", generic_dsd_config }, + { "CSC3551", "103C8A6E", generic_dsd_config }, ++ { "CSC3551", "103C8B63", generic_dsd_config }, + { "CSC3551", "103C8BB3", generic_dsd_config }, + { "CSC3551", "103C8BB4", generic_dsd_config }, + { "CSC3551", "103C8BDD", generic_dsd_config }, +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch b/queue-7.0/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch new file mode 100644 index 0000000000..9fa7160b29 --- /dev/null +++ b/queue-7.0/alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch @@ -0,0 +1,48 @@ +From fafd0e20edd6ab5bb5c31d8cb09ac1c19980da2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:12:38 +0800 +Subject: ALSA: hda: cs35l41: Put ACPI device on missing physical node + +From: Shuhao Fu + +[ Upstream commit fca7401fe37f7abc6e54147ea560f37279231137 ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers must balance it with acpi_dev_put(). + +cs35l41_hda_read_acpi() stores the returned ACPI device in +cs35l41->dacpi. That reference is normally released by the later +probe cleanup or the remove path, but the NULL-check on +physdev exits before either of those paths can run. + +Drop the lookup reference before returning -ENODEV. + +Fixes: c34b04cc6178 ("ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_hda_read_acpi()") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428081238.GA1659932@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l41_hda.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c +index b64890006bb70..acfccc848f82d 100644 +--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c +@@ -1896,8 +1896,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i + + cs35l41->dacpi = adev; + physdev = get_device(acpi_get_first_physical_node(adev)); +- if (!physdev) ++ if (!physdev) { ++ acpi_dev_put(adev); + return -ENODEV; ++ } + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch b/queue-7.0/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch new file mode 100644 index 0000000000..1e5015488c --- /dev/null +++ b/queue-7.0/alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch @@ -0,0 +1,44 @@ +From 1b37284a9106a3c421fe6168365790319dd774e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:01:39 +0800 +Subject: ALSA: hda: cs35l56: Put ACPI device after setting companion + +From: Shuhao Fu + +[ Upstream commit aa2fbece1b07954ef26488c800d126a36a8ab93e ] + +acpi_dev_get_first_match_dev() returns a refcounted ACPI device and +callers are expected to balance it with acpi_dev_put(). + +When no companion is already attached, cs35l56_hda_read_acpi() looks +up an ACPI device and sets it with ACPI_COMPANION_SET(), but leaves +the lookup reference held. + +ACPI_COMPANION_SET() does not take ownership of that reference, so +drop it with acpi_dev_put() after attaching the companion. + +Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") +Signed-off-by: Shuhao Fu +Tested-by: Simon Trimmer +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260428080139.GA1649104@chcpu16 +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l56_hda.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c +index 4c8d01799931c..cdbc576569efe 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c +@@ -1041,6 +1041,7 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); ++ acpi_dev_put(adev); + } + + /* Initialize things that could be overwritten by a fixup */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch new file mode 100644 index 0000000000..f125a2fdc5 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch @@ -0,0 +1,36 @@ +From 8f6d5072bd32689212d877445b3a811df94d3f37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 15:20:25 -0600 +Subject: ALSA: hda/realtek: Add quirk for Acer PT316-51S headset mic + +From: Faye Nichols + +[ Upstream commit a7b56be59b47f4195ddc79ecab238c4401a60bbb ] + +The Acer PT316-51S (PCI SSID 1025:160e) with ALC287 codec does not +detect the headset microphone due to missing BIOS pin configuration +for pin 0x19. Apply ALC2XX_FIXUP_HEADSET_MIC to enable it. + +Signed-off-by: Faye Nichols +Link: https://patch.msgid.link/20260413212645.117119-1-faye.opensource@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index c9f622651fce6..cd5c9f2a7a59e 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -6730,6 +6730,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), + SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), + SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED), +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch new file mode 100644 index 0000000000..796a3c8fed --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch @@ -0,0 +1,80 @@ +From 2e03369514c6825d337e7f7de072989ddaa85d16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:40:28 +0800 +Subject: ALSA: hda/realtek: Add quirk for CSL Unity BF24B + +From: Zhang Heng + +[ Upstream commit de65275fc94e2e0acc79bd016d60889bf251ccd9 ] + +The CSL Unity BF24B all-in-one PC uses a Realtek ALC662 rev3 audio +codec and requires the correct GPIO configuration to enable sound +output from both the speakers and the headphone. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221258 +Signed-off-by: Zhang Heng +Link: https://patch.msgid.link/20260409024028.1297587-1-zhangheng@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc662.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c +index 5073165d1f3cf..3abe41c7315c4 100644 +--- a/sound/hda/codecs/realtek/alc662.c ++++ b/sound/hda/codecs/realtek/alc662.c +@@ -255,6 +255,25 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, + alc_fixup_headset_mode(codec, fix, action); + } + ++static void alc662_fixup_csl_amp(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ struct alc_spec *spec = codec->spec; ++ ++ switch (action) { ++ case HDA_FIXUP_ACT_PRE_PROBE: ++ spec->gpio_mask |= 0x03; ++ spec->gpio_dir |= 0x03; ++ break; ++ case HDA_FIXUP_ACT_INIT: ++ /* need to toggle GPIO to enable the amp */ ++ alc_update_gpio_data(codec, 0x03, true); ++ msleep(100); ++ alc_update_gpio_data(codec, 0x03, false); ++ break; ++ } ++} ++ + enum { + ALC662_FIXUP_ASPIRE, + ALC662_FIXUP_LED_GPIO1, +@@ -313,6 +332,7 @@ enum { + ALC897_FIXUP_HEADSET_MIC_PIN2, + ALC897_FIXUP_UNIS_H3C_X500S, + ALC897_FIXUP_HEADSET_MIC_PIN3, ++ ALC662_FIXUP_CSL_GPIO, + }; + + static const struct hda_fixup alc662_fixups[] = { +@@ -766,11 +786,16 @@ static const struct hda_fixup alc662_fixups[] = { + { } + }, + }, ++ [ALC662_FIXUP_CSL_GPIO] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc662_fixup_csl_amp, ++ }, + }; + + static const struct hda_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), ++ SND_PCI_QUIRK(0x1022, 0xc950, "CSL Unity BF24B", ALC662_FIXUP_CSL_GPIO), + SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-honor-mrb-xxx-m1020.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-honor-mrb-xxx-m1020.patch new file mode 100644 index 0000000000..85a6624d31 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-honor-mrb-xxx-m1020.patch @@ -0,0 +1,69 @@ +From 6e85e8267cf446e4be03f5bcb958d8dacb52dd44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:46:57 +1000 +Subject: ALSA: hda/realtek: add quirk for HONOR MRB-XXX M1020 + +From: Timofey Tarasenko + +[ Upstream commit d9448dca423543c6c0a9890d3ff53a5d51895318 ] + +Adds pin fixups to enable subwoofer and JACK functionality +on Honor Magicbook Art 14 2025 (HONOR MRB-XXX M1020) + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221147 +Signed-off-by: Timofey Tarasenko +Link: https://patch.msgid.link/20260415074657.1217862-1-timka.tarasen@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index b96ff8abc99db..89ff47d8ad4e0 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -4132,6 +4132,7 @@ enum { + ALC245_FIXUP_ACER_MICMUTE_LED, + ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED, + ALC236_FIXUP_HP_DMIC, ++ ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, + }; + + /* A special fixup for Lenovo C940 and Yoga Duet 7; +@@ -6678,6 +6679,16 @@ static const struct hda_fixup alc269_fixups[] = { + { 0x12, 0x90a60160 }, /* use as internal mic */ + { } + }, ++ }, ++ [ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x14, 0x90170111 }, ++ { 0x19, 0x03a1113c }, ++ { 0x1a, 0x22a190a0 }, ++ { 0x1b, 0x90170110 }, ++ { } ++ } + } + }; + +@@ -7780,6 +7791,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), + SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK), + SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO), + SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC), + SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), +@@ -8000,6 +8012,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { + {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"}, + {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"}, + {.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"}, ++ {.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"}, + {} + }; + #define ALC225_STANDARD_PINS \ +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch b/queue-7.0/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch new file mode 100644 index 0000000000..5f63ec47f6 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch @@ -0,0 +1,47 @@ +From 34e59f5d45751ac5d0df3366e25479d7d4af4281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:18:54 +0800 +Subject: ALSA: hda/realtek: Add quirk for HP Spectre x360 14-ea + +From: songxiebing + +[ Upstream commit 882321ccaeea52dd645dff98bfea2f92b286e673 ] + +HP Spectre x360 Convertible 14-ea0xxx (2021 model or so) +doesn't make produce sound,The Bang & Olufsen speaker amplifier +is not enabled. + +Root causing: +The PCI subsystem ID is 103c:0000 (HP left it unset), while the codec +subsystem ID is 103c:885b. The vendor-wide catch-all +SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED) matches +103c:0000 before the codec SSID fallback is reached, so +ALC245_FIXUP_HP_X360_AMP never applies. + +So add the quirk in alc269_fixup_tbl. + +Reported-by: dzidmail +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221341 +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260413011854.96520-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index cd5c9f2a7a59e..b96ff8abc99db 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -6967,6 +6967,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), ++ HDA_CODEC_QUIRK(0x103c, 0x885b, "HP Spectre x360 14-ea", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch b/queue-7.0/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch new file mode 100644 index 0000000000..3398834d41 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-support-for-asus-2026-commercia.patch @@ -0,0 +1,45 @@ +From 7835018eb2845ac4a96604fb0114fafa065e27d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:46:18 +0100 +Subject: ALSA: hda/realtek: Add support for ASUS 2026 Commercial laptops using + CS35L41 HDA + +From: Stefan Binding + +[ Upstream commit 66a6333ba5087b00b7d6cb9ff671f4e2739383b3 ] + +Add support for laptops: +- ASUS PM5406CGA +- ASUS PM5606CGA +- ASUS P5406CCA +- ASUS P5606CCA + +Laptops use 2 CS35L41 Amps with HDA, using Internal boost, with I2C or +SPI. + +Signed-off-by: Stefan Binding +Link: https://patch.msgid.link/20260330134651.443439-3-sbinding@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index 8f7d8337b4bc6..fa484f0bc946a 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7379,6 +7379,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3391, "ASUS PM3606CKA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3601, "ASUS PM5406CGA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3611, "ASUS PM5606CGA", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x1043, 0x3701, "ASUS P5406CCA", ALC245_FIXUP_CS35L41_SPI_2), ++ SND_PCI_QUIRK(0x1043, 0x3711, "ASUS P5606CCA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-add-support-for-hp-laptops.patch b/queue-7.0/alsa-hda-realtek-add-support-for-hp-laptops.patch new file mode 100644 index 0000000000..4ee538d862 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-add-support-for-hp-laptops.patch @@ -0,0 +1,47 @@ +From c5256df9739b75b96912e124ae101a6528994c04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:46:17 +0100 +Subject: ALSA: hda/realtek: Add support for HP Laptops + +From: Stefan Binding + +[ Upstream commit 8dbbd39d0605b93a176f2c775dd2b6bb7c7a8adb ] + +Add support for HP Auster, Trekker and Agusta G7KX. +Laptops use 2 CS35L41 Amps with HDA, using Internal boost, with I2C + +Signed-off-by: Stefan Binding +Link: https://patch.msgid.link/20260330134651.443439-2-sbinding@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index fa484f0bc946a..c9f622651fce6 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -7212,6 +7212,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8e60, "HP OmniBook 7 Laptop 16-bh0xxx", ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x103c, 0x8e75, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e8a, "HP NexusX", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8e9c, "HP 16 Clipper OmniBook X X360", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), +@@ -7233,8 +7234,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8ee4, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), + SND_PCI_QUIRK(0x103c, 0x8ee5, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), + SND_PCI_QUIRK(0x103c, 0x8ee7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), ++ SND_PCI_QUIRK(0x103c, 0x8f07, "HP Agusta G7KX", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8f0c, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2), ++ SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8f41, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-enable-mute-led-support-on-thinkboo.patch b/queue-7.0/alsa-hda-realtek-enable-mute-led-support-on-thinkboo.patch new file mode 100644 index 0000000000..b8c060998c --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-enable-mute-led-support-on-thinkboo.patch @@ -0,0 +1,65 @@ +From 37936b9f8cc1c1f60a3370d9e24f193c1abb0d7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 19:21:07 +0800 +Subject: ALSA: hda/realtek: enable mute LED support on ThinkBook 16p + +From: Yuxuan Qiu + +[ Upstream commit 597aa74b0e73f5e0c915b5d0c95cb296774589bd ] + +On ThinkBook 16p systems the platform mute LED is present and +bound to the audio-mute trigger, but it does not react to Master +mute changes. + +The affected fixup chain sets up the DAC routing, but does not enable +vmaster mute LED handling. Because of that, the generic HDA code does +not mark Master Playback Switch with SNDRV_CTL_ELEM_ACCESS_SPK_LED, +and the audio-mute trigger never receives speaker mute updates. + +Add a ThinkBook-specific wrapper around alc287_fixup_bind_dacs() and +enable spec->gen.vmaster_mute_led during PRE_PROBE. This keeps the +existing DAC binding logic unchanged while allowing the normal generic +LED path to drive the mute LED. + +Signed-off-by: Yuxuan Qiu +Link: https://patch.msgid.link/20260424112107.22206-1-yuxuanqiu596@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index 89ff47d8ad4e0..4d2a9728acbbb 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -3714,6 +3714,17 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; + } ++ ++static void alc287_fixup_tb_vmaster_led(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ struct alc_spec *spec = codec->spec; ++ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) ++ spec->gen.vmaster_mute_led = 1; ++ ++ alc287_fixup_bind_dacs(codec, fix, action); ++} + /* GPIO2: mute led GPIO3: micmute led */ + static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +@@ -6473,7 +6484,7 @@ static const struct hda_fixup alc269_fixups[] = { + }, + [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = { + .type = HDA_FIXUP_FUNC, +- .v.func = alc287_fixup_bind_dacs, ++ .v.func = alc287_fixup_tb_vmaster_led, + .chained = true, + .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, + }, +-- +2.53.0 + diff --git a/queue-7.0/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch b/queue-7.0/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch new file mode 100644 index 0000000000..60109db01f --- /dev/null +++ b/queue-7.0/alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch @@ -0,0 +1,65 @@ +From ec6d99b99fd9e16e5023500d097f5fbfc0982d6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:59:45 -0300 +Subject: ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1a56641b7ae4f19216774a59d68024be3e6197d0 ] + +snd_pcm_suspend_all() walks all PCM substreams and uses a lockless +runtime check to skip closed streams. It then calls snd_pcm_suspend() +for each remaining substream and finally runs snd_pcm_sync_stop() in a +second pass. + +The runtime lifetime is still controlled by pcm->open_mutex in the +open/release path. That means a concurrent close can clear or free +substream->runtime after the initial check in snd_pcm_suspend_all(), +leaving the later suspend or sync-stop path to dereference a stale or +NULL runtime pointer. + +Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime +pointer stays stable across both loops. This matches the existing PCM +runtime lifetime rule already used by other core paths that access +substream->runtime outside the stream lock. + +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_native.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index 5a64453da7283..1ccc482a8dfd3 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -1761,6 +1761,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream) + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm + * @pcm: the PCM instance + * ++ * Takes and releases pcm->open_mutex to serialize against ++ * concurrent open/close while walking the substreams. ++ * + * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. +@@ -1773,8 +1776,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) + if (! pcm) + return 0; + ++ guard(mutex)(&pcm->open_mutex); ++ + for_each_pcm_substream(pcm, stream, substream) { +- /* FIXME: the open/close code should lock this as well */ + if (!substream->runtime) + continue; + +-- +2.53.0 + diff --git a/queue-7.0/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch b/queue-7.0/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch new file mode 100644 index 0000000000..5e1fb5eca7 --- /dev/null +++ b/queue-7.0/alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch @@ -0,0 +1,60 @@ +From 59d97c1bd83064029159fd4e7e8b4fcdb7f3e1c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 20:02:21 -0300 +Subject: ALSA: pcm: Use pcm_lib_apply_appl_ptr() in x32 sync_ptr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 1e512ac1254c8e370dd18efe9da4dfc92492cdc5 ] + +snd_pcm_ioctl_sync_ptr_x32() still handles incoming appl_ptr updates +differently from the other SYNC_PTR paths. The native handler and the +32-bit compat handler both pass appl_ptr through pcm_lib_apply_appl_ptr(), +but the x32 handler still writes control->appl_ptr directly. + +That direct assignment skips the common appl_ptr validation against +runtime->boundary and also bypasses the substream ack() callback. +This makes the x32 ioctl path behave differently from the native and +compat32 cases, and it can miss the driver notification that explicit +appl_ptr synchronization relies on. + +Use pcm_lib_apply_appl_ptr() for x32 too, so appl_ptr updates are +validated consistently and drivers relying on ack() notifications +see the same behavior. + +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260321-alsa-pcm-x32-sync-ptr-v1-1-02ce655657c6@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/pcm_compat.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c +index e71f393d3b018..5313f50f17da5 100644 +--- a/sound/core/pcm_compat.c ++++ b/sound/core/pcm_compat.c +@@ -430,11 +430,13 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, + if (!boundary) + boundary = 0x7fffffff; + scoped_guard(pcm_stream_lock_irq, substream) { +- /* FIXME: we should consider the boundary for the sync from app */ +- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) +- control->appl_ptr = scontrol.appl_ptr; +- else ++ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { ++ err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr); ++ if (err < 0) ++ return err; ++ } else { + scontrol.appl_ptr = control->appl_ptr % boundary; ++ } + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else +-- +2.53.0 + diff --git a/queue-7.0/alsa-scarlett2-add-missing-error-check-when-initiali.patch b/queue-7.0/alsa-scarlett2-add-missing-error-check-when-initiali.patch new file mode 100644 index 0000000000..4379912798 --- /dev/null +++ b/queue-7.0/alsa-scarlett2-add-missing-error-check-when-initiali.patch @@ -0,0 +1,41 @@ +From fe2073747515ee42c241d38f3c442d2d97fb34ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 10:39:14 +0700 +Subject: ALSA: scarlett2: Add missing error check when initialise Autogain + Status + +From: Robertus Diawan Chris + +[ Upstream commit c0e4fffc0f474b7ed10adee4ab2bc1a66d36fc72 ] + +When initialise new control with scarlett2_add_new_ctl() function for +Autogain Status, scarlett2_add_new_ctl() might throw an error. So, add +error check after initialise new control for Autogain Status. + +This is reported by Coverity Scan with CID 1598781 as UNUSED_VALUE. + +Fixes: 0a995e38dc44 ("ALSA: scarlett2: Add support for software-controllable input gain") +Signed-off-by: Robertus Diawan Chris +Link: https://patch.msgid.link/20260508033914.111596-1-robertusdchris@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index 8eaa962227596..0f83f8981213f 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -6707,6 +6707,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_status_ctl, + i, 1, s, &private->autogain_status_ctls[i]); ++ if (err < 0) ++ return err; + } + + /* Add autogain target controls */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch b/queue-7.0/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch new file mode 100644 index 0000000000..b0253ff6cd --- /dev/null +++ b/queue-7.0/alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch @@ -0,0 +1,47 @@ +From 02277b134d4c49145c056074a2ba881bfe10da7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 08:21:37 +0000 +Subject: ALSA: usb-audio: Add iface reset and delay quirk for HUAWEI USB-C + HEADSET + +From: Lianqin Hu + +[ Upstream commit 9575766a682f50ec4bcb85ecd438685bdc09f9cc ] + +Setting up the interface when suspended/resumeing fail on this card. +Adding a reset and delay quirk will eliminate this problem. + +usb 1-1: new full-speed USB device number 2 using xhci-hcd +usb 1-1: New USB device found, idVendor=12d1, idProduct=3a07 +usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +usb 1-1: Product: HUAWEI USB-C HEADSET +usb 1-1: Manufacturer: bestechnic +usb 1-1: SerialNumber: 0296C100000000000000000000000 + +Signed-off-by: Lianqin Hu +Link: https://patch.msgid.link/TYUPR06MB62176A18EA7A9DD0AC2826BCD2582@TYUPR06MB6217.apcprd06.prod.outlook.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index e8ae3464887b2..4ff02a4e1fcae 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2291,8 +2291,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ + QUIRK_FLAG_GET_SAMPLE_RATE), +- DEVICE_FLG(0x12d1, 0x3a07, /* Huawei Technologies Co., Ltd. */ +- QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), ++ DEVICE_FLG(0x12d1, 0x3a07, /* HUAWEI USB-C HEADSET */ ++ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE | QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE | ++ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch b/queue-7.0/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch new file mode 100644 index 0000000000..0bb10577ef --- /dev/null +++ b/queue-7.0/alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch @@ -0,0 +1,43 @@ +From def84458613964ae366848ef31847bfdb58926be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 19:01:23 -0600 +Subject: ALSA: usb-audio: Add quirk entries for NexiGo N930W webcam + +From: Johnathan Penberthy + +[ Upstream commit 17bc5dd49214b50c9eb6df0fad1d1aea287dd078 ] + +The NexiGo N930W 60fps webcam (USB ID 3443:930d) hits the same +'cannot get freq at ep 0x84' error in snd-usb-audio as its sibling +N930AF (1bcf:2283). Without QUIRK_FLAG_GET_SAMPLE_RATE the ADC clock +is never configured and the microphone streams only zero samples. + +Testing on Linux 6.17 with QUIRK_FLAG_GET_SAMPLE_RATE | +QUIRK_FLAG_MIC_RES_16 (via quirk_alias=3443930d:1bcf2283) confirmed +the microphone captures real audio after a cold USB re-enumeration. +Adding a native quirk_flags_table entry avoids the alias workaround. + +Signed-off-by: Johnathan Penberthy +Link: https://patch.msgid.link/20260417010123.3080904-1-johnathan.penberthy@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 4fc6f7cb8c94b..222e04aab3834 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2418,6 +2418,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), + DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), ++ DEVICE_FLG(0x3443, 0x930d, /* NexiGo N930W 60fps Webcam */ ++ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), + DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */ + QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch b/queue-7.0/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch new file mode 100644 index 0000000000..5d4bae4364 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch @@ -0,0 +1,55 @@ +From 15ccc8b1f83f4004bf3525a431a747beadcbbfd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 02:33:05 +0800 +Subject: ALSA: usb-audio: Add quirk flags for Feaulle Rainbow + +From: Rong Zhang + +[ Upstream commit 4f84e6caf38b05991b3b2afc0ddf4e48c2752d1d ] + +Feaulle Rainbow is a wired USB-C dynamic in-ear monitor (IEM) featuring +active noise cancellation (ANC). + +The supported sample rates are 48000Hz and 96000Hz at 16bit or 24bit, +but it does not support reading the current sample rate and results in +an error message printed to kmsg. Set QUIRK_FLAG_GET_SAMPLE_RATE to skip +the sample rate check. + +Its playback mixer reports val = -15360/0/128. Setting -15360 (-60dB) +mutes the playback, so QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE is needed. + +Add a quirk table entry matching VID/PID=0x0e0b/0xfa01 and applying +the mentioned quirk flags, so that it can work properly. + +Quirky device sample: + + usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00 + usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + usb 7-1: Product: Feaulle Rainbow + usb 7-1: Manufacturer: Generic + usb 7-1: SerialNumber: 20210726905926 + +Signed-off-by: Rong Zhang +Link: https://patch.msgid.link/20260409-feaulle-rainbow-v1-1-09179e09000d@rong.moe +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 4ff02a4e1fcae..4fc6f7cb8c94b 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2281,6 +2281,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), ++ DEVICE_FLG(0x0e0b, 0xfa01, /* Feaulle Rainbow */ ++ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), + DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ + QUIRK_FLAG_FIXED_RATE), + DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch b/queue-7.0/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch new file mode 100644 index 0000000000..82dc90eee5 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-add-quirks-for-arturia-af16rig.patch @@ -0,0 +1,212 @@ +From bc214fe5d6c35be585ee9aec0e283be8a49d5dc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 11:08:41 +0000 +Subject: ALSA: usb-audio: Add quirks for Arturia AF16Rig + +From: Phil Willoughby + +[ Upstream commit 0da18c2dd1cc2a026416222ed206e2f269edf055 ] + +The AF16Rig supports 34 channels at 44.1k/48k, 18 channels at 88.2k/96k +and 10 channels at 176.4k/192k. + +This quirks is necessary because the automatic probing process we would +otherwise use fails. The root cause of that is that the AF16Rig clock is +not readable (its descriptor says that it is but the reads fail). + +Except as described below, the values in the audio format quirks were +copied from the USB descriptors of the device. The rate information is +from the datasheet of the device. The clock is the internal clock of the +AF16Rig. + +Tested-By: Phil Willoughby +I have tested all the configurations enabled by this patch. + +Cc: Jaroslav Kysela +Cc: Takashi Iwai +Signed-off-by: Phil Willoughby +Link: https://patch.msgid.link/20260328112426.14816-1-willerz@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 165 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 165 insertions(+) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index eafc0d73cca1f..8f79a15055a6a 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -3900,5 +3900,170 @@ YAMAHA_DEVICE(0x7010, "UB99"), + QUIRK_RME_DIGIFACE(0x3f8c), + QUIRK_RME_DIGIFACE(0x3fa0), + ++/* Arturia AudioFuse 16Rig Audio */ ++/* AF16Rig MIDI has USB PID 0xaf21 and appears to work OK without quirks */ ++{ ++ USB_DEVICE(0x1c75, 0xaf20), ++ QUIRK_DRIVER_INFO { ++ .vendor_name = "Arturia", ++ .product_name = "AF16Rig", ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 34, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03b8, ++ .rates = SNDRV_PCM_RATE_44100| ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 44100, ++ .rate_max = 48000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 44100, 48000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 18, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03a8, ++ .rates = SNDRV_PCM_RATE_88200| ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 88200, ++ .rate_max = 96000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 88200, 96000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(1) { /* Playback */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 10, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 1, ++ .altsetting = 3, ++ .altset_idx = 3, ++ .endpoint = 0x01, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03e8, ++ .rates = SNDRV_PCM_RATE_176400| ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 176400, ++ .rate_max = 192000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 176400, 192000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 34, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03b8, ++ .rates = SNDRV_PCM_RATE_44100| ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 44100, ++ .rate_max = 48000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 44100, 48000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 18, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 2, ++ .altset_idx = 2, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03a8, ++ .rates = SNDRV_PCM_RATE_88200| ++ SNDRV_PCM_RATE_96000, ++ .rate_min = 88200, ++ .rate_max = 96000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 88200, 96000 }, ++ .clock = 41, ++ } ++ }, ++ { ++ QUIRK_DATA_AUDIOFORMAT(2) { /* Capture */ ++ .formats = SNDRV_PCM_FMTBIT_S32_LE, ++ .channels = 10, ++ .fmt_type = UAC_FORMAT_TYPE_I_PCM, ++ .fmt_bits = 24, ++ .fmt_sz = 4, ++ .iface = 2, ++ .altsetting = 3, ++ .altset_idx = 3, ++ .endpoint = 0x81, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC| ++ USB_ENDPOINT_SYNC_ASYNC, ++ .datainterval = 1, ++ .protocol = UAC_VERSION_2, ++ .maxpacksize = 0x03e8, ++ .rates = SNDRV_PCM_RATE_176400| ++ SNDRV_PCM_RATE_192000, ++ .rate_min = 176400, ++ .rate_max = 192000, ++ .nr_rates = 2, ++ .rate_table = (unsigned int[]) { 176400, 192000 }, ++ .clock = 41, ++ } ++ }, ++ { QUIRK_DATA_IGNORE(3) }, /* Firmware update */ ++ QUIRK_COMPOSITE_END ++ } ++ } ++}, ++ + #undef USB_DEVICE_VENDOR_SPEC + #undef USB_AUDIO_DEVICE +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-add-studio-1824-support.patch b/queue-7.0/alsa-usb-audio-add-studio-1824-support.patch new file mode 100644 index 0000000000..2abe438335 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-add-studio-1824-support.patch @@ -0,0 +1,80 @@ +From a2790ae614b62e1f0e42d03cb28a50971ce1b9e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 16:22:16 +0100 +Subject: ALSA: usb-audio: add Studio 1824 support + +From: Frederic Popp + +[ Upstream commit c4791ce96b88a444b04c7089ae2827a3b3ae1877 ] + +Adapt the already implemented support for the Studio 1824c +audio interface to the predecessor Studio 1824. + +Basically just a change adding the +different hardware ID in the relevant places. + +Tested as much as possible. +All implemented functionality seemingly works. + +Signed-off-by: Frederic Popp +Link: https://patch.msgid.link/20260308153334.50433-2-frederic.l.popp@t-online.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/format.c | 4 ++++ + sound/usb/mixer_quirks.c | 3 +++ + sound/usb/mixer_s1810c.c | 2 ++ + 3 files changed, 9 insertions(+) + +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 0fa2f3f3dd2b5..4830f9f93ad77 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -455,6 +455,10 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, + if (chip->usb_id == USB_ID(0x194f, 0x010d) && + !s1810c_valid_sample_rate(fp, rate)) + goto skip_rate; ++ /* Filter out invalid rates on Presonus Studio 1824 */ ++ if (chip->usb_id == USB_ID(0x194f, 0x0107) && ++ !s1810c_valid_sample_rate(fp, rate)) ++ goto skip_rate; + + /* Filter out invalid rates on Focusrite devices */ + if (USB_ID_VENDOR(chip->usb_id) == 0x1235 && +diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c +index 50c42a477030f..930ac93568997 100644 +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -4479,6 +4479,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + err = snd_sc1810_init_mixer(mixer); + break; ++ case USB_ID(0x194f, 0x0107): /* Presonus Studio 1824 */ ++ err = snd_sc1810_init_mixer(mixer); ++ break; + case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ + err = snd_bbfpro_controls_create(mixer); + break; +diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c +index 7eac7d1bce647..2e5a8d37ec578 100644 +--- a/sound/usb/mixer_s1810c.c ++++ b/sound/usb/mixer_s1810c.c +@@ -362,6 +362,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); + break; + ++ case USB_ID(0x194f, 0x0107): /* 1824 */ + case USB_ID(0x194f, 0x010d): /* 1824c */ + /* Set all output faders to unity gain */ + a = SC1810C_SEL_OUTPUT; +@@ -685,6 +686,7 @@ int snd_sc1810_init_mixer(struct usb_mixer_interface *mixer) + return ret; + + break; ++ case USB_ID(0x194f, 0x0107): /* Presonus Studio 1824 */ + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + ret = snd_s1810c_switch_init(mixer, &snd_s1824c_mono_sw); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch b/queue-7.0/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch new file mode 100644 index 0000000000..70bfa0337a --- /dev/null +++ b/queue-7.0/alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch @@ -0,0 +1,47 @@ +From e294e4bcab7cee141c455594b9a4b17233ec8d39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 04:55:19 +0200 +Subject: ALSA: usb-audio: apply quirk for Playstation PDP Riffmaster + +From: Rosalie Wanders + +[ Upstream commit 110189f0268d0eb85895721526328cac5804a739 ] + +This device, just like the Playstation 5's DualSense, has a volume +that's too low, hid-playstation solves this by raising the minimum +volume on the device itself by sending an output report, third party PS5 +controllers/accessories do not support this output report format, so we +apply a quirk to raise the minimum volume by 6dB. + +Signed-off-by: Rosalie Wanders +Link: https://patch.msgid.link/20260426025520.3985-2-rosalie@mailbox.org +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 21191da4c0496..c2a230f91cd06 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, + cval->res = 1; + } + break; ++ ++ case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ ++ case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ ++ if (!strcmp(kctl->id.name, "PCM Playback Volume")) { ++ usb_audio_info(chip, ++ "set volume quirk for PDP Riffmaster for PS4/PS5\n"); ++ cval->min = -2560; /* Mute under it */ ++ } ++ break; ++ + case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { + usb_audio_info(chip, +-- +2.53.0 + diff --git a/queue-7.0/arm-xen-validate-hypervisor-compatible-before-parsin.patch b/queue-7.0/arm-xen-validate-hypervisor-compatible-before-parsin.patch new file mode 100644 index 0000000000..4713390595 --- /dev/null +++ b/queue-7.0/arm-xen-validate-hypervisor-compatible-before-parsin.patch @@ -0,0 +1,60 @@ +From b482206bebbdb4ac29a416f3bd28904074ba4c25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 08:42:00 +0800 +Subject: ARM: xen: validate hypervisor compatible before parsing its version + +From: Pengpeng Hou + +[ Upstream commit f45ab27774aadeee28f093a9f074892e9bebb586 ] + +fdt_find_hyper_node() reads the raw compatible property and then derives +hyper_node.version from a prefix match before later printing it with %s. +Flat DT properties are external boot input, and this path does not prove +that the first compatible entry is NUL-terminated within the returned +property length. + +Keep the existing flat-DT lookup path, but verify that the first +compatible entry terminates within the returned property length before +deriving the version suffix from it. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Stefano Stabellini +Signed-off-by: Juergen Gross +Message-ID: <20260405094005.5-arm-xen-v2-pengpeng@iscas.ac.cn> +Signed-off-by: Sasha Levin +--- + arch/arm/xen/enlighten.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index 4feed2c2498dd..25a0ce3b4584a 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -218,8 +218,9 @@ static __initdata struct { + static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + int depth, void *data) + { +- const void *s = NULL; ++ const char *s = NULL; + int len; ++ size_t prefix_len = strlen(hyper_node.prefix); + + if (depth != 1 || strcmp(uname, "hypervisor") != 0) + return 0; +@@ -228,9 +229,10 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname, + hyper_node.found = true; + + s = of_get_flat_dt_prop(node, "compatible", &len); +- if (strlen(hyper_node.prefix) + 3 < len && +- !strncmp(hyper_node.prefix, s, strlen(hyper_node.prefix))) +- hyper_node.version = s + strlen(hyper_node.prefix); ++ if (s && len > 0 && strnlen(s, len) < len && ++ len > prefix_len + 3 && ++ !strncmp(hyper_node.prefix, s, prefix_len)) ++ hyper_node.version = s + prefix_len; + + /* + * Check if Xen supports EFI by checking whether there is the +-- +2.53.0 + diff --git a/queue-7.0/arm64-tegra-fix-snps-blen-properties.patch b/queue-7.0/arm64-tegra-fix-snps-blen-properties.patch new file mode 100644 index 0000000000..d60faa5ddc --- /dev/null +++ b/queue-7.0/arm64-tegra-fix-snps-blen-properties.patch @@ -0,0 +1,52 @@ +From 371356725c4b725e407ae588d53649135acb4743 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 15:33:04 +0100 +Subject: arm64: tegra: Fix snps,blen properties + +From: Thierry Reding + +[ Upstream commit 51f10c527a63dc4a71bce4b40fc53eee78bbbd52 ] + +The snps,blen property of stmmac-axi-config nodes needs to have 7 +entries in total, with unsupported burst lengths listed as 0. + +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/nvidia/tegra234.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +index 850c473235e36..04a95b6658caa 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +@@ -3621,7 +3621,7 @@ ethernet@6800000 { + snps,axi-config = <&mgbe0_axi_setup>; + + mgbe0_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3663,7 +3663,7 @@ ethernet@6900000 { + snps,axi-config = <&mgbe1_axi_setup>; + + mgbe1_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +@@ -3705,7 +3705,7 @@ ethernet@6a00000 { + snps,axi-config = <&mgbe2_axi_setup>; + + mgbe2_axi_setup: stmmac-axi-config { +- snps,blen = <256 128 64 32>; ++ snps,blen = <256 128 64 32 0 0 0>; + snps,rd_osr_lmt = <63>; + snps,wr_osr_lmt = <63>; + }; +-- +2.53.0 + diff --git a/queue-7.0/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch b/queue-7.0/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch new file mode 100644 index 0000000000..d0f17b7a6a --- /dev/null +++ b/queue-7.0/asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch @@ -0,0 +1,47 @@ +From 30d5eefde98db9bc6046f955a990c007655f86c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:45:53 +0200 +Subject: ASoC: amd: yc: Add MSI Vector A16 HX A8WHG to quirk table + +From: Ihor Uzlov + +[ Upstream commit 72dcd84938f5026dc44d0e7e1e68d9d571c113a0 ] + +Add the MSI Vector A16 HX A8WHG (board MS-15MM) to the DMI quirk table +to enable DMIC support. This laptop uses an AMD Ryzen 9 7945HX (Dragon +Range) with the ACP6x audio coprocessor (rev 0x62) and a Realtek ALC274 +codec. The built-in digital microphone is connected via the ACP PDM +interface and requires this DMI entry to be activated. + +Tested on MSI Vector A16 HX A8WHG with kernel 6.8.0-107 (Ubuntu 24.04). +DMIC capture device appears as 'acp6x' and records audio correctly. + +Signed-off-by: Ihor Uzlov +Link: https://patch.msgid.link/20260410094553.24654-1-igor.uzlov@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index 2f7a51d7eb115..dfee004e2b9a7 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -500,6 +500,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vector A16 HX A8WHG"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +-- +2.53.0 + diff --git a/queue-7.0/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch b/queue-7.0/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch new file mode 100644 index 0000000000..ffc00d1bac --- /dev/null +++ b/queue-7.0/asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch @@ -0,0 +1,65 @@ +From e573ce5a649f54033c5b4991e3bdde80db3dfc2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:34:08 +0800 +Subject: ASoC: aw88395: Fix kernel panic caused by invalid GPIO error pointer + +From: wangdicheng + +[ Upstream commit 241ee17ecb6be210f7b231b2a81bfb68871950d0 ] + +In aw88395_i2c_probe(), if `devm_gpiod_get_optional()` fails, it returns +an ERR_PTR() error pointer. The current code only prints a message and +continues execution, leaving `aw88395->reset_gpio` as an invalid pointer. + +Later, in `aw88395_hw_reset()`, this invalid pointer is passed to +`gpiod_set_value_cansleep()`, which dereferences it and causes a kernel +panic. + +For optional GPIOs, `devm_gpiod_get_optional()` returns NULL if the GPIO +is not defined in the DT, which is safe. If it returns an ERR_PTR, it +means a real error occurred (e.g., -EPROBE_DEFER) and the probe must be +aborted. + +Also, since the GPIO is optional, remove the dev_err() log in +aw88395_hw_reset() when the GPIO is missing to match the optional +semantics. This also fixes a potential NULL pointer dereference as +aw_pa is not initialized when aw88395_hw_reset() is called. + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428023408.46420-1-wangdich9700@163.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/aw88395/aw88395.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c +index 3602b5b9f7d77..dd09bac652f7f 100644 +--- a/sound/soc/codecs/aw88395/aw88395.c ++++ b/sound/soc/codecs/aw88395/aw88395.c +@@ -456,8 +456,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); + gpiod_set_value_cansleep(aw88395->reset_gpio, 1); + usleep_range(AW88395_1000_US, AW88395_1000_US + 10); +- } else { +- dev_err(aw88395->aw_pa->dev, "%s failed", __func__); + } + } + +@@ -522,9 +520,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) + i2c_set_clientdata(i2c, aw88395); + + aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); +- if (IS_ERR(aw88395->reset_gpio)) +- dev_info(&i2c->dev, "reset gpio not defined\n"); +- ++ if (IS_ERR(aw88395->reset_gpio)) { ++ return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), ++ "failed to get reset gpio\n"); ++ } + /* hardware reset */ + aw88395_hw_reset(aw88395); + +-- +2.53.0 + diff --git a/queue-7.0/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch b/queue-7.0/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch new file mode 100644 index 0000000000..a26c5097e1 --- /dev/null +++ b/queue-7.0/asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch @@ -0,0 +1,56 @@ +From 8ccba703bb116ffa9446356bbcca12c61b1013b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 15:10:06 +0100 +Subject: ASoC: codecs: wcd-clsh: Always update buck/flyback on transitions on + transitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit f8d51e903a6c97d8d298f14d9f8b4fff808670e3 ] + +The WCD934x audio outputs (earpiece, headphone, speaker) share two power +supply converters, a buck and a flyback, managed by reference counters +(buck_users, flyback_users) in the Class-H controller. + +The early return in wcd_clsh_ctrl_set_state() when nstate == ctrl->state +prevented _wcd_clsh_ctrl_set_state() from being called when switching +between outputs sharing the same state value. As a result, the buck and +flyback reference counters were never decremented on disable, leaving the +converters active and their counters out of sync with the actual hardware +state. + +This caused audible distortion on the earpiece output and spurious MBHC +over-current protection interrupts on HPHL/HPHR during output switching. + +Remove the early return so that CLSH_REQ_ENABLE and CLSH_REQ_DISABLE are +always dispatched, keeping the buck and flyback reference counters +consistent on every state transition. + +Signed-off-by: Cédric Bellegarde +Link: https://patch.msgid.link/20260304141006.280894-1-cedric.bellegarde@adishatz.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd-clsh-v2.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c +index 13d07296916f6..62ca22ea0f3b6 100644 +--- a/sound/soc/codecs/wcd-clsh-v2.c ++++ b/sound/soc/codecs/wcd-clsh-v2.c +@@ -848,9 +848,6 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + { + struct snd_soc_component *comp = ctrl->comp; + +- if (nstate == ctrl->state) +- return 0; +- + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch b/queue-7.0/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch new file mode 100644 index 0000000000..f59ddd49dd --- /dev/null +++ b/queue-7.0/asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch @@ -0,0 +1,88 @@ +From 391da5077fe9ede336713367d099aab71043654e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:32:21 +0530 +Subject: ASoC: codecs: wcd937x: fix AUX PA sequencing and mixer controls + +From: Ajay Kumar Nandam + +[ Upstream commit 74c876bfd71b1023029a483d7213015201f62b53 ] + +Enable AUX PA sequencing during AUX DAC DAPM events and keep the +AUX-specific RX supplies enabled while the path is active. + +Add the missing AUX-related mixer controls, including CLSH PA and +DSD left/right switches, so AUX playback can be routed from userspace. + +Signed-off-by: Ajay Kumar Nandam +Link: https://patch.msgid.link/20260420180221.785113-1-ajay.nandam@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wcd937x.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c +index 10a2d598caa71..72a53f95d6887 100644 +--- a/sound/soc/codecs/wcd937x.c ++++ b/sound/soc/codecs/wcd937x.c +@@ -546,6 +546,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), BIT(2)); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), BIT(4)); + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_DIG_CLK_CTL, + BIT(2), BIT(2)); +@@ -562,6 +565,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_DIGITAL_CDC_ANA_CLK_CTL, + BIT(2), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_AUX_AUXPA, ++ BIT(4), 0x00); + break; + } + +@@ -730,10 +736,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + snd_soc_component_update_bits(component, + WCD937X_ANA_RX_SUPPLIES, + BIT(1), BIT(1)); ++ /* Enable AUX PA related RX supplies */ ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), BIT(6)); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), BIT(7)); + enable_irq(wcd937x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd937x->aux_pdm_wd_int); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(6), 0x00); ++ snd_soc_component_update_bits(component, ++ WCD937X_ANA_RX_SUPPLIES, ++ BIT(7), 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(2000, 2010); +@@ -2051,7 +2070,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), +- ++ SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), ++ SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0, ++ wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, + wcd937x_get_swr_port, wcd937x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch b/queue-7.0/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..c81c2c98d6 --- /dev/null +++ b/queue-7.0/asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From a6b17dbeace43f85823243c02d8ea2585204729e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:04 -0400 +Subject: ASoC: Intel: bytcr_rt5640: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit a02496a29463e7f0d1643e83aab28adb3dd03f1a ] + +If byt_rt5640_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-2-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index 103e0b445603f..e4c21c9c5b38c 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -289,6 +289,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch b/queue-7.0/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch new file mode 100644 index 0000000000..3fdb963280 --- /dev/null +++ b/queue-7.0/asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch @@ -0,0 +1,40 @@ +From 8a43ceaee06f4f881037515d2ca6a970e6263619 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:05 -0400 +Subject: ASoC: Intel: bytcr_rt5651: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit b022e5c142efe4c5497e6cfda1f143618b4b9254 ] + +If byt_rt5651_prepare_and_enable_pll1() fails, the function returns +without calling clk_disable_unprepare() on priv->mclk, which was +already enabled earlier in the same code path. Add the missing +cleanup call to prevent the clock from leaking. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-3-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5651.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index 68cf463f1d507..8932fc5d6f4f2 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -209,6 +209,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + return ret; + } + ret = byt_rt5651_prepare_and_enable_pll1(codec_dai, 48000, 50); ++ if (ret < 0) ++ clk_disable_unprepare(priv->mclk); + } else { + /* + * Set codec clock source to internal clock before +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch b/queue-7.0/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch new file mode 100644 index 0000000000..f3bb54444d --- /dev/null +++ b/queue-7.0/asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch @@ -0,0 +1,50 @@ +From c29abf4fff1b75b16b9a91e26edbf670b39f403d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 18:05:06 -0400 +Subject: ASoC: Intel: cht_bsw_rt5672: Fix MCLK leak on platform_clock_control + error + +From: Aravind Anilraj + +[ Upstream commit dced5a373a96cfd9f3bd0ffcf5339a7579d1473a ] + +If snd_soc_dai_set_pll() or snd_soc_dai_set_sysclk() fail inside the +EVENT_ON path, the function returns without calling +clk_disable_unprepare() on ctx->mclk, which was already enabled earlier +in the same code path. Add the missing clk_disable_unprepare() calls +before returning the error. + +Signed-off-by: Aravind Anilraj +Reviewed-by: Cezary Rojewski +Link: https://patch.msgid.link/20260401220507.23557-4-aravindanilraj0702@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c +index 359723f2700e4..57d6997eb12ff 100644 +--- a/sound/soc/intel/boards/cht_bsw_rt5672.c ++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c +@@ -77,6 +77,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + +@@ -85,6 +87,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); ++ if (ctx->mclk) ++ clk_disable_unprepare(ctx->mclk); + return ret; + } + } else { +-- +2.53.0 + diff --git a/queue-7.0/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch b/queue-7.0/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch new file mode 100644 index 0000000000..524c9e8695 --- /dev/null +++ b/queue-7.0/asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch @@ -0,0 +1,46 @@ +From 811b2701d18c1ac0971baf5ac78a8e94b4c78537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 13:30:51 +0800 +Subject: ASoC: mxs-sgtl5000: disable MCLK on error paths of + mxs_sgtl5000_probe() + +From: Haoxiang Li + +[ Upstream commit c8ef13d692f19cdbbf195fb845421a5b71801704 ] + +Call mxs_saif_put_mclk() to disable MCLK on error +paths of mxs_sgtl5000_probe(). + +Signed-off-by: Haoxiang Li +Link: https://patch.msgid.link/20260401053051.586290-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/mxs/mxs-sgtl5000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c +index 245f174116384..f1c0e612313dd 100644 +--- a/sound/soc/mxs/mxs-sgtl5000.c ++++ b/sound/soc/mxs/mxs-sgtl5000.c +@@ -157,13 +157,16 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); ++ mxs_saif_put_mclk(0); + return ret; + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) ++ if (ret) { ++ mxs_saif_put_mclk(0); + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/asoc-qcom-x1e80100-limit-speaker-volumes.patch b/queue-7.0/asoc-qcom-x1e80100-limit-speaker-volumes.patch new file mode 100644 index 0000000000..7de5a7f893 --- /dev/null +++ b/queue-7.0/asoc-qcom-x1e80100-limit-speaker-volumes.patch @@ -0,0 +1,75 @@ +From 5c1b78c2b2b0db00d6d88b9f29b43d674843ce98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 15:30:59 +0200 +Subject: ASoC: qcom: x1e80100: limit speaker volumes + +From: Tobias Heider + +[ Upstream commit 0a5ee0e520eff98ee2b4568194562870877b050f ] + +Limit the digital gain and PA volumes to a combined -3 dB in the machine +driver to reduce the risk of speaker damage until we have active speaker +protection in place (or higher safe levels have been established). + +Based on commit c481016bb4f8 ("ASoC: qcom: sc8280xp: limit speaker +volumes") which addressed the same issue on the sc8280x SoC with some +minor changes as explained below. + +The Digital Volume behaves almost identical to sc8280x since both use +the same lpass-wsa-macro, but x1e80100 has two sets of controls prefixed +with WSA and WSA2. +For PA x1e80100 machines use wsa884x amplifiers which expose a linear +scale from -9 dB to 9 dB with a 1.5 dB step size giving us +0 dB = -9 dB + 6 * 1.5 dB. + +On x1e80100 there are two different speaker topologies we need to handle: + 2-Speakers: SpkrLeft, Spkr Right + 4-Speakers: WooferLeft, WooferRight, TweeterLeft, TweeterRight + +Signed-off-by: Tobias Heider +Tested-by: Srinivas Kandagatla +Reviewed-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260422-x1e80100-audio-limit-v2-1-333258b97697@canonical.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/x1e80100.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c +index a3f4785c4bbe6..c81df41ace883 100644 +--- a/sound/soc/qcom/x1e80100.c ++++ b/sound/soc/qcom/x1e80100.c +@@ -27,10 +27,29 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) + { + struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_card *card = rtd->card; + struct snd_soc_jack *dp_jack = NULL; + int dp_pcm_id = 0; + + switch (cpu_dai->id) { ++ case WSA_CODEC_DMA_RX_0: ++ case WSA_CODEC_DMA_RX_1: ++ /* ++ * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume ++ * to reduce the risk of speaker damage until we have active ++ * speaker protection in place. ++ */ ++ snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81); ++ snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81); ++ snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "SpkrRight PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6); ++ snd_soc_limit_volume(card, "WooferRight PA Volume", 6); ++ snd_soc_limit_volume(card, "TweeterRight PA Volume", 6); ++ break; + case DISPLAY_PORT_RX_0: + dp_pcm_id = 0; + dp_jack = &data->dp_jack[dp_pcm_id]; +-- +2.53.0 + diff --git a/queue-7.0/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch b/queue-7.0/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch new file mode 100644 index 0000000000..b91fae6a85 --- /dev/null +++ b/queue-7.0/asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch @@ -0,0 +1,46 @@ +From a9d9592a34382a4a1c7880a8847365ea2f9445e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:05:47 +0000 +Subject: ASoC: rt5640: Handle 0Hz sysclk during stream shutdown + +From: Sheetal + +[ Upstream commit 247d1c13992d2c501e2e020e84d9d2920e11bf78 ] + +Commit 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when +shutdown") sends a 0Hz sysclk request during stream shutdown to clear +codec rate constraints. The rt5640 codec forwards this 0Hz to +clk_set_rate(), which can cause clock controller firmware faults on +platforms where MCLK is SoC-driven (e.g. Tegra) and 0Hz falls below +the hardware minimum rate. + +Handle the 0Hz case by clearing the internal sysclk state and +returning early, avoiding the invalid clk_set_rate() call. + +Signed-off-by: Sheetal +Link: https://patch.msgid.link/20260406090547.988966-1-sheetal@nvidia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5640.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index db2222e6f2e75..f6c6294e15880 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -1838,6 +1838,11 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, + unsigned int pll_bit = 0; + int ret; + ++ if (!freq) { ++ rt5640->sysclk = 0; ++ return 0; ++ } ++ + switch (clk_id) { + case RT5640_SCLK_S_MCLK: + ret = clk_set_rate(rt5640->mclk, freq); +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdca-add-cs47l47-to-class-driver.patch b/queue-7.0/asoc-sdca-add-cs47l47-to-class-driver.patch new file mode 100644 index 0000000000..ceca81d682 --- /dev/null +++ b/queue-7.0/asoc-sdca-add-cs47l47-to-class-driver.patch @@ -0,0 +1,35 @@ +From 6c7455f48f9b6eaca5d9f609e2c16bcf02144579 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 15:02:56 +0000 +Subject: ASoC: SDCA: Add CS47L47 to class driver + +From: Richard Fitzgerald + +[ Upstream commit ada32396f90951e12465224c04742607ca56a982 ] + +Add the SoundWire ID for CS47L47 to the class driver. + +Signed-off-by: Richard Fitzgerald +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260223150256.326143-4-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_class.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c +index 5def6ae2d99f0..26321b8f5cdf9 100644 +--- a/sound/soc/sdca/sdca_class.c ++++ b/sound/soc/sdca/sdca_class.c +@@ -324,6 +324,7 @@ static const struct dev_pm_ops class_pm_ops = { + + static const struct sdw_device_id class_sdw_id[] = { + SDW_SLAVE_ENTRY(0x01FA, 0x4245, 0), ++ SDW_SLAVE_ENTRY(0x01FA, 0x4747, 0), + {} + }; + MODULE_DEVICE_TABLE(sdw, class_sdw_id); +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdw_utils-add-cs42l43b-codec-info.patch b/queue-7.0/asoc-sdw_utils-add-cs42l43b-codec-info.patch new file mode 100644 index 0000000000..404291ecbc --- /dev/null +++ b/queue-7.0/asoc-sdw_utils-add-cs42l43b-codec-info.patch @@ -0,0 +1,90 @@ +From f12d1c00c665e171d2b6a4b1ec5de9037ce01e16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:28:08 +0000 +Subject: ASoC: sdw_utils: Add CS42L43B codec info + +From: Maciej Strozek + +[ Upstream commit 3e314fde2304b328929c471a70906bc5968f9dcf ] + +Add codec_info for a new variant of CS42L43. It can resue existing info +but needs a new part_id. + +Signed-off-by: Maciej Strozek +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20260306152829.3130530-2-mstrozek@opensource.cirrus.com +Tested-by: Charles Keepax +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdw_utils/soc_sdw_utils.c | 54 +++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c +index 0e67d9f34cba3..4f9089b2a9f84 100644 +--- a/sound/soc/sdw_utils/soc_sdw_utils.c ++++ b/sound/soc/sdw_utils/soc_sdw_utils.c +@@ -723,6 +723,60 @@ struct asoc_sdw_codec_info codec_info_list[] = { + }, + .dai_num = 4, + }, ++ { ++ .part_id = 0x2A3B, ++ .name_prefix = "cs42l43", ++ .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, ++ .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, ++ .dais = { ++ { ++ .direction = {true, false}, ++ .codec_name = "cs42l43-codec", ++ .dai_name = "cs42l43-dp5", ++ .dai_type = SOC_SDW_DAI_TYPE_JACK, ++ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, ++ .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, ++ .controls = generic_jack_controls, ++ .num_controls = ARRAY_SIZE(generic_jack_controls), ++ .widgets = generic_jack_widgets, ++ .num_widgets = ARRAY_SIZE(generic_jack_widgets), ++ }, ++ { ++ .direction = {false, true}, ++ .codec_name = "cs42l43-codec", ++ .dai_name = "cs42l43-dp1", ++ .dai_type = SOC_SDW_DAI_TYPE_MIC, ++ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, ++ .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, ++ .widgets = generic_dmic_widgets, ++ .num_widgets = ARRAY_SIZE(generic_dmic_widgets), ++ .quirk = SOC_SDW_CODEC_MIC, ++ .quirk_exclude = true, ++ }, ++ { ++ .direction = {false, true}, ++ .codec_name = "cs42l43-codec", ++ .dai_name = "cs42l43-dp2", ++ .dai_type = SOC_SDW_DAI_TYPE_JACK, ++ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, ++ }, ++ { ++ .direction = {true, false}, ++ .codec_name = "cs42l43-codec", ++ .dai_name = "cs42l43-dp6", ++ .dai_type = SOC_SDW_DAI_TYPE_AMP, ++ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, ++ .init = asoc_sdw_cs42l43_spk_init, ++ .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, ++ .controls = generic_spk_controls, ++ .num_controls = ARRAY_SIZE(generic_spk_controls), ++ .widgets = generic_spk_widgets, ++ .num_widgets = ARRAY_SIZE(generic_spk_widgets), ++ .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, ++ }, ++ }, ++ .dai_num = 4, ++ }, + { + .part_id = 0x4245, + .name_prefix = "cs42l45", +-- +2.53.0 + diff --git a/queue-7.0/asoc-spacemit-move-hw-constraints-from-hw_params-to-.patch b/queue-7.0/asoc-spacemit-move-hw-constraints-from-hw_params-to-.patch new file mode 100644 index 0000000000..db8dea119f --- /dev/null +++ b/queue-7.0/asoc-spacemit-move-hw-constraints-from-hw_params-to-.patch @@ -0,0 +1,102 @@ +From 2964f09232324f898e631681fabcedcafeda28fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:38:47 +0800 +Subject: ASoC: spacemit: move hw constraints from hw_params to startup + +From: Troy Mitchell + +[ Upstream commit 6b4afbaaa342eaa52172e0be5ef8d1fcbf9ff460 ] + +Hardware constraints should be applied in the startup callback rather +than hw_params, as hw_params may be called too late for the constraints +to take effect properly. + +Move the channel count and format constraints for I2S and DSP_A/DSP_B +modes into a new startup callback. This also tightens the I2S mode +channel constraint from 1-2 to exactly 2, matching the actual hardware +behavior. + +Signed-off-by: Troy Mitchell +Link: https://patch.msgid.link/20260429-k3-i2s-v1-2-2fe99db11ecb@linux.spacemit.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/spacemit/k1_i2s.c | 45 ++++++++++++++++++++++++++----------- + 1 file changed, 32 insertions(+), 13 deletions(-) + +diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c +index 1cb99f1abc7cd..bb73d32a1b097 100644 +--- a/sound/soc/spacemit/k1_i2s.c ++++ b/sound/soc/spacemit/k1_i2s.c +@@ -106,6 +106,37 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) + writel(0, i2s->base + SSINTEN); + } + ++static int spacemit_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); ++ ++ switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_CHANNELS, ++ 2, 2); ++ snd_pcm_hw_constraint_mask64(substream->runtime, ++ SNDRV_PCM_HW_PARAM_FORMAT, ++ SNDRV_PCM_FMTBIT_S16_LE); ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ case SND_SOC_DAIFMT_DSP_B: ++ snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_CHANNELS, ++ 1, 1); ++ snd_pcm_hw_constraint_mask64(substream->runtime, ++ SNDRV_PCM_HW_PARAM_FORMAT, ++ SNDRV_PCM_FMTBIT_S32_LE); ++ break; ++ default: ++ dev_dbg(i2s->dev, "unexpected format type"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +@@ -157,22 +188,9 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, + dma_data->maxburst = 32; + dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + } +- +- snd_pcm_hw_constraint_minmax(substream->runtime, +- SNDRV_PCM_HW_PARAM_CHANNELS, +- 1, 2); +- snd_pcm_hw_constraint_mask64(substream->runtime, +- SNDRV_PCM_HW_PARAM_FORMAT, +- SNDRV_PCM_FMTBIT_S16_LE); + break; + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: +- snd_pcm_hw_constraint_minmax(substream->runtime, +- SNDRV_PCM_HW_PARAM_CHANNELS, +- 1, 1); +- snd_pcm_hw_constraint_mask64(substream->runtime, +- SNDRV_PCM_HW_PARAM_FORMAT, +- SNDRV_PCM_FMTBIT_S32_LE); + break; + default: + dev_dbg(i2s->dev, "unexpected format type"); +@@ -303,6 +321,7 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai) + static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { + .probe = spacemit_i2s_dai_probe, + .remove = spacemit_i2s_dai_remove, ++ .startup = spacemit_i2s_startup, + .hw_params = spacemit_i2s_hw_params, + .set_sysclk = spacemit_i2s_set_sysclk, + .set_fmt = spacemit_i2s_set_fmt, +-- +2.53.0 + diff --git a/queue-7.0/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch b/queue-7.0/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch new file mode 100644 index 0000000000..3e055af1cc --- /dev/null +++ b/queue-7.0/asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch @@ -0,0 +1,73 @@ +From 8bb7b253aa5c0fce73363932910da1aa4683b056 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 21:22:19 +0100 +Subject: ASoC: tas2552: Allow audio enable GPIO to sleep + +From: Marek Vasut + +[ Upstream commit 5ebc20921b7fff9feb44de465448e17a382c9965 ] + +The audio enable GPIO is not toggled in any critical section where it +could not sleep, allow the audio enable GPIO to sleep. This allows the +driver to operate the audio enable GPIO connected to I2C GPIO expander. + +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260220202332.241035-1-marex@nabladev.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2552.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c +index 43449d7c25843..80206c2e09462 100644 +--- a/sound/soc/codecs/tas2552.c ++++ b/sound/soc/codecs/tas2552.c +@@ -487,7 +487,7 @@ static int tas2552_runtime_suspend(struct device *dev) + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + return 0; + } +@@ -496,7 +496,7 @@ static int tas2552_runtime_resume(struct device *dev) + { + struct tas2552_data *tas2552 = dev_get_drvdata(dev); + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + tas2552_sw_shutdown(tas2552, 0); + +@@ -583,7 +583,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + return ret; + } + +- gpiod_set_value(tas2552->enable_gpio, 1); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 1); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { +@@ -608,7 +608,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) + + probe_fail: + pm_runtime_put_noidle(component->dev); +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + + regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), + tas2552->supplies); +@@ -621,7 +621,7 @@ static void tas2552_component_remove(struct snd_soc_component *component) + + pm_runtime_put(component->dev); + +- gpiod_set_value(tas2552->enable_gpio, 0); ++ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + }; + + #ifdef CONFIG_PM +-- +2.53.0 + diff --git a/queue-7.0/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch b/queue-7.0/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch new file mode 100644 index 0000000000..2b20c7674f --- /dev/null +++ b/queue-7.0/asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch @@ -0,0 +1,40 @@ +From 9946d5a7ceaaf82149dc6742dc7401327d287e07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:10:01 -0600 +Subject: ASoC: ti: davinci-mcasp: Add system suspend/resume support + +From: Sen Wang + +[ Upstream commit 5879521cb558871472b97c4744dbe634a4286f0e ] + +The McASP driver supports runtime PM callbacks for register save/restore +during device idle, but doesn't provide system suspend/resume callbacks. +This causes audio to fail to resume after system suspend. + +Since the driver already handles runtime suspend & resume, we can reuse +existing runtime PM logics. + +Signed-off-by: Sen Wang +Link: https://patch.msgid.link/20260211221001.155843-1-sen@ti.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/ti/davinci-mcasp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c +index 2d260fbc9b835..14267be4a288a 100644 +--- a/sound/soc/ti/davinci-mcasp.c ++++ b/sound/soc/ti/davinci-mcasp.c +@@ -2823,6 +2823,8 @@ static int davinci_mcasp_runtime_resume(struct device *dev) + #endif + + static const struct dev_pm_ops davinci_mcasp_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, + davinci_mcasp_runtime_resume, + NULL) +-- +2.53.0 + diff --git a/queue-7.0/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch b/queue-7.0/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch new file mode 100644 index 0000000000..9d5d2a0986 --- /dev/null +++ b/queue-7.0/ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch @@ -0,0 +1,40 @@ +From c813925be5ad1715315493379f912198d819a554 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:07:05 -0700 +Subject: ata: libata-eh: Do not retry reset if the device is gone + +From: Igor Pylypiv + +[ Upstream commit 182caa17360dd48e6df08e18f00ebda0be87ab24 ] + +If a device is hot-unplugged or otherwise disappears during error handling, +ata_eh_reset() may fail with -ENODEV. Currently, the error handler will +continue to retry the reset operation up to max_tries times. + +Prevent unnecessary reset retries by exiting the loop early when +ata_do_reset() returns -ENODEV. + +Reviewed-by: Damien Le Moal +Signed-off-by: Igor Pylypiv +Signed-off-by: Niklas Cassel +Signed-off-by: Sasha Levin +--- + drivers/ata/libata-eh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 23be85418b3b1..e97a842005e98 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -3171,7 +3171,7 @@ int ata_eh_reset(struct ata_link *link, int classify, + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + +- if (try >= max_tries) { ++ if (try >= max_tries || rc == -ENODEV) { + /* + * Thaw host port even if reset failed, so that the port + * can be retried on the next phy event. This risks +-- +2.53.0 + diff --git a/queue-7.0/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch b/queue-7.0/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch new file mode 100644 index 0000000000..9300455baa --- /dev/null +++ b/queue-7.0/blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch @@ -0,0 +1,215 @@ +From c324732d119f606ce24da59ae3665596a2595483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:05:09 +0000 +Subject: blk-iocost: fix busy_level reset when no IOs complete + +From: Jialin Wang + +[ Upstream commit f91ffe89b2016d280995a9c28d73288b02d83615 ] + +When a disk is saturated, it is common for no IOs to complete within a +timer period. Currently, in this case, rq_wait_pct and missed_ppm are +calculated as 0, the iocost incorrectly interprets this as meeting QoS +targets and resets busy_level to 0. + +This reset prevents busy_level from reaching the threshold (4) needed +to reduce vrate. On certain cloud storage, such as Azure Premium SSD, +we observed that iocost may fail to reduce vrate for tens of seconds +during saturation, failing to mitigate noisy neighbor issues. + +Fix this by tracking the number of IO completions (nr_done) in a period. +If nr_done is 0 and there are lagging IOs, the saturation status is +unknown, so we keep busy_level unchanged. + +The issue is consistently reproducible on Azure Standard_D8as_v5 (Dasv5) +VMs with 512GB Premium SSD (P20) using the script below. It was not +observed on GCP n2d VMs (with 100G pd-ssd and 1.5T local-ssd), and no +regressions were found with this patch. In this script, cgA performs +large IOs with iodepth=128, while cgB performs small IOs with iodepth=1 +rate_iops=100 rw=randrw. With iocost enabled, we expect it to throttle +cgA, the submission latency (slat) of cgA should be significantly higher, +cgB can reach 200 IOPS and the completion latency (clat) should below. + + BLK_DEVID="8:0" + MODEL="rbps=173471131 rseqiops=3566 rrandiops=3566 wbps=173333269 wseqiops=3566 wrandiops=3566" + QOS="rpct=90 rlat=3500 wpct=90 wlat=3500 min=80 max=10000" + + echo "$BLK_DEVID ctrl=user model=linear $MODEL" > /sys/fs/cgroup/io.cost.model + echo "$BLK_DEVID enable=1 ctrl=user $QOS" > /sys/fs/cgroup/io.cost.qos + + CG_A="/sys/fs/cgroup/cgA" + CG_B="/sys/fs/cgroup/cgB" + + FILE_A="/path/to/sda/A.fio.testfile" + FILE_B="/path/to/sda/B.fio.testfile" + RESULT_DIR="./iocost_results_$(date +%Y%m%d_%H%M%S)" + + mkdir -p "$CG_A" "$CG_B" "$RESULT_DIR" + + get_result() { + local file=$1 + local label=$2 + + local results=$(jq -r ' + .jobs[0].mixed | + ( .iops | tonumber | round ) as $iops | + ( .bw_bytes / 1024 / 1024 ) as $bps | + ( .slat_ns.mean / 1000000 ) as $slat | + ( .clat_ns.mean / 1000000 ) as $avg | + ( .clat_ns.max / 1000000 ) as $max | + ( .clat_ns.percentile["90.000000"] / 1000000 ) as $p90 | + ( .clat_ns.percentile["99.000000"] / 1000000 ) as $p99 | + ( .clat_ns.percentile["99.900000"] / 1000000 ) as $p999 | + ( .clat_ns.percentile["99.990000"] / 1000000 ) as $p9999 | + "\($iops)|\($bps)|\($slat)|\($avg)|\($max)|\($p90)|\($p99)|\($p999)|\($p9999)" + ' "$file") + + IFS='|' read -r iops bps slat avg max p90 p99 p999 p9999 <<<"$results" + printf "%-8s %-6s %-7.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f\n" \ + "$label" "$iops" "$bps" "$slat" "$avg" "$max" "$p90" "$p99" "$p999" "$p9999" + } + + run_fio() { + local cg_path=$1 + local filename=$2 + local name=$3 + local bs=$4 + local qd=$5 + local out=$6 + shift 6 + local extra=$@ + + ( + pid=$(sh -c 'echo $PPID') + echo $pid >"${cg_path}/cgroup.procs" + fio --name="$name" --filename="$filename" --direct=1 --rw=randrw --rwmixread=50 \ + --ioengine=libaio --bs="$bs" --iodepth="$qd" --size=4G --runtime=10 \ + --time_based --group_reporting --unified_rw_reporting=mixed \ + --output-format=json --output="$out" $extra >/dev/null 2>&1 + ) & + } + + echo "Starting Test ..." + + for bs_b in "4k" "32k" "256k"; do + echo "Running iteration: BS=$bs_b" + out_a="${RESULT_DIR}/cgA_1m.json" + out_b="${RESULT_DIR}/cgB_${bs_b}.json" + + # cgA: Heavy background (BS 1MB, QD 128) + run_fio "$CG_A" "$FILE_A" "cgA" "1m" 128 "$out_a" + # cgB: Latency sensitive (Variable BS, QD 1, Read/Write IOPS limit 100) + run_fio "$CG_B" "$FILE_B" "cgB" "$bs_b" 1 "$out_b" "--rate_iops=100" + + wait + SUMMARY_DATA+="$(get_result "$out_a" "cgA-1m")"$'\n' + SUMMARY_DATA+="$(get_result "$out_b" "cgB-$bs_b")"$'\n\n' + done + + echo -e "\nFinal Results Summary:\n" + + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n" \ + "" "" "" "slat" "clat" "clat" "clat" "clat" "clat" "clat" + printf "%-8s %-6s %-7s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n\n" \ + "CGROUP" "IOPS" "MB/s" "avg(ms)" "avg(ms)" "max(ms)" "P90(ms)" "P99" "P99.9" "P99.99" + echo "$SUMMARY_DATA" + + echo "Results saved in $RESULT_DIR" + +Before: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 166 166.37 3.44 748.95 1298.29 977.27 1233.13 1300.23 1300.23 + cgB-4k 5 0.02 0.02 181.74 761.32 742.39 759.17 759.17 759.17 + + cgA-1m 167 166.51 1.98 748.68 1549.41 809.50 1451.23 1551.89 1551.89 + cgB-32k 6 0.18 0.02 169.98 761.76 742.39 759.17 759.17 759.17 + + cgA-1m 166 165.55 2.89 750.89 1540.37 851.44 1451.23 1535.12 1535.12 + cgB-256k 5 1.30 0.02 191.35 759.51 750.78 759.17 759.17 759.17 + +After: + slat clat clat clat clat clat clat + CGROUP IOPS MB/s avg(ms) avg(ms) max(ms) P90(ms) P99 P99.9 P99.99 + + cgA-1m 162 162.48 6.14 749.69 850.02 826.28 834.67 843.06 851.44 + cgB-4k 199 0.78 0.01 1.95 42.12 2.57 7.50 34.87 42.21 + + cgA-1m 146 146.20 6.83 833.04 908.68 893.39 901.78 910.16 910.16 + cgB-32k 200 6.25 0.01 2.32 31.40 3.06 7.50 16.58 31.33 + + cgA-1m 110 110.46 9.04 1082.67 1197.91 1182.79 1199.57 1199.57 1199.57 + cgB-256k 200 49.98 0.02 3.69 22.20 4.88 9.11 20.05 22.15 + +Signed-off-by: Jialin Wang +Acked-by: Tejun Heo +Link: https://patch.msgid.link/20260331100509.182882-1-wjl.linux@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index d145db61e5c31..0cca88a366dc9 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1596,7 +1596,8 @@ static enum hrtimer_restart iocg_waitq_timer_fn(struct hrtimer *timer) + return HRTIMER_NORESTART; + } + +-static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p) ++static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p, ++ u32 *nr_done) + { + u32 nr_met[2] = { }; + u32 nr_missed[2] = { }; +@@ -1633,6 +1634,8 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_p + + *rq_wait_pct_p = div64_u64(rq_wait_ns * 100, + ioc->period_us * NSEC_PER_USEC); ++ ++ *nr_done = nr_met[READ] + nr_met[WRITE] + nr_missed[READ] + nr_missed[WRITE]; + } + + /* was iocg idle this period? */ +@@ -2250,12 +2253,12 @@ static void ioc_timer_fn(struct timer_list *timer) + u64 usage_us_sum = 0; + u32 ppm_rthr; + u32 ppm_wthr; +- u32 missed_ppm[2], rq_wait_pct; ++ u32 missed_ppm[2], rq_wait_pct, nr_done; + u64 period_vtime; + int prev_busy_level; + + /* how were the latencies during the period? */ +- ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct); ++ ioc_lat_stat(ioc, missed_ppm, &rq_wait_pct, &nr_done); + + /* take care of active iocgs */ + spin_lock_irq(&ioc->lock); +@@ -2397,9 +2400,17 @@ static void ioc_timer_fn(struct timer_list *timer) + * and should increase vtime rate. + */ + prev_busy_level = ioc->busy_level; +- if (rq_wait_pct > RQ_WAIT_BUSY_PCT || +- missed_ppm[READ] > ppm_rthr || +- missed_ppm[WRITE] > ppm_wthr) { ++ if (!nr_done && nr_lagging) { ++ /* ++ * When there are lagging IOs but no completions, we don't ++ * know if the IO latency will meet the QoS targets. The ++ * disk might be saturated or not. We should not reset ++ * busy_level to 0 (which would prevent vrate from scaling ++ * up or down), but rather to keep it unchanged. ++ */ ++ } else if (rq_wait_pct > RQ_WAIT_BUSY_PCT || ++ missed_ppm[READ] > ppm_rthr || ++ missed_ppm[WRITE] > ppm_wthr) { + /* clearly missing QoS targets, slow down vrate */ + ioc->busy_level = max(ioc->busy_level, 0); + ioc->busy_level++; +-- +2.53.0 + diff --git a/queue-7.0/block-allow-submitting-all-zone-writes-from-a-single.patch b/queue-7.0/block-allow-submitting-all-zone-writes-from-a-single.patch new file mode 100644 index 0000000000..e1757576c6 --- /dev/null +++ b/queue-7.0/block-allow-submitting-all-zone-writes-from-a-single.patch @@ -0,0 +1,643 @@ +From a063c4791697f1165d4098229f947df553f0e335 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 22:19:49 +0900 +Subject: block: allow submitting all zone writes from a single context + +From: Damien Le Moal + +[ Upstream commit 1365b6904fd050bf22ab9f3df375a396de5837a1 ] + +In order to maintain sequential write patterns per zone with zoned block +devices, zone write plugging issues only a single write BIO per zone at +any time. This works well but has the side effect that when large +sequential write streams are issued by the user and these streams cross +zone boundaries, the device ends up receiving a discontiguous set of +write commands for different zones. The same also happens when a user +writes simultaneously at high queue depth multiple zones: the device +does not see all sequential writes per zone and receives discontiguous +writes to different zones. While this does not affect the performance of +solid state zoned block devices, when using an SMR HDD, this pattern +change from sequential writes to discontiguous writes to different zones +significantly increases head seek which results in degraded write +throughput. + +In order to reduce this seek overhead for rotational media devices, +introduce a per disk zone write plugs kernel thread to issue all write +BIOs to zones. This single zone write issuing context is enabled for +any zoned block device that has a request queue flagged with the new +QUEUE_ZONED_QD1_WRITES flag. + +The flag QUEUE_ZONED_QD1_WRITES is visible as the sysfs queue attribute +zoned_qd1_writes for zoned devices. For regular block devices, this +attribute is not visible. For zoned block devices, a user can override +the default value set to force the global write maximum queue depth of +1 for a zoned block device, or clear this attribute to fallback to the +default behavior of zone write plugging which limits writes to QD=1 per +sequential zone. + +Writing to a zoned block device flagged with QUEUE_ZONED_QD1_WRITES is +implemented using a list of zone write plugs that have a non-empty BIO +list. Listed zone write plugs are processed by the disk zone write plugs +worker kthread in FIFO order, and all BIOs of a zone write plug are all +processed before switching to the next listed zone write plug. A newly +submitted BIO for a non-FULL zone write plug that is not yet listed +causes the addition of the zone write plug at the end of the disk list +of zone write plugs. + +Since the write BIOs queued in a zone write plug BIO list are +necessarilly sequential, for rotational media, using the single zone +write plugs kthread to issue all BIOs maintains a sequential write +pattern and thus reduces seek overhead and improves write throughput. +This processing essentially result in always writing to HDDs at QD=1, +which is not an issue for HDDs operating with write caching enabled. +Performance with write cache disabled is also not degraded thanks to +the efficient write handling of modern SMR HDDs. + +A disk list of zone write plugs is defined using the new struct gendisk +zone_wplugs_list, and accesses to this list is protected using the +zone_wplugs_list_lock spinlock. The per disk kthread +(zone_wplugs_worker) code is implemented by the function +disk_zone_wplugs_worker(). A reference on listed zone write plugs is +always held until all BIOs of the zone write plug are processed by the +worker kthread. BIO issuing at QD=1 is driven using a completion +structure (zone_wplugs_worker_bio_done) and calls to blk_io_wait(). + +With this change, performance when sequentially writing the zones of a +30 TB SMR SATA HDD connected to an AHCI adapter changes as follows +(1MiB direct I/Os, results in MB/s unit): + + +--------------------+ + | Write BW (MB/s) | + +------------------+----------+---------+ + | Sequential write | Baseline | Patched | + | Queue Depth | 6.19-rc8 | | + +------------------+----------+---------+ + | 1 | 244 | 245 | + | 2 | 244 | 245 | + | 4 | 245 | 245 | + | 8 | 242 | 245 | + | 16 | 222 | 246 | + | 32 | 211 | 245 | + | 64 | 193 | 244 | + | 128 | 112 | 246 | + +------------------+----------+---------+ + +With the current code (baseline), as the sequential write stream crosses +a zone boundary, higher queue depth creates a gap between the +last IO to the previous zone and the first IOs to the following zones, +causing head seeks and degrading performance. Using the disk zone +write plugs worker thread, this pattern disappears and the maximum +throughput of the drive is maintained, leading to over 100% +improvements in throughput for high queue depth write. + +Using 16 fio jobs all writing to randomly chosen zones at QD=32 with 1 +MiB direct IOs, write throughput also increases significantly. + + +--------------------+ + | Write BW (MB/s) | + +------------------+----------+---------+ + | Random write | Baseline | Patched | + | Number of zones | 6.19-rc7 | | + +------------------+----------+---------+ + | 1 | 191 | 192 | + | 2 | 101 | 128 | + | 4 | 115 | 123 | + | 8 | 90 | 120 | + | 16 | 64 | 115 | + | 32 | 58 | 105 | + | 64 | 56 | 101 | + | 128 | 55 | 99 | + +------------------+----------+---------+ + +Tests using XFS shows that buffered write speed with 8 jobs writing +files increases by 12% to 35% depending on the workload. + + +--------------------+ + | Write BW (MB/s) | + +------------------+----------+---------+ + | Workload | Baseline | Patched | + | | 6.19-rc7 | | + +------------------+----------+---------+ + | 256MiB file size | 212 | 238 | + +------------------+----------+---------+ + | 4MiB .. 128 MiB | 213 | 243 | + | random file size | | | + +------------------+----------+---------+ + | 2MiB .. 8 MiB | 179 | 242 | + | random file size | | | + +------------------+----------+---------+ + +Performance gains are even more significant when using an HBA that +limits the maximum size of commands to a small value, e.g. HBAs +controlled with the mpi3mr driver limit commands to a maximum of 1 MiB. +In such case, the write throughput gains are over 40%. + + +--------------------+ + | Write BW (MB/s) | + +------------------+----------+---------+ + | Workload | Baseline | Patched | + | | 6.19-rc7 | | + +------------------+----------+---------+ + | 256MiB file size | 175 | 245 | + +------------------+----------+---------+ + | 4MiB .. 128 MiB | 174 | 244 | + | random file size | | | + +------------------+----------+---------+ + | 2MiB .. 8 MiB | 171 | 243 | + | random file size | | | + +------------------+----------+---------+ + +Signed-off-by: Damien Le Moal +Reviewed-by: Christoph Hellwig +Reviewed-by: Bart Van Assche +Reviewed-by: Johannes Thumshirn +Signed-off-by: Jens Axboe +Stable-dep-of: 836efd35c472 ("block: fix handling of dead zone write plugs") +Signed-off-by: Sasha Levin +--- + block/blk-mq-debugfs.c | 1 + + block/blk-sysfs.c | 35 +++++++- + block/blk-zoned.c | 190 ++++++++++++++++++++++++++++++++++++----- + include/linux/blkdev.h | 8 ++ + 4 files changed, 212 insertions(+), 22 deletions(-) + +diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c +index 28167c9baa559..047ec887456b6 100644 +--- a/block/blk-mq-debugfs.c ++++ b/block/blk-mq-debugfs.c +@@ -97,6 +97,7 @@ static const char *const blk_queue_flag_name[] = { + QUEUE_FLAG_NAME(NO_ELV_SWITCH), + QUEUE_FLAG_NAME(QOS_ENABLED), + QUEUE_FLAG_NAME(BIO_ISSUE_TIME), ++ QUEUE_FLAG_NAME(ZONED_QD1_WRITES), + }; + #undef QUEUE_FLAG_NAME + +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index 55a1bbfef7d45..ca8033e6d6990 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -390,6 +390,36 @@ static ssize_t queue_nr_zones_show(struct gendisk *disk, char *page) + return queue_var_show(disk_nr_zones(disk), page); + } + ++static ssize_t queue_zoned_qd1_writes_show(struct gendisk *disk, char *page) ++{ ++ return queue_var_show(!!blk_queue_zoned_qd1_writes(disk->queue), ++ page); ++} ++ ++static ssize_t queue_zoned_qd1_writes_store(struct gendisk *disk, ++ const char *page, size_t count) ++{ ++ struct request_queue *q = disk->queue; ++ unsigned long qd1_writes; ++ unsigned int memflags; ++ ssize_t ret; ++ ++ ret = queue_var_store(&qd1_writes, page, count); ++ if (ret < 0) ++ return ret; ++ ++ memflags = blk_mq_freeze_queue(q); ++ blk_mq_quiesce_queue(q); ++ if (qd1_writes) ++ blk_queue_flag_set(QUEUE_FLAG_ZONED_QD1_WRITES, q); ++ else ++ blk_queue_flag_clear(QUEUE_FLAG_ZONED_QD1_WRITES, q); ++ blk_mq_unquiesce_queue(q); ++ blk_mq_unfreeze_queue(q, memflags); ++ ++ return count; ++} ++ + static ssize_t queue_iostats_passthrough_show(struct gendisk *disk, char *page) + { + return queue_var_show(!!blk_queue_passthrough_stat(disk->queue), page); +@@ -617,6 +647,7 @@ QUEUE_LIM_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes"); + QUEUE_LIM_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity"); + + QUEUE_LIM_RO_ENTRY(queue_zoned, "zoned"); ++QUEUE_RW_ENTRY(queue_zoned_qd1_writes, "zoned_qd1_writes"); + QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones"); + QUEUE_LIM_RO_ENTRY(queue_max_open_zones, "max_open_zones"); + QUEUE_LIM_RO_ENTRY(queue_max_active_zones, "max_active_zones"); +@@ -754,6 +785,7 @@ static struct attribute *queue_attrs[] = { + &queue_nomerges_entry.attr, + &queue_poll_entry.attr, + &queue_poll_delay_entry.attr, ++ &queue_zoned_qd1_writes_entry.attr, + + NULL, + }; +@@ -786,7 +818,8 @@ static umode_t queue_attr_visible(struct kobject *kobj, struct attribute *attr, + struct request_queue *q = disk->queue; + + if ((attr == &queue_max_open_zones_entry.attr || +- attr == &queue_max_active_zones_entry.attr) && ++ attr == &queue_max_active_zones_entry.attr || ++ attr == &queue_zoned_qd1_writes_entry.attr) && + !blk_queue_is_zoned(q)) + return 0; + +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index 2fa7f7b5f4c80..9b697043871f8 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + + #include + +@@ -40,6 +42,8 @@ static const char *const zone_cond_name[] = { + /* + * Per-zone write plug. + * @node: hlist_node structure for managing the plug using a hash table. ++ * @entry: list_head structure for listing the plug in the disk list of active ++ * zone write plugs. + * @bio_list: The list of BIOs that are currently plugged. + * @bio_work: Work struct to handle issuing of plugged BIOs + * @rcu_head: RCU head to free zone write plugs with an RCU grace period. +@@ -62,6 +66,7 @@ static const char *const zone_cond_name[] = { + */ + struct blk_zone_wplug { + struct hlist_node node; ++ struct list_head entry; + struct bio_list bio_list; + struct work_struct bio_work; + struct rcu_head rcu_head; +@@ -629,7 +634,19 @@ static void disk_mark_zone_wplug_dead(struct blk_zone_wplug *zwplug) + } + } + +-static void blk_zone_wplug_bio_work(struct work_struct *work); ++static bool disk_zone_wplug_submit_bio(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug); ++ ++static void blk_zone_wplug_bio_work(struct work_struct *work) ++{ ++ struct blk_zone_wplug *zwplug = ++ container_of(work, struct blk_zone_wplug, bio_work); ++ ++ disk_zone_wplug_submit_bio(zwplug->disk, zwplug); ++ ++ /* Drop the reference we took in disk_zone_wplug_schedule_work(). */ ++ disk_put_zone_wplug(zwplug); ++} + + /* + * Get a reference on the write plug for the zone containing @sector. +@@ -667,6 +684,7 @@ static struct blk_zone_wplug *disk_get_and_lock_zone_wplug(struct gendisk *disk, + zwplug->wp_offset = bdev_offset_from_zone_start(disk->part0, sector); + bio_list_init(&zwplug->bio_list); + INIT_WORK(&zwplug->bio_work, blk_zone_wplug_bio_work); ++ INIT_LIST_HEAD(&zwplug->entry); + zwplug->disk = disk; + + spin_lock_irqsave(&zwplug->lock, *flags); +@@ -702,6 +720,7 @@ static inline void blk_zone_wplug_bio_io_error(struct blk_zone_wplug *zwplug, + */ + static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) + { ++ struct gendisk *disk = zwplug->disk; + struct bio *bio; + + lockdep_assert_held(&zwplug->lock); +@@ -715,6 +734,20 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) + blk_zone_wplug_bio_io_error(zwplug, bio); + + zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; ++ ++ /* ++ * If we are using the per disk zone write plugs worker thread, remove ++ * the zone write plug from the work list and drop the reference we ++ * took when the zone write plug was added to that list. ++ */ ++ if (blk_queue_zoned_qd1_writes(disk->queue)) { ++ spin_lock(&disk->zone_wplugs_list_lock); ++ if (!list_empty(&zwplug->entry)) { ++ list_del_init(&zwplug->entry); ++ disk_put_zone_wplug(zwplug); ++ } ++ spin_unlock(&disk->zone_wplugs_list_lock); ++ } + } + + /* +@@ -1149,8 +1182,8 @@ void blk_zone_mgmt_bio_endio(struct bio *bio) + } + } + +-static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, +- struct blk_zone_wplug *zwplug) ++static void disk_zone_wplug_schedule_work(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug) + { + lockdep_assert_held(&zwplug->lock); + +@@ -1163,6 +1196,7 @@ static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, + * and we also drop this reference if the work is already scheduled. + */ + WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); ++ WARN_ON_ONCE(blk_queue_zoned_qd1_writes(disk->queue)); + refcount_inc(&zwplug->ref); + if (!queue_work(disk->zone_wplugs_wq, &zwplug->bio_work)) + disk_put_zone_wplug(zwplug); +@@ -1202,6 +1236,22 @@ static inline void disk_zone_wplug_add_bio(struct gendisk *disk, + bio_list_add(&zwplug->bio_list, bio); + trace_disk_zone_wplug_add_bio(zwplug->disk->queue, zwplug->zone_no, + bio->bi_iter.bi_sector, bio_sectors(bio)); ++ ++ /* ++ * If we are using the disk zone write plugs worker instead of the per ++ * zone write plug BIO work, add the zone write plug to the work list ++ * if it is not already there. Make sure to also get an extra reference ++ * on the zone write plug so that it does not go away until it is ++ * removed from the work list. ++ */ ++ if (blk_queue_zoned_qd1_writes(disk->queue)) { ++ spin_lock(&disk->zone_wplugs_list_lock); ++ if (list_empty(&zwplug->entry)) { ++ list_add_tail(&zwplug->entry, &disk->zone_wplugs_list); ++ refcount_inc(&zwplug->ref); ++ } ++ spin_unlock(&disk->zone_wplugs_list_lock); ++ } + } + + /* +@@ -1433,6 +1483,13 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + goto queue_bio; + } + ++ /* ++ * For rotational devices, we will use the gendisk zone write plugs ++ * work instead of the per zone write plug BIO work, so queue the BIO. ++ */ ++ if (blk_queue_zoned_qd1_writes(disk->queue)) ++ goto queue_bio; ++ + /* If the zone is already plugged, add the BIO to the BIO plug list. */ + if (zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) + goto queue_bio; +@@ -1455,7 +1512,10 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + + if (!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)) { + zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; +- disk_zone_wplug_schedule_bio_work(disk, zwplug); ++ if (blk_queue_zoned_qd1_writes(disk->queue)) ++ wake_up_process(disk->zone_wplugs_worker); ++ else ++ disk_zone_wplug_schedule_work(disk, zwplug); + } + + spin_unlock_irqrestore(&zwplug->lock, flags); +@@ -1596,16 +1656,22 @@ static void disk_zone_wplug_unplug_bio(struct gendisk *disk, + + spin_lock_irqsave(&zwplug->lock, flags); + +- /* Schedule submission of the next plugged BIO if we have one. */ +- if (!bio_list_empty(&zwplug->bio_list)) { +- disk_zone_wplug_schedule_bio_work(disk, zwplug); +- spin_unlock_irqrestore(&zwplug->lock, flags); +- return; +- } ++ /* ++ * For rotational devices, signal the BIO completion to the zone write ++ * plug work. Otherwise, schedule submission of the next plugged BIO ++ * if we have one. ++ */ ++ if (bio_list_empty(&zwplug->bio_list)) ++ zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; ++ ++ if (blk_queue_zoned_qd1_writes(disk->queue)) ++ complete(&disk->zone_wplugs_worker_bio_done); ++ else if (!bio_list_empty(&zwplug->bio_list)) ++ disk_zone_wplug_schedule_work(disk, zwplug); + +- zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; + if (!zwplug->wp_offset || disk_zone_wplug_is_full(disk, zwplug)) + disk_mark_zone_wplug_dead(zwplug); ++ + spin_unlock_irqrestore(&zwplug->lock, flags); + } + +@@ -1695,10 +1761,9 @@ void blk_zone_write_plug_finish_request(struct request *req) + disk_put_zone_wplug(zwplug); + } + +-static void blk_zone_wplug_bio_work(struct work_struct *work) ++static bool disk_zone_wplug_submit_bio(struct gendisk *disk, ++ struct blk_zone_wplug *zwplug) + { +- struct blk_zone_wplug *zwplug = +- container_of(work, struct blk_zone_wplug, bio_work); + struct block_device *bdev; + unsigned long flags; + struct bio *bio; +@@ -1714,7 +1779,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + if (!bio) { + zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; + spin_unlock_irqrestore(&zwplug->lock, flags); +- goto put_zwplug; ++ return false; + } + + trace_blk_zone_wplug_bio(zwplug->disk->queue, zwplug->zone_no, +@@ -1728,14 +1793,15 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + goto again; + } + +- bdev = bio->bi_bdev; +- + /* + * blk-mq devices will reuse the extra reference on the request queue + * usage counter we took when the BIO was plugged, but the submission + * path for BIO-based devices will not do that. So drop this extra + * reference here. + */ ++ if (blk_queue_zoned_qd1_writes(disk->queue)) ++ reinit_completion(&disk->zone_wplugs_worker_bio_done); ++ bdev = bio->bi_bdev; + if (bdev_test_flag(bdev, BD_HAS_SUBMIT_BIO)) { + bdev->bd_disk->fops->submit_bio(bio); + blk_queue_exit(bdev->bd_disk->queue); +@@ -1743,14 +1809,78 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + blk_mq_submit_bio(bio); + } + +-put_zwplug: +- /* Drop the reference we took in disk_zone_wplug_schedule_bio_work(). */ +- disk_put_zone_wplug(zwplug); ++ return true; ++} ++ ++static struct blk_zone_wplug *disk_get_zone_wplugs_work(struct gendisk *disk) ++{ ++ struct blk_zone_wplug *zwplug; ++ ++ spin_lock_irq(&disk->zone_wplugs_list_lock); ++ zwplug = list_first_entry_or_null(&disk->zone_wplugs_list, ++ struct blk_zone_wplug, entry); ++ if (zwplug) ++ list_del_init(&zwplug->entry); ++ spin_unlock_irq(&disk->zone_wplugs_list_lock); ++ ++ return zwplug; ++} ++ ++static int disk_zone_wplugs_worker(void *data) ++{ ++ struct gendisk *disk = data; ++ struct blk_zone_wplug *zwplug; ++ unsigned int noio_flag; ++ ++ noio_flag = memalloc_noio_save(); ++ set_user_nice(current, MIN_NICE); ++ set_freezable(); ++ ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE | TASK_FREEZABLE); ++ ++ zwplug = disk_get_zone_wplugs_work(disk); ++ if (zwplug) { ++ /* ++ * Process all BIOs of this zone write plug and then ++ * drop the reference we took when adding the zone write ++ * plug to the active list. ++ */ ++ set_current_state(TASK_RUNNING); ++ while (disk_zone_wplug_submit_bio(disk, zwplug)) ++ blk_wait_io(&disk->zone_wplugs_worker_bio_done); ++ disk_put_zone_wplug(zwplug); ++ continue; ++ } ++ ++ /* ++ * Only sleep if nothing sets the state to running. Else check ++ * for zone write plugs work again as a newly submitted BIO ++ * might have added a zone write plug to the work list. ++ */ ++ if (get_current_state() == TASK_RUNNING) { ++ try_to_freeze(); ++ } else { ++ if (kthread_should_stop()) { ++ set_current_state(TASK_RUNNING); ++ break; ++ } ++ schedule(); ++ } ++ } ++ ++ WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list)); ++ memalloc_noio_restore(noio_flag); ++ ++ return 0; + } + + void disk_init_zone_resources(struct gendisk *disk) + { + spin_lock_init(&disk->zone_wplugs_hash_lock); ++ spin_lock_init(&disk->zone_wplugs_list_lock); ++ INIT_LIST_HEAD(&disk->zone_wplugs_list); ++ init_completion(&disk->zone_wplugs_worker_bio_done); + } + + /* +@@ -1766,6 +1896,7 @@ static int disk_alloc_zone_resources(struct gendisk *disk, + unsigned int pool_size) + { + unsigned int i; ++ int ret = -ENOMEM; + + atomic_set(&disk->nr_zone_wplugs, 0); + disk->zone_wplugs_hash_bits = +@@ -1791,8 +1922,21 @@ static int disk_alloc_zone_resources(struct gendisk *disk, + if (!disk->zone_wplugs_wq) + goto destroy_pool; + ++ disk->zone_wplugs_worker = ++ kthread_create(disk_zone_wplugs_worker, disk, ++ "%s_zwplugs_worker", disk->disk_name); ++ if (IS_ERR(disk->zone_wplugs_worker)) { ++ ret = PTR_ERR(disk->zone_wplugs_worker); ++ disk->zone_wplugs_worker = NULL; ++ goto destroy_wq; ++ } ++ wake_up_process(disk->zone_wplugs_worker); ++ + return 0; + ++destroy_wq: ++ destroy_workqueue(disk->zone_wplugs_wq); ++ disk->zone_wplugs_wq = NULL; + destroy_pool: + mempool_destroy(disk->zone_wplugs_pool); + disk->zone_wplugs_pool = NULL; +@@ -1800,7 +1944,7 @@ static int disk_alloc_zone_resources(struct gendisk *disk, + kfree(disk->zone_wplugs_hash); + disk->zone_wplugs_hash = NULL; + disk->zone_wplugs_hash_bits = 0; +- return -ENOMEM; ++ return ret; + } + + static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk) +@@ -1850,6 +1994,10 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond) + + void disk_free_zone_resources(struct gendisk *disk) + { ++ if (disk->zone_wplugs_worker) ++ kthread_stop(disk->zone_wplugs_worker); ++ WARN_ON_ONCE(!list_empty(&disk->zone_wplugs_list)); ++ + if (disk->zone_wplugs_wq) { + destroy_workqueue(disk->zone_wplugs_wq); + disk->zone_wplugs_wq = NULL; +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 6890900237707..ac899cd0cd708 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -204,6 +205,10 @@ struct gendisk { + struct mempool *zone_wplugs_pool; + struct hlist_head *zone_wplugs_hash; + struct workqueue_struct *zone_wplugs_wq; ++ spinlock_t zone_wplugs_list_lock; ++ struct list_head zone_wplugs_list; ++ struct task_struct *zone_wplugs_worker; ++ struct completion zone_wplugs_worker_bio_done; + #endif /* CONFIG_BLK_DEV_ZONED */ + + #if IS_ENABLED(CONFIG_CDROM) +@@ -668,6 +673,7 @@ enum { + QUEUE_FLAG_NO_ELV_SWITCH, /* can't switch elevator any more */ + QUEUE_FLAG_QOS_ENABLED, /* qos is enabled */ + QUEUE_FLAG_BIO_ISSUE_TIME, /* record bio->issue_time_ns */ ++ QUEUE_FLAG_ZONED_QD1_WRITES, /* Limit zoned devices writes to QD=1 */ + QUEUE_FLAG_MAX + }; + +@@ -707,6 +713,8 @@ void blk_queue_flag_clear(unsigned int flag, struct request_queue *q); + test_bit(QUEUE_FLAG_DISABLE_WBT_DEF, &(q)->queue_flags) + #define blk_queue_no_elv_switch(q) \ + test_bit(QUEUE_FLAG_NO_ELV_SWITCH, &(q)->queue_flags) ++#define blk_queue_zoned_qd1_writes(q) \ ++ test_bit(QUEUE_FLAG_ZONED_QD1_WRITES, &(q)->queue_flags) + + extern void blk_set_pm_only(struct request_queue *q); + extern void blk_clear_pm_only(struct request_queue *q); +-- +2.53.0 + diff --git a/queue-7.0/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch b/queue-7.0/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch new file mode 100644 index 0000000000..0ad2dd18c8 --- /dev/null +++ b/queue-7.0/block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch @@ -0,0 +1,72 @@ +From d785e0d928365df9c6543b2bcbdd57ce0c273aa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 01:09:29 -0400 +Subject: block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user() + +From: Sungwoo Kim + +[ Upstream commit 8582792cf23b3d94674d4d838f7cde9a28d0fcaf ] + +pin_user_pages_fast() can partially succeed and return the number of +pages that were actually pinned. However, the bio_integrity_map_user() +does not handle this partial pinning. This leads to a general protection +fault since bvec_from_pages() dereferences an unpinned page address, +which is 0. + +To fix this, add a check to verify that all requested memory is pinned. +If partial pinning occurs, unpin the memory and return -EFAULT. + +Kernel Oops: + +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI +KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] +CPU: 0 UID: 0 PID: 1061 Comm: nvme-passthroug Not tainted 7.0.0-11783-g90957f9314e8-dirty #16 PREEMPT(lazy) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 +RIP: 0010:bio_integrity_map_user.cold+0x1b0/0x9d6 + +Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers") +Acked-by: Chao Shi +Acked-by: Weidong Zhu +Acked-by: Dave Tian +Signed-off-by: Sungwoo Kim +Tested-by: Shin'ichiro Kawasaki +Link: https://github.com/linux-blktests/blktests/pull/244 +Link: https://patch.msgid.link/20260512050929.541397-2-iam@sung-woo.kim +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index 5a316d8bc5efa..d6c9a09a8dc6e 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -338,6 +338,24 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter) + if (unlikely(ret < 0)) + goto free_bvec; + ++ /* ++ * Handle partial pinning. This can happen when pin_user_pages_fast() ++ * returns fewer pages than requested. ++ */ ++ if (user_backed_iter(iter) && unlikely(ret != bytes)) { ++ if (ret > 0) { ++ int npinned = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ int i; ++ ++ for (i = 0; i < npinned; i++) ++ unpin_user_page(pages[i]); ++ } ++ if (pages != stack_pages) ++ kvfree(pages); ++ ret = -EFAULT; ++ goto free_bvec; ++ } ++ + nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset, + &is_p2p); + if (pages != stack_pages) +-- +2.53.0 + diff --git a/queue-7.0/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch b/queue-7.0/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch new file mode 100644 index 0000000000..0b1b828a3b --- /dev/null +++ b/queue-7.0/block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch @@ -0,0 +1,43 @@ +From 6685066e1faa98134e683fbff4c5ef8c1a92d402 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 22:51:51 +0100 +Subject: block: don't overwrite bip_vcnt in bio_integrity_copy_user() + +From: David Carlier + +[ Upstream commit 637ad3a56a3b889527d1dacea6fea2a8bd648140 ] + +bio_integrity_add_page() already sets bip_vcnt to 1 for the bounce +segment. Overwriting it with nr_vecs breaks bip_vcnt <= bip_max_vcnt +on WRITE (bip_max_vcnt is 1), so the gap-merge checks in block/blk.h +read past the bip_vec[] flex array. On READ the read is in bounds +but lands on a saved user bvec instead of the bounce. + +The line was added for split propagation, but bio_integrity_clone() +doesn't copy bip_vcnt and BIP_CLONE_FLAGS excludes BIP_COPY_USER. + +Fixes: 3991657ae707 ("block: set bip_vcnt correctly") +Signed-off-by: David Carlier +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511215151.346228-1-devnexen@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio-integrity.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index a319362217037..5a316d8bc5efa 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -244,7 +244,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + } + + bip->bip_flags |= BIP_COPY_USER; +- bip->bip_vcnt = nr_vecs; + return 0; + free_bip: + bio_integrity_free(bio); +-- +2.53.0 + diff --git a/queue-7.0/block-fix-handling-of-dead-zone-write-plugs.patch b/queue-7.0/block-fix-handling-of-dead-zone-write-plugs.patch new file mode 100644 index 0000000000..9c3c16a281 --- /dev/null +++ b/queue-7.0/block-fix-handling-of-dead-zone-write-plugs.patch @@ -0,0 +1,104 @@ +From 511ebe3dee8fb6afb6767a6cc4eaa168cbd77424 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 20:11:29 +0900 +Subject: block: fix handling of dead zone write plugs + +From: Damien Le Moal + +[ Upstream commit 836efd35c472d89c838d7b17ef339ddb3286ffc5 ] + +Shin'ichiro reported hard to reproduce unaligned write errors with zoned +block devices. Under normal operation conditions (e.g. running XFS on an +SMR disk), these errors are nearly impossible to trigger. But using a +"slow" kernel with many debug options enables and some specific use +cases (e.g. fio zbd test case 46), the errors can be reproduced fairly +easily. + +The unaligned write errors come from mishandling a valid reference +counting pattern of zone write plugs. Such pattern triggers for instance +if a process A writes a zone (not necessarilly to the full state), +another process B immediately resets the zone and immediately following +the completion of the zone reset, starts issuing writes to the zone. +With such pattern, in some cases, the zone write plugs worker thread of +the device may still be holding a reference to the zone write plug of +the zone taken when process A was writing to the zone. The following +zone reset from process B marks the zone as dead but does not remove the +zone write plug from the device hash table as a reference to the plug +still exist. Once process B starts issuing new writes, the zone write +plug is seen as dead and the writes from process B are immediately +failed, despite this write pattern being perfectly legal. + +Fix this by allowing restoring a dead zone write plug to a live state if +a write is issued to the zone when the zone is: marked as dead, empty +and the write sector corresponds to the first sector of the zone (that +is, the write is aligned to the zone write pointer). This is done with +the new helper function disk_check_zone_wplug_dead(), which restores a +dead zone write plug to a live state by clearing the BLK_ZONE_WPLUG_DEAD +flag and restoring the initial reference to the zone write plug taken +when the plug was added to the device hash table. + +Reported-by: Shin'ichiro Kawasaki +Fixes: b7d4ffb51037 ("block: fix zone write plug removal") +Signed-off-by: Damien Le Moal +Tested-by: Shin'ichiro Kawasaki +Link: https://patch.msgid.link/20260513111129.108809-1-dlemoal@kernel.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-zoned.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index 9b697043871f8..af724ce650801 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -634,6 +634,28 @@ static void disk_mark_zone_wplug_dead(struct blk_zone_wplug *zwplug) + } + } + ++static inline bool disk_check_zone_wplug_dead(struct blk_zone_wplug *zwplug) ++{ ++ if (!(zwplug->flags & BLK_ZONE_WPLUG_DEAD)) ++ return false; ++ ++ /* ++ * If a new write is received right after a zone reset completes and ++ * while the disk_zone_wplugs_worker() thread has not yet released the ++ * reference on the zone write plug after processing the last write to ++ * the zone, then the new write BIO will see the zone write plug marked ++ * as dead. This case is however a false positive and a perfectly valid ++ * pattern. In such case, restore the zone write plug to a live one. ++ */ ++ if (!zwplug->wp_offset && bio_list_empty(&zwplug->bio_list)) { ++ zwplug->flags &= ~BLK_ZONE_WPLUG_DEAD; ++ refcount_inc(&zwplug->ref); ++ return false; ++ } ++ ++ return true; ++} ++ + static bool disk_zone_wplug_submit_bio(struct gendisk *disk, + struct blk_zone_wplug *zwplug); + +@@ -1459,12 +1481,12 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) + } + + /* +- * If we got a zone write plug marked as dead, then the user is issuing +- * writes to a full zone, or without synchronizing with zone reset or +- * zone finish operations. In such case, fail the BIO to signal this +- * invalid usage. ++ * Check if we got a zone write plug marked as dead. If yes, then the ++ * user is likely issuing writes to a full zone, or without ++ * synchronizing with zone reset or zone finish operations. In such ++ * case, fail the BIO to signal this invalid usage. + */ +- if (zwplug->flags & BLK_ZONE_WPLUG_DEAD) { ++ if (disk_check_zone_wplug_dead(zwplug)) { + spin_unlock_irqrestore(&zwplug->lock, flags); + disk_put_zone_wplug(zwplug); + bio_io_error(bio); +-- +2.53.0 + diff --git a/queue-7.0/block-recompute-nr_integrity_segments-in-blk_insert_.patch b/queue-7.0/block-recompute-nr_integrity_segments-in-blk_insert_.patch new file mode 100644 index 0000000000..63ad86c6a1 --- /dev/null +++ b/queue-7.0/block-recompute-nr_integrity_segments-in-blk_insert_.patch @@ -0,0 +1,82 @@ +From 0a58604f175a24d2c2b4865106964219b4f88d13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 15:22:30 -0600 +Subject: block: recompute nr_integrity_segments in blk_insert_cloned_request + +From: Casey Chen + +[ Upstream commit 2c6e6a18a37b905cb584eb0dda3ae482162a81ca ] + +blk_insert_cloned_request() already recomputes nr_phys_segments +against the bottom queue, because "the queue settings related to +segment counting may differ from the original queue." The exact same +reasoning applies to integrity segments: a stacked driver's underlying +queue can have tighter virt_boundary_mask, seg_boundary_mask, or +max_segment_size than the top queue, in which case +blk_rq_count_integrity_sg() against the bottom queue produces a +different count than the cached rq->nr_integrity_segments inherited +from the source request by blk_rq_prep_clone(). + +When the cached count is lower than the bottom queue's actual count, +blk_rq_map_integrity_sg() trips + + BUG_ON(segments > rq->nr_integrity_segments); + +on dispatch. The same families of stacked setups that motivated the +existing nr_phys_segments recompute -- dm-multipath fanning out to +nvme-rdma in particular -- can produce this. + +Mirror the nr_phys_segments handling: when the request carries +integrity, recompute nr_integrity_segments against the bottom queue +and reject the request if it exceeds the bottom queue's +max_integrity_segments. blk_rq_count_integrity_sg() and +queue_max_integrity_segments() are both already available via +, which blk-mq.c includes. + +This closes a latent gap in the stacking contract and brings the +integrity-segment accounting in line with the existing +phys-segment accounting. + +Fixes: 76c313f658d2 ("blk-integrity: improved sg segment mapping") +Signed-off-by: Casey Chen +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260511212230.27511-1-cachen@purestorage.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-mq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 3da2215b29125..7a7d8d536841d 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3305,6 +3305,25 @@ blk_status_t blk_insert_cloned_request(struct request *rq) + return BLK_STS_IOERR; + } + ++ /* ++ * Integrity segment counting depends on the same queue limits ++ * (virt_boundary_mask, seg_boundary_mask, max_segment_size) that ++ * vary across stacked queues, so recompute against the bottom ++ * queue just like nr_phys_segments above. ++ */ ++ if (blk_integrity_rq(rq) && rq->bio) { ++ unsigned short max_int_segs = queue_max_integrity_segments(q); ++ ++ rq->nr_integrity_segments = ++ blk_rq_count_integrity_sg(rq->q, rq->bio); ++ if (rq->nr_integrity_segments > max_int_segs) { ++ printk(KERN_ERR "%s: over max integrity segments limit. (%u > %u)\n", ++ __func__, rq->nr_integrity_segments, ++ max_int_segs); ++ return BLK_STS_IOERR; ++ } ++ } ++ + if (q->disk && should_fail_request(q->disk->part0, blk_rq_bytes(rq))) + return BLK_STS_IOERR; + +-- +2.53.0 + diff --git a/queue-7.0/block-reject-zero-length-in-bio_add_page.patch b/queue-7.0/block-reject-zero-length-in-bio_add_page.patch new file mode 100644 index 0000000000..796dee3d40 --- /dev/null +++ b/queue-7.0/block-reject-zero-length-in-bio_add_page.patch @@ -0,0 +1,70 @@ +From 2058cdccdcefa8d0f06a78e8b5d539c42bc39472 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 18:36:34 +1030 +Subject: block: reject zero length in bio_add_page() + +From: Qu Wenruo + +[ Upstream commit 643893647cac7317bafca4040dd0cfb815b510d4 ] + +The function bio_add_page() returns the number of bytes added to the +bio, and if that failed it should return 0. + +However there is a special quirk, if a caller is passing a page with +length 0, that function will always return 0 but with different results: + +- The page is added to the bio + If there is enough bvec slot or the folio can be merged with the last + bvec. + + The return value 0 is just the length passed in, which is also 0. + +- The page is not added to the bio + If the page is not mergeable with the last bvec, or there is no bvec + slot available. + + The return value 0 means page is not added into the bio. + +Unfortunately the caller is not able to distinguish the above two cases, +and will treat the 0 return value as page addition failure. + +In that case, this can lead to the double releasing of the last page: + +- By the bio cleanup + Which normally goes through every page of the bio, including the last + page which is added into the bio. + +- By the caller + Which believes the page is not added into the bio, thus would manually + release the page. + +I do not think anyone should call bio_add_folio()/bio_add_page() with zero +length, but idiots like me can still show up. + +So add an extra WARN_ON_ONCE() check for zero length and rejects it +early to avoid double freeing. + +Signed-off-by: Qu Wenruo +Link: https://patch.msgid.link/bc2223c080f38d0b63f968f605c918181c840f40.1773734749.git.wqu@suse.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/block/bio.c b/block/bio.c +index 3acd216bbc2ee..309e1f8dad94e 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -1064,6 +1064,8 @@ int bio_add_page(struct bio *bio, struct page *page, + { + if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) + return 0; ++ if (WARN_ON_ONCE(len == 0)) ++ return 0; + if (bio->bi_iter.bi_size > BIO_MAX_SIZE - len) + return 0; + +-- +2.53.0 + diff --git a/queue-7.0/block-rename-struct-gendisk-zone_wplugs_lock-field.patch b/queue-7.0/block-rename-struct-gendisk-zone_wplugs_lock-field.patch new file mode 100644 index 0000000000..cde238b638 --- /dev/null +++ b/queue-7.0/block-rename-struct-gendisk-zone_wplugs_lock-field.patch @@ -0,0 +1,118 @@ +From be4aeea7802ad181385bb04bbce99d2496a908e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 22:19:48 +0900 +Subject: block: rename struct gendisk zone_wplugs_lock field + +From: Damien Le Moal + +[ Upstream commit b7cbc30e93e3a64ea058230f6d0c764d6d80276f ] + +Rename struct gendisk zone_wplugs_lock field to zone_wplugs_hash_lock to +clearly indicates that this is the spinlock used for manipulating the +hash table of zone write plugs. + +Signed-off-by: Damien Le Moal +Reviewed-by: Hannes Reinecke +Reviewed-by: Johannes Thumshirn +Reviewed-by: Christoph Hellwig +Reviewed-by: Bart Van Assche +Signed-off-by: Jens Axboe +Stable-dep-of: 836efd35c472 ("block: fix handling of dead zone write plugs") +Signed-off-by: Sasha Levin +--- + block/blk-zoned.c | 23 ++++++++++++----------- + include/linux/blkdev.h | 2 +- + 2 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index a4d82342e37ac..2fa7f7b5f4c80 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -520,10 +520,11 @@ static bool disk_insert_zone_wplug(struct gendisk *disk, + * are racing with other submission context, so we may already have a + * zone write plug for the same zone. + */ +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); ++ spin_lock_irqsave(&disk->zone_wplugs_hash_lock, flags); + hlist_for_each_entry_rcu(zwplg, &disk->zone_wplugs_hash[idx], node) { + if (zwplg->zone_no == zwplug->zone_no) { +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); ++ spin_unlock_irqrestore(&disk->zone_wplugs_hash_lock, ++ flags); + return false; + } + } +@@ -535,7 +536,7 @@ static bool disk_insert_zone_wplug(struct gendisk *disk, + * necessarilly in the active condition. + */ + zones_cond = rcu_dereference_check(disk->zones_cond, +- lockdep_is_held(&disk->zone_wplugs_lock)); ++ lockdep_is_held(&disk->zone_wplugs_hash_lock)); + if (zones_cond) + zwplug->cond = zones_cond[zwplug->zone_no]; + else +@@ -543,7 +544,7 @@ static bool disk_insert_zone_wplug(struct gendisk *disk, + + hlist_add_head_rcu(&zwplug->node, &disk->zone_wplugs_hash[idx]); + atomic_inc(&disk->nr_zone_wplugs); +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); ++ spin_unlock_irqrestore(&disk->zone_wplugs_hash_lock, flags); + + return true; + } +@@ -596,13 +597,13 @@ static void disk_free_zone_wplug(struct blk_zone_wplug *zwplug) + WARN_ON_ONCE(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED); + WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list)); + +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); ++ spin_lock_irqsave(&disk->zone_wplugs_hash_lock, flags); + blk_zone_set_cond(rcu_dereference_check(disk->zones_cond, +- lockdep_is_held(&disk->zone_wplugs_lock)), ++ lockdep_is_held(&disk->zone_wplugs_hash_lock)), + zwplug->zone_no, zwplug->cond); + hlist_del_init_rcu(&zwplug->node); + atomic_dec(&disk->nr_zone_wplugs); +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); ++ spin_unlock_irqrestore(&disk->zone_wplugs_hash_lock, flags); + + call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu); + } +@@ -1749,7 +1750,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) + + void disk_init_zone_resources(struct gendisk *disk) + { +- spin_lock_init(&disk->zone_wplugs_lock); ++ spin_lock_init(&disk->zone_wplugs_hash_lock); + } + + /* +@@ -1839,10 +1840,10 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond) + { + unsigned long flags; + +- spin_lock_irqsave(&disk->zone_wplugs_lock, flags); ++ spin_lock_irqsave(&disk->zone_wplugs_hash_lock, flags); + zones_cond = rcu_replace_pointer(disk->zones_cond, zones_cond, +- lockdep_is_held(&disk->zone_wplugs_lock)); +- spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); ++ lockdep_is_held(&disk->zone_wplugs_hash_lock)); ++ spin_unlock_irqrestore(&disk->zone_wplugs_hash_lock, flags); + + kfree_rcu_mightsleep(zones_cond); + } +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index d463b9b5a0a59..6890900237707 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -200,7 +200,7 @@ struct gendisk { + u8 __rcu *zones_cond; + unsigned int zone_wplugs_hash_bits; + atomic_t nr_zone_wplugs; +- spinlock_t zone_wplugs_lock; ++ spinlock_t zone_wplugs_hash_lock; + struct mempool *zone_wplugs_pool; + struct hlist_head *zone_wplugs_hash; + struct workqueue_struct *zone_wplugs_wq; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch b/queue-7.0/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch new file mode 100644 index 0000000000..1d08349ae8 --- /dev/null +++ b/queue-7.0/bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch @@ -0,0 +1,36 @@ +From 8d1535af73a0ba91c1cc101f77fdea2b2de76576 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 18:11:48 +0100 +Subject: Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth + +From: Marek Vasut + +[ Upstream commit 04c217a7fc8f23a1c99b014cb6a89cf77ac7a012 ] + +This patch adds the device ID for the BCM4343A2 module, found e.g. +in the muRata 1YN WiFi+BT combined device. The required firmware +file is named 'BCM4343A2.hcd'. + +Signed-off-by: Marek Vasut +Reviewed-by: Paul Menzel +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index d33cc70eec662..975b73cd04e67 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -507,6 +507,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x6119, "BCM4345C0" }, /* 003.001.025 */ + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ ++ { 0x2310, "BCM4343A2" }, /* 001.003.016 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btmtk-add-mt7902-mcu-support.patch b/queue-7.0/bluetooth-btmtk-add-mt7902-mcu-support.patch new file mode 100644 index 0000000000..f2af71dcc3 --- /dev/null +++ b/queue-7.0/bluetooth-btmtk-add-mt7902-mcu-support.patch @@ -0,0 +1,47 @@ +From 9fa9f1a9005f027e38b84107e7129bda59aa9ae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:19 -0600 +Subject: Bluetooth: btmtk: add MT7902 MCU support + +From: Sean Wang + +[ Upstream commit aab25984e55972e53f3e58821cb85a7101876056 ] + +Add MT7902 device ID and firmware filename to enable MCU firmware +loading. + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 1 + + drivers/bluetooth/btmtk.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index 0e44265127474..3d04c325864b5 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -1343,6 +1343,7 @@ int btmtk_usb_setup(struct hci_dev *hdev) + case 0x7922: + case 0x7925: + case 0x7961: ++ case 0x7902: + btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id, + fw_version, fw_flavor); + +diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h +index 5df7c32966247..b4506186b2f70 100644 +--- a/drivers/bluetooth/btmtk.h ++++ b/drivers/bluetooth/btmtk.h +@@ -5,6 +5,7 @@ + #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" + #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" + #define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin" ++#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin" + #define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" + #define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" + +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch b/queue-7.0/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch new file mode 100644 index 0000000000..2a16177957 --- /dev/null +++ b/queue-7.0/bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch @@ -0,0 +1,40 @@ +From 769d09f0d84c9293c506ed0d52edb021fc6d9747 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 14:25:08 +0800 +Subject: Bluetooth: btmtk: improve mt79xx firmware setup retry flow + +From: Chris Lu + +[ Upstream commit 54f1f020e9f4a087779cc4d96a7c86f47d0c6797 ] + +If retries are exhausted, driver should not do futher operation. +During mt79xx firmware download process, if the retry count reaches0, +driver will return an -EIO error and release the firmware resources. + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtk.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index a4b4dacfd2ad3..0e44265127474 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -205,6 +205,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, + } + } + ++ /* If retry exhausted goto err_release_fw */ ++ if (retry == 0) { ++ err = -EIO; ++ goto err_release_fw; ++ } ++ + fw_ptr += section_offset; + wmt_params.op = BTMTK_WMT_PATCH_DWNLD; + wmt_params.status = NULL; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch b/queue-7.0/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch new file mode 100644 index 0000000000..4aece47970 --- /dev/null +++ b/queue-7.0/bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch @@ -0,0 +1,56 @@ +From 99f306b58138820cebb0b0428420f75bee521141 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 20:32:09 +0100 +Subject: Bluetooth: btusb: Add Lite-On 04ca:3807 for MediaTek MT7921 + +From: Dylan Eray + +[ Upstream commit 67377cd38b89ce782ccdb83bda3f65a2def843cd ] + +Add USB device ID (04ca:3807) for a Lite-On Wireless_Device containing +a MediaTek MT7921 (MT7920) Bluetooth chipset found in Acer laptops. + +Without this entry, btusb binds via the generic USB class-based wildcard +match but never sets the BTUSB_MEDIATEK flag. This means btmtk never +triggers firmware loading, and the driver sends a raw HCI Reset that +the uninitialized chip cannot respond to, resulting in: + + Bluetooth: hci0: Opcode 0x0c03 failed: -110 + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below: + +T: Bus=03 Lev=01 Prnt=01 Port=09 Cnt=01 Dev#=5 Spd=480 MxCh=0 +P: Vendor=04ca ProdID=3807 Rev=1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C: #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) + +Reviewed-by: Paul Menzel +Signed-off-by: Dylan Eray +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index aeba026bdb427..d07db8e3a79d5 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -707,6 +707,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x04ca, 0x3807), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch b/queue-7.0/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch new file mode 100644 index 0000000000..30929d406d --- /dev/null +++ b/queue-7.0/bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch @@ -0,0 +1,79 @@ +From 0fa6edd7b59e6f0ca88c067eb72685d647d8a955 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 00:13:20 -0600 +Subject: Bluetooth: btusb: Add new VID/PID 13d3/3579 for MT7902 + +From: Sean Wang + +[ Upstream commit 51c4173b89fe7399bad1381016096cc154588660 ] + +Add VID 13d3 & PID 3579 for MediaTek MT7902 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=04 Dev#= 7 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=13d3 ProdID=3579 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Sean Wang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d07db8e3a79d5..1acc07d0dc061 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -671,7 +671,9 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +- ++ /* MediaTek MT7902 Bluetooth devices */ ++ { USB_DEVICE(0x13d3, 0x3579), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + /* MediaTek MT7922 Bluetooth devices */ + { USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch b/queue-7.0/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch new file mode 100644 index 0000000000..8237a5ac4a --- /dev/null +++ b/queue-7.0/bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch @@ -0,0 +1,46 @@ +From cb7a92cbd53aa7514f4401ab1331f892a2f3e84d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:53:01 +0900 +Subject: Bluetooth: btusb: MediaTek MT7922: Add VID 0489 & PID e11d + +From: Kamiyama Chiaki + +[ Upstream commit 5e17010bfc7e6820a5004f1e06d08db886e3927e ] + +Add VID 0489 & PID e11d for MediaTek MT7922 USB Bluetooth chip. +Found in Dynabook GA/ZY (W6GAZY5RCL). + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e11d Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 + +Reviewed-by: Paul Menzel +Signed-off-by: Kamiyama Chiaki +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 1acc07d0dc061..5672f0ac27557 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -699,6 +699,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe11d), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe152), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch b/queue-7.0/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch new file mode 100644 index 0000000000..fb9a461622 --- /dev/null +++ b/queue-7.0/bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch @@ -0,0 +1,77 @@ +From d766d9d73150006acd33c7225eb8147956117ce1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:13:56 +0800 +Subject: Bluetooth: btusb: MT7922: Add VID/PID 0489/e174 + +From: Chris Lu + +[ Upstream commit 1f2ac009d3e06380400618e777c858e582872efa ] + +Add VID 0489 & PID e174 for MediaTek MT7922 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=06 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e174 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I: If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I:* If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Chris Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 5c535f3ab7228..aeba026bdb427 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -703,6 +703,8 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe174), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch b/queue-7.0/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch new file mode 100644 index 0000000000..e08681dcbf --- /dev/null +++ b/queue-7.0/bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch @@ -0,0 +1,68 @@ +From cf98fdf590fc56dd3ab8c1824d8e292eaf998d08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:47:03 +0200 +Subject: Bluetooth: hci_ll: Enable BROKEN_ENHANCED_SETUP_SYNC_CONN for WL183x + +From: Stefano Radaelli + +[ Upstream commit 1c0bc11cd445ba8235ac8ec87d5999b6769ed8b9 ] + +TI WL183x controllers advertise support for the HCI Enhanced Setup +Synchronous Connection command, but SCO setup fails when the enhanced +path is used. The only working configuration is to fall back to the +legacy HCI Setup Synchronous Connection (0x0028). + +This matches the scenario described in commit 05abad857277 +("Bluetooth: HCI: Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk"). + +Enable HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN automatically for +devices compatible with: + - ti,wl1831-st + - ti,wl1835-st + - ti,wl1837-st + +Signed-off-by: Stefano Radaelli +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ll.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c +index 91c96ad123422..ab744001dafc4 100644 +--- a/drivers/bluetooth/hci_ll.c ++++ b/drivers/bluetooth/hci_ll.c +@@ -68,6 +68,7 @@ struct ll_device { + struct gpio_desc *enable_gpio; + struct clk *ext_clk; + bdaddr_t bdaddr; ++ bool broken_enhanced_setup; + }; + + struct ll_struct { +@@ -658,6 +659,10 @@ static int ll_setup(struct hci_uart *hu) + hci_set_quirk(hu->hdev, HCI_QUIRK_INVALID_BDADDR); + } + ++ if (lldev->broken_enhanced_setup) ++ hci_set_quirk(hu->hdev, ++ HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN); ++ + /* Operational speed if any */ + if (hu->oper_speed) + speed = hu->oper_speed; +@@ -712,6 +717,11 @@ static int hci_ti_probe(struct serdev_device *serdev) + of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); + hci_uart_set_speeds(hu, 115200, max_speed); + ++ if (of_device_is_compatible(serdev->dev.of_node, "ti,wl1831-st") || ++ of_device_is_compatible(serdev->dev.of_node, "ti,wl1835-st") || ++ of_device_is_compatible(serdev->dev.of_node, "ti,wl1837-st")) ++ lldev->broken_enhanced_setup = true; ++ + /* optional BD address from nvram */ + bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address"); + if (IS_ERR(bdaddr_cell)) { +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch b/queue-7.0/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch new file mode 100644 index 0000000000..fa48ea0fbf --- /dev/null +++ b/queue-7.0/bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch @@ -0,0 +1,43 @@ +From 1213933bb809a07f775a9acee604e6144f415905 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:16 +0800 +Subject: Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is + not defined + +From: Shuai Zhang + +[ Upstream commit 7b75867803a8712bdf7683c31d71d3d5e28ce821 ] + +On platforms using an M.2 slot with both UART and USB support, bt_en is +pulled high by hardware. In this case, software-based power control +should be disabled. The current platforms are Lemans-EVK and Monaco-EVK. + +Add QCA_WCN7850 to the existing condition so that power_ctrl_enabled is +cleared when bt_en is not software-controlled (or absent), aligning its +behavior with WCN6750 and WCN6855 + +Signed-off-by: Shuai Zhang +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index bb9f002aa85e9..edc907c4e870a 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2471,7 +2471,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + if (!qcadev->bt_en && + (data->soc_type == QCA_WCN6750 || +- data->soc_type == QCA_WCN6855)) ++ data->soc_type == QCA_WCN6855 || ++ data->soc_type == QCA_WCN7850)) + power_ctrl_enabled = false; + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch b/queue-7.0/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch new file mode 100644 index 0000000000..a35e83c819 --- /dev/null +++ b/queue-7.0/bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch @@ -0,0 +1,72 @@ +From e4d7ed32e04d89ad1db157f9b8ad354eec199ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:54:43 +0800 +Subject: Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling + +From: Shuai Zhang + +[ Upstream commit c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f ] + +When a Bluetooth controller encounters a coredump, it triggers the +Subsystem Restart (SSR) mechanism. The controller first reports the +coredump data and, once the upload is complete, sends a hw_error +event. The host relies on this event to proceed with subsequent +recovery actions. + +If the host has not finished processing the coredump data when the +hw_error event is received, it waits until either the processing is +complete or the 8-second timeout expires before handling the event. + +The current implementation clears QCA_MEMDUMP_COLLECTION using +clear_bit(), which does not wake up waiters sleeping in +wait_on_bit_timeout(). As a result, the waiting thread may remain +blocked until the timeout expires even if the coredump collection +has already completed. + +Fix this by clearing QCA_MEMDUMP_COLLECTION with +clear_and_wake_up_bit(), which also wakes up the waiting thread and +allows the hw_error handling to proceed immediately. + +Test case: +- Trigger a controller coredump using: + hcitool cmd 0x3f 0c 26 +- Tested on QCA6390. +- Capture HCI logs using btmon. +- Verify that the delay between receiving the hw_error event and + initiating the power-off sequence is reduced compared to the + timeout-based behavior. + +Reviewed-by: Bartosz Golaszewski +Reviewed-by: Paul Menzel +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_qca.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index edc907c4e870a..524e47392f919 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -1105,7 +1105,7 @@ static void qca_controller_memdump(struct work_struct *work) + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; +@@ -1183,7 +1183,7 @@ static void qca_controller_memdump(struct work_struct *work) + kfree(qca->qca_memdump); + qca->qca_memdump = NULL; + qca->memdump_state = QCA_MEMDUMP_COLLECTED; +- clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } + + mutex_unlock(&qca->hci_memdump_lock); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch b/queue-7.0/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch new file mode 100644 index 0000000000..e91d8cbc7e --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch @@ -0,0 +1,45 @@ +From 505f178e1fb7ce7687450049a8625a834215d892 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 18:07:26 +0100 +Subject: Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS + +From: Christian Eggers + +[ Upstream commit 728a3d128325bad286b1e4f191026e8de8d12a85 ] + +Core 6.0, Vol 3, Part A, 3.4.3: +"... If the payload size of any K-frame exceeds the receiver's MPS, the +receiver shall disconnect the channel..." + +This fixes L2CAP/LE/CFC/BV-27-C (running together with 'l2test -r -P +0x0027 -V le_public -I 100'). + +Signed-off-by: Christian Eggers +Signed-off-by: Luiz Augusto von Dentz +Tested-by: Christian Eggers +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 0d8053a3fc0a6..77dec104a9c36 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6711,6 +6711,13 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + return -ENOBUFS; + } + ++ if (skb->len > chan->mps) { ++ BT_ERR("Too big LE L2CAP MPS: len %u > %u", skb->len, ++ chan->mps); ++ l2cap_send_disconn_req(chan, ECONNRESET); ++ return -ENOBUFS; ++ } ++ + chan->rx_credits--; + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); +-- +2.53.0 + diff --git a/queue-7.0/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch b/queue-7.0/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch new file mode 100644 index 0000000000..27bc58b460 --- /dev/null +++ b/queue-7.0/bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch @@ -0,0 +1,44 @@ +From a23bfa5aa3f4bb9c5de0eeb19aed6e5c7ad01353 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:59:58 +0530 +Subject: bpf: Do not increment tailcall count when prog is NULL + +From: Hari Bathini + +[ Upstream commit 3733f4be287029dad963534da3d91ac806df233d ] + +Currently, tailcall count is incremented in the interpreter even when +tailcall fails due to non-existent prog. Fix this by holding off on +the tailcall count increment until after NULL check on the prog. + +Suggested-by: Ilya Leoshkevich +Signed-off-by: Hari Bathini +Link: https://lore.kernel.org/r/20260220062959.195101-1-hbathini@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 048d275accae2..dcf8c73292269 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -2089,12 +2089,12 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + if (unlikely(tail_call_cnt >= MAX_TAIL_CALL_CNT)) + goto out; + +- tail_call_cnt++; +- + prog = READ_ONCE(array->ptrs[index]); + if (!prog) + goto out; + ++ tail_call_cnt++; ++ + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handled like a helper, that is, bpf_tail_call_proto, +-- +2.53.0 + diff --git a/queue-7.0/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch b/queue-7.0/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch new file mode 100644 index 0000000000..62009c5279 --- /dev/null +++ b/queue-7.0/bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch @@ -0,0 +1,40 @@ +From 5fb2a88968e890a6abba400d6065dd2e974ea0e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 14:08:00 +0800 +Subject: bpf: propagate kvmemdup_bpfptr errors from bpf_prog_verify_signature + +From: Weixie Cui + +[ Upstream commit ad2f7ed0ee91d63792cbe52f2b38325918ae3daa ] + +kvmemdup_bpfptr() returns -EFAULT when the user pointer cannot be +copied, and -ENOMEM on allocation failure. The error path always +returned -ENOMEM, misreporting bad addresses as out-of-memory. + +Return PTR_ERR(sig) so user space gets the correct errno. + +Signed-off-by: Weixie Cui +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/tencent_C9C5B2B28413D6303D505CD02BFEA4708C07@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index ed595159f1c53..810991709da77 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -2832,7 +2832,7 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr + sig = kvmemdup_bpfptr(usig, attr->signature_size); + if (IS_ERR(sig)) { + bpf_key_put(key); +- return -ENOMEM; ++ return PTR_ERR(sig); + } + + bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0, +-- +2.53.0 + diff --git a/queue-7.0/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch b/queue-7.0/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch new file mode 100644 index 0000000000..e7b564dd6c --- /dev/null +++ b/queue-7.0/bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch @@ -0,0 +1,52 @@ +From 19b1f29da3db5a76f3c9bc9b6a65b643f5f8639f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:15 +0200 +Subject: bpf, sockmap: Annotate af_unix sock:: Sk_state data-races + +From: Michal Luczaj + +[ Upstream commit a25566084e391348385a72dd507e0cc0c268dd5d ] + +sock_map_sk_state_allowed() and sock_map_redirect_allowed() read af_unix +socket sk_state locklessly. + +Use READ_ONCE(). Note that for sock_map_redirect_allowed() change affects +not only af_unix, but all non-TCP sockets (UDP, af_vsock). + +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-1-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/core/sock_map.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/core/sock_map.c b/net/core/sock_map.c +index b0e96337a2698..02a68be3002a2 100644 +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -530,7 +530,7 @@ static bool sock_map_redirect_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return sk->sk_state != TCP_LISTEN; + else +- return sk->sk_state == TCP_ESTABLISHED; ++ return READ_ONCE(sk->sk_state) == TCP_ESTABLISHED; + } + + static bool sock_map_sk_is_suitable(const struct sock *sk) +@@ -543,7 +543,7 @@ static bool sock_map_sk_state_allowed(const struct sock *sk) + if (sk_is_tcp(sk)) + return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); + if (sk_is_stream_unix(sk)) +- return (1 << sk->sk_state) & TCPF_ESTABLISHED; ++ return (1 << READ_ONCE(sk->sk_state)) & TCPF_ESTABLISHED; + if (sk_is_vsock(sk) && + (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) + return (1 << sk->sk_state) & TCPF_ESTABLISHED; +-- +2.53.0 + diff --git a/queue-7.0/btrfs-abort-transaction-in-do_remap_reloc_trans-on-f.patch b/queue-7.0/btrfs-abort-transaction-in-do_remap_reloc_trans-on-f.patch new file mode 100644 index 0000000000..bed1ebc9ba --- /dev/null +++ b/queue-7.0/btrfs-abort-transaction-in-do_remap_reloc_trans-on-f.patch @@ -0,0 +1,60 @@ +From 56d062d9adccb968c7dc9aeef21ae6f38727b8d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:16:43 +0000 +Subject: btrfs: abort transaction in do_remap_reloc_trans() on failure + +From: Mark Harmstone + +[ Upstream commit 73db0fad673af844772de964eebecae60eda0496 ] + +If one of the calls made by do_remap_reloc_trans() fails, we can leave +the remap tree in an inconsistent state. Abort the transaction if this +happens, to prevent the corrupt state from reaching the disk. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/relocation.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index d8cd04fe9a4cd..3e5443e207aae 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -5043,21 +5043,27 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info, + + if (bg_needs_free_space) { + ret = btrfs_add_block_group_free_space(trans, dest_bg); +- if (ret) ++ if (ret) { ++ btrfs_abort_transaction(trans, ret); + goto fail; ++ } + } + + ret = copy_remapped_data(fs_info, start, new_addr, length); +- if (ret) ++ if (ret) { ++ btrfs_abort_transaction(trans, ret); + goto fail; ++ } + + ret = btrfs_remove_from_free_space_tree(trans, new_addr, length); +- if (ret) ++ if (ret) { ++ btrfs_abort_transaction(trans, ret); + goto fail; ++ } + + ret = add_remap_entry(trans, path, src_bg, start, new_addr, length); + if (ret) { +- btrfs_add_to_free_space_tree(trans, new_addr, length); ++ btrfs_abort_transaction(trans, ret); + goto fail; + } + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-apply-first-key-check-for-readahead-when-possi.patch b/queue-7.0/btrfs-apply-first-key-check-for-readahead-when-possi.patch new file mode 100644 index 0000000000..8651cfe7a9 --- /dev/null +++ b/queue-7.0/btrfs-apply-first-key-check-for-readahead-when-possi.patch @@ -0,0 +1,129 @@ +From 2a33a15189a3969b66aa5fab95cbb50733af69a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 20:31:05 +0930 +Subject: btrfs: apply first key check for readahead when possible + +From: Qu Wenruo + +[ Upstream commit a86a283430e1a44907b142c4f53e1f3ad24e87ae ] + +Currently for tree block readahead we never pass a +btrfs_tree_parent_check with @has_first_key set. + +Without @has_first_key set, btrfs will skip the following extra +checks: + +- Header generation check + This is a minor one. + +- Empty leaf/node checks + This is more serious, for certain trees like the csum tree, they are + allowed to be empty, thus an empty leaf can pass the tree checker. + But if there is a parent node for such an empty leaf, it indicates + corruption. + + Without @has_first_key set, we can no longer detect such a problem. + + In fact there is already a fuzzed image report that a corrupted csum + leaf which has zero nritems but still has a parent node can trigger + a BUG_ON() during csum deletion. + +However there are only two call sites of btrfs_readahead_tree_block(): + +- Inside relocate_tree_blocks() + At this call site we are trying to grab the first key of the tree + block, thus we are not able to pass a @first_key parameter. + +- Inside btrfs_readahead_node_child() + This is the more common call site, where we have the parent node and + want to readahead the child tree blocks. + + In this case we can easily grab the node key and pass it for checks. + +Add a new parameter @first_key to btrfs_readahead_tree_block() and pass +the node key to it inside btrfs_readahead_node_child(). + +This should plug the gap in empty leaf detection during readahead. + +Link: https://lore.kernel.org/linux-btrfs/20260409071255.3358044-1-gality369@gmail.com/ +Reviewed-by: David Sterba +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 14 ++++++++++++-- + fs/btrfs/extent_io.h | 3 ++- + fs/btrfs/relocation.c | 2 +- + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 5f97a3d2a8d72..83feb96b82673 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -4593,7 +4593,8 @@ int try_release_extent_buffer(struct folio *folio) + * to read the block we will not block on anything. + */ + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level) ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key) + { + struct btrfs_tree_parent_check check = { + .level = level, +@@ -4602,6 +4603,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + struct extent_buffer *eb; + int ret; + ++ if (first_key) { ++ memcpy(&check.first_key, first_key, sizeof(struct btrfs_key)); ++ check.has_first_key = true; ++ } ++ + eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); + if (IS_ERR(eb)) + return; +@@ -4629,9 +4635,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, + */ + void btrfs_readahead_node_child(struct extent_buffer *node, int slot) + { ++ struct btrfs_key node_key; ++ ++ btrfs_node_key_to_cpu(node, &node_key, slot); + btrfs_readahead_tree_block(node->fs_info, + btrfs_node_blockptr(node, slot), + btrfs_header_owner(node), + btrfs_node_ptr_generation(node, slot), +- btrfs_header_level(node) - 1); ++ btrfs_header_level(node) - 1, ++ &node_key); + } +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 080215352b7a1..255210a3dd905 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -285,7 +285,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb) + } + + void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, +- u64 bytenr, u64 owner_root, u64 gen, int level); ++ u64 bytenr, u64 owner_root, u64 gen, int level, ++ const struct btrfs_key *first_key); + void btrfs_readahead_node_child(struct extent_buffer *node, int slot); + + /* Note: this can be used in for loops without caching the value in a variable. */ +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 3e5443e207aae..af8bf7857fa31 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2610,7 +2610,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, + if (!block->key_ready) + btrfs_readahead_tree_block(fs_info, block->bytenr, + block->owner, 0, +- block->level); ++ block->level, NULL); + } + + /* Get first keys */ +-- +2.53.0 + diff --git a/queue-7.0/btrfs-avoid-gfp_atomic-allocations-in-qgroup-free-pa.patch b/queue-7.0/btrfs-avoid-gfp_atomic-allocations-in-qgroup-free-pa.patch new file mode 100644 index 0000000000..23bed565b9 --- /dev/null +++ b/queue-7.0/btrfs-avoid-gfp_atomic-allocations-in-qgroup-free-pa.patch @@ -0,0 +1,142 @@ +From 8b715a97f273cd759be8d29b9e63daa799470177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:49:08 -0700 +Subject: btrfs: avoid GFP_ATOMIC allocations in qgroup free paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Leo Martins + +[ Upstream commit e0a85137a882db789b1bccc1e7db06356ac8c69f ] + +When qgroups are enabled, __btrfs_qgroup_release_data() and +qgroup_free_reserved_data() pass an extent_changeset to +btrfs_clear_record_extent_bits() to track how many bytes had their +EXTENT_QGROUP_RESERVED bits cleared. Inside the extent IO tree spinlock, +add_extent_changeset() calls ulist_add() with GFP_ATOMIC to record each +changed range. If this allocation fails, it hits a BUG_ON and panics the +kernel. + +However, both of these callers only read changeset.bytes_changed +afterwards — the range_changed ulist is populated and immediately freed +without ever being iterated. The GFP_ATOMIC allocation is entirely +unnecessary for these paths. + +Introduce extent_changeset_init_bytes_only() which uses a sentinel value +(EXTENT_CHANGESET_BYTES_ONLY) on the ulist's prealloc field to signal +that only bytes_changed should be tracked. add_extent_changeset() checks +for this sentinel and returns early after updating bytes_changed, +skipping the ulist_add() call entirely. This eliminates the GFP_ATOMIC +allocation and makes the BUG_ON unreachable for these paths. + +Callers that need range tracking (qgroup_reserve_data, +qgroup_unreserve_range, btrfs_qgroup_check_reserved_leak) continue to +use extent_changeset_init() and are unaffected. + +Reviewed-by: Qu Wenruo +Signed-off-by: Leo Martins +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent-io-tree.c | 3 +++ + fs/btrfs/extent_io.h | 23 ++++++++++++++++++++++- + fs/btrfs/qgroup.c | 5 +++-- + 3 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c +index d0dd50f7d2795..2a2bce0f1f7c8 100644 +--- a/fs/btrfs/extent-io-tree.c ++++ b/fs/btrfs/extent-io-tree.c +@@ -193,7 +193,10 @@ static int add_extent_changeset(struct extent_state *state, u32 bits, + return 0; + if (!set && (state->state & bits) == 0) + return 0; ++ + changeset->bytes_changed += state->end - state->start + 1; ++ if (!extent_changeset_tracks_ranges(changeset)) ++ return 0; + + return ulist_add(&changeset->range_changed, state->start, state->end, GFP_ATOMIC); + } +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 8d05f1a58b7c3..080215352b7a1 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -196,6 +196,25 @@ static inline void extent_changeset_init(struct extent_changeset *changeset) + ulist_init(&changeset->range_changed); + } + ++/* ++ * Sentinel value for range_changed.prealloc indicating that the changeset ++ * only tracks bytes_changed and does not record individual ranges. This ++ * avoids GFP_ATOMIC allocations inside add_extent_changeset() when the ++ * caller doesn't need to iterate the changed ranges afterwards. ++ */ ++#define EXTENT_CHANGESET_BYTES_ONLY ((struct ulist_node *)1) ++ ++static inline void extent_changeset_init_bytes_only(struct extent_changeset *changeset) ++{ ++ changeset->bytes_changed = 0; ++ changeset->range_changed.prealloc = EXTENT_CHANGESET_BYTES_ONLY; ++} ++ ++static inline bool extent_changeset_tracks_ranges(const struct extent_changeset *changeset) ++{ ++ return changeset->range_changed.prealloc != EXTENT_CHANGESET_BYTES_ONLY; ++} ++ + static inline struct extent_changeset *extent_changeset_alloc(void) + { + struct extent_changeset *ret; +@@ -210,6 +229,7 @@ static inline struct extent_changeset *extent_changeset_alloc(void) + + static inline void extent_changeset_prealloc(struct extent_changeset *changeset, gfp_t gfp_mask) + { ++ ASSERT(extent_changeset_tracks_ranges(changeset)); + ulist_prealloc(&changeset->range_changed, gfp_mask); + } + +@@ -218,7 +238,8 @@ static inline void extent_changeset_release(struct extent_changeset *changeset) + if (!changeset) + return; + changeset->bytes_changed = 0; +- ulist_release(&changeset->range_changed); ++ if (extent_changeset_tracks_ranges(changeset)) ++ ulist_release(&changeset->range_changed); + } + + static inline void extent_changeset_free(struct extent_changeset *changeset) +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 41589ce663718..a95fa70def7f8 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -4326,7 +4326,7 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode, + u64 freed = 0; + int ret; + +- extent_changeset_init(&changeset); ++ extent_changeset_init_bytes_only(&changeset); + len = round_up(start + len, root->fs_info->sectorsize); + start = round_down(start, root->fs_info->sectorsize); + +@@ -4391,7 +4391,7 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode, + WARN_ON(!free && reserved); + if (free && reserved) + return qgroup_free_reserved_data(inode, reserved, start, len, released); +- extent_changeset_init(&changeset); ++ extent_changeset_init_bytes_only(&changeset); + ret = btrfs_clear_record_extent_bits(&inode->io_tree, start, start + len - 1, + EXTENT_QGROUP_RESERVED, &changeset); + if (ret < 0) +@@ -4646,6 +4646,7 @@ void btrfs_qgroup_check_reserved_leak(struct btrfs_inode *inode) + + WARN_ON(ret < 0); + if (WARN_ON(changeset.bytes_changed)) { ++ ASSERT(extent_changeset_tracks_ranges(&changeset)); + ULIST_ITER_INIT(&iter); + while ((unode = ulist_next(&changeset.range_changed, &iter))) { + btrfs_warn(inode->root->fs_info, +-- +2.53.0 + diff --git a/queue-7.0/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch b/queue-7.0/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch new file mode 100644 index 0000000000..5d9bbdcd36 --- /dev/null +++ b/queue-7.0/btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch @@ -0,0 +1,297 @@ +From 392d51087bde2acb07bd1a38a82c2ffbd0d2ddbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:12:29 +0000 +Subject: btrfs: be less aggressive with metadata overcommit when we can do + full flushing + +From: Filipe Manana + +[ Upstream commit 574d93fc62e2b03ab39c8f92fb44ded89ca6274d ] + +Over the years we often get reports of some -ENOSPC failure while updating +metadata that leads to a transaction abort. I have seen this happen for +filesystems of all sizes and with workloads that are very user/customer +specific and unable to reproduce, but Aleksandar recently reported a +simple way to reproduce this with a 1G filesystem and using the bonnie++ +benchmark tool. The following test script reproduces the failure: + + $ cat test.sh + #!/bin/bash + + # Create and use a 1G null block device, memory backed, otherwise + # the test takes a very long time. + modprobe null_blk nr_devices="0" + null_dev="/sys/kernel/config/nullb/nullb0" + mkdir "$null_dev" + size=$((1 * 1024)) # in MB + echo 2 > "$null_dev/submit_queues" + echo "$size" > "$null_dev/size" + echo 1 > "$null_dev/memory_backed" + echo 1 > "$null_dev/discard" + echo 1 > "$null_dev/power" + + DEV=/dev/nullb0 + MNT=/mnt/nullb0 + + mkfs.btrfs -f $DEV + mount $DEV $MNT + + mkdir $MNT/test/ + bonnie++ -d $MNT/test/ -m BTRFS -u 0 -s 256M -r 128M -b + + umount $MNT + + echo 0 > "$null_dev/power" + rmdir "$null_dev" + +When running this bonnie++ fails in the phase where it deletes test +directories and files: + + $ ./test.sh + (...) + Using uid:0, gid:0. + Writing a byte at a time...done + Writing intelligently...done + Rewriting...done + Reading a byte at a time...done + Reading intelligently...done + start 'em...done...done...done...done...done... + Create files in sequential order...done. + Stat files in sequential order...done. + Delete files in sequential order...done. + Create files in random order...done. + Stat files in random order...done. + Delete files in random order...Can't sync directory, turning off dir-sync. + Can't delete file 9Bq7sr0000000338 + Cleaning up test directory after error. + Bonnie: drastic I/O error (rmdir): Read-only file system + +And in the syslog/dmesg we can see the following transaction abort trace: + + [161915.501506] BTRFS warning (device nullb0): Skipping commit of aborted transaction. + [161915.502983] ------------[ cut here ]------------ + [161915.503832] BTRFS: Transaction aborted (error -28) + [161915.504748] WARNING: fs/btrfs/transaction.c:2045 at btrfs_commit_transaction+0xa21/0xd30 [btrfs], CPU#11: bonnie++/3377975 + [161915.506786] Modules linked in: btrfs dm_zero dm_snapshot (...) + [161915.518759] CPU: 11 UID: 0 PID: 3377975 Comm: bonnie++ Tainted: G W 6.19.0-rc7-btrfs-next-224+ #4 PREEMPT(full) + [161915.520857] Tainted: [W]=WARN + [161915.521405] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [161915.523414] RIP: 0010:btrfs_commit_transaction+0xa24/0xd30 [btrfs] + [161915.524630] Code: 48 8b 7c 24 (...) + [161915.526982] RSP: 0018:ffffd3fe8206fda8 EFLAGS: 00010292 + [161915.527707] RAX: 0000000000000002 RBX: ffff8f4886d3c000 RCX: 0000000000000000 + [161915.528723] RDX: 0000000002040001 RSI: 00000000ffffffe4 RDI: ffffffffc088f780 + [161915.529691] RBP: ffff8f4f5adae7e0 R08: 0000000000000000 R09: ffffd3fe8206fb90 + [161915.530842] R10: ffff8f4f9c1fffa8 R11: 0000000000000003 R12: 00000000ffffffe4 + [161915.532027] R13: ffff8f4ef2cf2400 R14: ffff8f4f5adae708 R15: ffff8f4f62d18000 + [161915.533229] FS: 00007ff93112a780(0000) GS:ffff8f4ff63ee000(0000) knlGS:0000000000000000 + [161915.534611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [161915.535575] CR2: 00005571b3072000 CR3: 0000000176080005 CR4: 0000000000370ef0 + [161915.536758] Call Trace: + [161915.537185] + [161915.537575] btrfs_sync_file+0x431/0x530 [btrfs] + [161915.538473] do_fsync+0x39/0x80 + [161915.539042] __x64_sys_fsync+0xf/0x20 + [161915.539750] do_syscall_64+0x50/0xf20 + [161915.540396] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [161915.541301] RIP: 0033:0x7ff930ca49ee + [161915.541904] Code: 08 0f 85 f5 (...) + [161915.544830] RSP: 002b:00007ffd94291f38 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + [161915.546152] RAX: ffffffffffffffda RBX: 00007ff93112a780 RCX: 00007ff930ca49ee + [161915.547263] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 + [161915.548383] RBP: 0000000000000dab R08: 0000000000000000 R09: 0000000000000000 + [161915.549853] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffd94291fb0 + [161915.551196] R13: 00007ffd94292350 R14: 0000000000000001 R15: 00007ffd94292340 + [161915.552161] + [161915.552457] ---[ end trace 0000000000000000 ]--- + [161915.553232] BTRFS info (device nullb0 state A): dumping space info: + [161915.553236] BTRFS info (device nullb0 state A): space_info DATA (sub-group id 0) has 12582912 free, is not full + [161915.553239] BTRFS info (device nullb0 state A): space_info total=12582912, used=0, pinned=0, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553243] BTRFS info (device nullb0 state A): space_info METADATA (sub-group id 0) has -5767168 free, is full + [161915.553245] BTRFS info (device nullb0 state A): space_info total=53673984, used=6635520, pinned=46956544, reserved=16384, may_use=5767168, readonly=65536 zone_unusable=0 + [161915.553251] BTRFS info (device nullb0 state A): space_info SYSTEM (sub-group id 0) has 8355840 free, is not full + [161915.553254] BTRFS info (device nullb0 state A): space_info total=8388608, used=16384, pinned=16384, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [161915.553257] BTRFS info (device nullb0 state A): global_block_rsv: size 5767168 reserved 5767168 + [161915.553261] BTRFS info (device nullb0 state A): trans_block_rsv: size 0 reserved 0 + [161915.553263] BTRFS info (device nullb0 state A): chunk_block_rsv: size 0 reserved 0 + [161915.553265] BTRFS info (device nullb0 state A): remap_block_rsv: size 0 reserved 0 + [161915.553268] BTRFS info (device nullb0 state A): delayed_block_rsv: size 0 reserved 0 + [161915.553270] BTRFS info (device nullb0 state A): delayed_refs_rsv: size 0 reserved 0 + [161915.553272] BTRFS: error (device nullb0 state A) in cleanup_transaction:2045: errno=-28 No space left + [161915.554463] BTRFS info (device nullb0 state EA): forced readonly + +The problem is that we allow for a very aggressive metadata overcommit, +about 1/8th of the currently available space, even when the task +attempting the reservation allows for full flushing. Over time this allows +more and more tasks to overcommit without getting a transaction commit to +release pinned extents, joining the same transaction and eventually lead +to the transaction abort when attempting some tree update, as the extent +allocator is not able to find any available metadata extent and it's not +able to allocate a new metadata block group either (not enough unallocated +space for that). + +Fix this by allowing the overcommit to be up to 1/64th of the available +(unallocated) space instead and for that limit to apply to both types of +full flushing, BTRFS_RESERVE_FLUSH_ALL and BTRFS_RESERVE_FLUSH_ALL_STEAL. +This way we get more frequent transaction commits to release pinned +extents in case our caller is in a context where full flushing is allowed. + +Note that the space infos dump in the dmesg/syslog right after the +transaction abort give the wrong idea that we have plenty of unallocated +space when the abort happened. During the bonnie++ workload we had a +metadata chunk allocation attempt and it failed with -ENOSPC because at +that time we had a bunch of data block groups allocated, which then became +empty and got deleted by the cleaner kthread after the metadata chunk +allocation failed with -ENOSPC and before the transaction abort happened +and dumped the space infos. + +The custom tracing (some trace_printk() calls spread in strategic places) +used to check that: + + mount-1793735 [011] ...1. 28877.261096: btrfs_add_bg_to_space_info: added bg offset 13631488 length 8388608 flags 1 to space_info->flags 1 total_bytes 8388608 bytes_used 0 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261098: btrfs_add_bg_to_space_info: added bg offset 22020096 length 8388608 flags 34 to space_info->flags 2 total_bytes 8388608 bytes_used 16384 bytes_may_use 0 + mount-1793735 [011] ...1. 28877.261100: btrfs_add_bg_to_space_info: added bg offset 30408704 length 53673984 flags 36 to space_info->flags 4 total_bytes 53673984 bytes_used 131072 bytes_may_use 0 + +These are from loading the block groups created by mkfs during mount. + +Then when bonnie++ starts doing its thing: + + kworker/u48:5-1792004 [011] ..... 28886.122050: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.122053: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 927596544 + kworker/u48:5-1792004 [011] ..... 28886.122055: btrfs_make_block_group: make bg offset 84082688 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.122064: btrfs_add_bg_to_space_info: added bg offset 84082688 length 117440512 flags 1 to space_info->flags 1 total_bytes 125829120 bytes_used 0 bytes_may_use 5251072 + +First allocation of a data block group of 112M. + + kworker/u48:5-1792004 [011] ..... 28886.192408: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.192413: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 810156032 + kworker/u48:5-1792004 [011] ..... 28886.192415: btrfs_make_block_group: make bg offset 201523200 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.192425: btrfs_add_bg_to_space_info: added bg offset 201523200 length 117440512 flags 1 to space_info->flags 1 total_bytes 243269632 bytes_used 0 bytes_may_use 122691584 + +Another 112M data block group allocated. + + kworker/u48:5-1792004 [011] ..... 28886.260935: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.260941: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 692715520 + kworker/u48:5-1792004 [011] ..... 28886.260943: btrfs_make_block_group: make bg offset 318963712 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.260954: btrfs_add_bg_to_space_info: added bg offset 318963712 length 117440512 flags 1 to space_info->flags 1 total_bytes 360710144 bytes_used 0 bytes_may_use 240132096 + +Yet another one. + + bonnie++-1793755 [010] ..... 28886.280407: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [010] ..... 28886.280412: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 575275008 + bonnie++-1793755 [010] ..... 28886.280414: btrfs_make_block_group: make bg offset 436404224 size 117440512 type 1 + bonnie++-1793755 [010] ...1. 28886.280419: btrfs_add_bg_to_space_info: added bg offset 436404224 length 117440512 flags 1 to space_info->flags 1 total_bytes 478150656 bytes_used 0 bytes_may_use 268435456 + +One more. + + kworker/u48:5-1792004 [011] ..... 28886.566233: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + kworker/u48:5-1792004 [011] ..... 28886.566238: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 457834496 + kworker/u48:5-1792004 [011] ..... 28886.566241: btrfs_make_block_group: make bg offset 553844736 size 117440512 type 1 + kworker/u48:5-1792004 [011] ...1. 28886.566250: btrfs_add_bg_to_space_info: added bg offset 553844736 length 117440512 flags 1 to space_info->flags 1 total_bytes 595591168 bytes_used 268435456 bytes_may_use 209723392 + +Another one. + + bonnie++-1793755 [009] ..... 28886.613446: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.613451: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 340393984 + bonnie++-1793755 [009] ..... 28886.613453: btrfs_make_block_group: make bg offset 671285248 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.613458: btrfs_add_bg_to_space_info: added bg offset 671285248 length 117440512 flags 1 to space_info->flags 1 total_bytes 713031680 bytes_used 268435456 bytes_may_use 2 68435456 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674953: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674957: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 222953472 + bonnie++-1793755 [009] ..... 28886.674959: btrfs_make_block_group: make bg offset 788725760 size 117440512 type 1 + bonnie++-1793755 [009] ...1. 28886.674963: btrfs_add_bg_to_space_info: added bg offset 788725760 length 117440512 flags 1 to space_info->flags 1 total_bytes 830472192 bytes_used 268435456 bytes_may_use 1 34217728 + +Another one. + + bonnie++-1793755 [009] ..... 28886.674981: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793755 [009] ..... 28886.674982: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 105512960 + bonnie++-1793755 [009] ..... 28886.674983: btrfs_make_block_group: make bg offset 906166272 size 105512960 type 1 + bonnie++-1793755 [009] ...1. 28886.674984: btrfs_add_bg_to_space_info: added bg offset 906166272 length 105512960 flags 1 to space_info->flags 1 total_bytes 935985152 bytes_used 268435456 bytes_may_use 67108864 + +Another one, but a bit smaller (~100.6M) since we now have less space. + + bonnie++-1793758 [009] ..... 28891.962096: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 + bonnie++-1793758 [009] ..... 28891.962103: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 65536 dev_extent_want 1073741824 max_avail 12582912 + bonnie++-1793758 [009] ..... 28891.962105: btrfs_make_block_group: make bg offset 1011679232 size 12582912 type 1 + bonnie++-1793758 [009] ...1. 28891.962114: btrfs_add_bg_to_space_info: added bg offset 1011679232 length 12582912 flags 1 to space_info->flags 1 total_bytes 948568064 bytes_used 268435456 bytes_may_use 8192 + +Another one, this one even smaller (12M). + + kworker/u48:5-1792004 [011] ..... 28892.112802: btrfs_chunk_alloc: enter first metadata chunk alloc attempt + kworker/u48:5-1792004 [011] ..... 28892.112805: btrfs_create_chunk: gather_device_info 1 ctl->dev_extent_min = 131072 dev_extent_want 536870912 + kworker/u48:5-1792004 [011] ..... 28892.112806: btrfs_create_chunk: gather_device_info 2 ctl->dev_extent_min = 131072 dev_extent_want 536870912 max_avail 0 + +536870912 is 512M, the standard 256M metadata chunk size times 2 because +of the DUP profile for metadata. +'max_avail' is what find_free_dev_extent() returns to us in +gather_device_info(). + +As a result, gather_device_info() sets ctl->ndevs to 0, making +decide_stripe_size() fail with -ENOSPC, and therefore metadata chunk +allocation fails while we are attempting to run delayed items during +the transaction commit. + + kworker/u48:5-1792004 [011] ..... 28892.112807: btrfs_create_chunk: decide_stripe_size fail -ENOSPC + +In the syslog/dmesg pasted above, which happened after the transaction was +aborted, the space info dumps did not account for all these data block +groups that were allocated during bonnie++'s workload. And that is because +after the metadata chunk allocation failed with -ENOSPC and before the +transaction abort happened, most of the data block groups had become empty +and got deleted by by the cleaner kthread - when the abort happened, we +had bonnie++ in the middle of deleting the files it created. + +But dumping the space infos right after the metadata chunk allocation fails +by adding a call to btrfs_dump_space_info_for_trans_abort() in +decide_stripe_size() when it returns -ENOSPC, we get: + + [29972.409295] BTRFS info (device nullb0): dumping space info: + [29972.409300] BTRFS info (device nullb0): space_info DATA (sub-group id 0) has 673341440 free, is not full + [29972.409303] BTRFS info (device nullb0): space_info total=948568064, used=0, pinned=275226624, reserved=0, may_use=0, readonly=0 zone_unusable=0 + [29972.409305] BTRFS info (device nullb0): space_info METADATA (sub-group id 0) has 3915776 free, is not full + [29972.409306] BTRFS info (device nullb0): space_info total=53673984, used=163840, pinned=42827776, reserved=147456, may_use=6553600, readonly=65536 zone_unusable=0 + [29972.409308] BTRFS info (device nullb0): space_info SYSTEM (sub-group id 0) has 7979008 free, is not full + [29972.409310] BTRFS info (device nullb0): space_info total=8388608, used=16384, pinned=0, reserved=0, may_use=393216, readonly=0 zone_unusable=0 + [29972.409311] BTRFS info (device nullb0): global_block_rsv: size 5767168 reserved 5767168 + [29972.409313] BTRFS info (device nullb0): trans_block_rsv: size 0 reserved 0 + [29972.409314] BTRFS info (device nullb0): chunk_block_rsv: size 393216 reserved 393216 + [29972.409315] BTRFS info (device nullb0): remap_block_rsv: size 0 reserved 0 + [29972.409316] BTRFS info (device nullb0): delayed_block_rsv: size 0 reserved 0 + +So here we see there's ~904.6M of data space, ~51.2M of metadata space and +8M of system space, making a total of 963.8M. + +Reported-by: Aleksandar Gerasimovski +Link: https://lore.kernel.org/linux-btrfs/SA1PR18MB56922F690C5EC2D85371408B998FA@SA1PR18MB5692.namprd18.prod.outlook.com/ +Link: https://lore.kernel.org/linux-btrfs/CAL3q7H61vZ3_+eqJ1A9po2WcgNJJjUu9MJQoYB2oDSAAecHaug@mail.gmail.com/ +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/space-info.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index 4e5196cf7b352..b45532dc54d05 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -487,10 +487,10 @@ static u64 calc_available_free_space(const struct btrfs_space_info *space_info, + /* + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit +- * too much, let it overcommit up to 1/8 of the space. ++ * too much, let it overcommit up to 1/64th of the space. + */ +- if (flush == BTRFS_RESERVE_FLUSH_ALL) +- avail >>= 3; ++ if (flush == BTRFS_RESERVE_FLUSH_ALL || flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) ++ avail >>= 6; + else + avail >>= 1; + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-check-return-value-of-btrfs_partially_delete_r.patch b/queue-7.0/btrfs-check-return-value-of-btrfs_partially_delete_r.patch new file mode 100644 index 0000000000..7161b2913b --- /dev/null +++ b/queue-7.0/btrfs-check-return-value-of-btrfs_partially_delete_r.patch @@ -0,0 +1,73 @@ +From 0c26881a596939146719f50889f82ee5c73ac419 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:37 +0800 +Subject: btrfs: check return value of btrfs_partially_delete_raid_extent() + +From: robbieko + +[ Upstream commit a8d58a7c0200904ff24ca7f0d7c147017e25aa99 ] + +btrfs_partially_delete_raid_extent() returns an error code (e.g. +-ENOMEM from kzalloc(), or errors from btrfs_del_item/btrfs_insert_item()), +but all three call sites in btrfs_delete_raid_extent() discard the +return value, silently losing errors and potentially leaving the stripe +tree in an inconsistent state. + +Fix by capturing the return value into ret at all three call sites and +breaking out of the loop on error where appropriate. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index 5909ad35a1b07..86ddc3ecb4060 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -213,8 +213,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + /* The "left" item. */ + path->slots[0]--; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); +- btrfs_partially_delete_raid_extent(trans, path, &key, +- diff_start, 0); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ diff_start, 0); + break; + } + +@@ -230,8 +231,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + if (found_start < start) { + u64 diff_start = start - found_start; + +- btrfs_partially_delete_raid_extent(trans, path, &key, +- diff_start, 0); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ diff_start, 0); ++ if (ret) ++ break; + + start += (key.offset - diff_start); + length -= (key.offset - diff_start); +@@ -254,9 +258,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + if (found_end > end) { + u64 diff_end = found_end - end; + +- btrfs_partially_delete_raid_extent(trans, path, &key, +- key.offset - length, +- length); ++ ret = btrfs_partially_delete_raid_extent(trans, path, ++ &key, ++ key.offset - length, ++ length); + ASSERT(key.offset - diff_end == length); + break; + } +-- +2.53.0 + diff --git a/queue-7.0/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch b/queue-7.0/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch new file mode 100644 index 0000000000..94dbe8a187 --- /dev/null +++ b/queue-7.0/btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch @@ -0,0 +1,47 @@ +From 216e2cd6c0a5349ed09d0b68fe2686cb586897a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:32 +0800 +Subject: btrfs: copy devid in btrfs_partially_delete_raid_extent() + +From: robbieko + +[ Upstream commit 513f8a52eed880ea525dbb139b2127bd9bb793f1 ] + +When btrfs_partially_delete_raid_extent() rebuilds a truncated/shifted +stripe extent into newitem, the loop copies the physical address for +each stride but forgets to copy the devid. The resulting item written +back to the stripe tree has zeroed-out devids, corrupting the stripe +mapping. + +Fix this by reading the devid with btrfs_raid_stride_devid() and +writing it into the new item with btrfs_set_stack_raid_stride_devid() +before copying the physical address. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index a2e9ac2d97988..5909ad35a1b07 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans, + + for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { + struct btrfs_raid_stride *stride = &extent->strides[i]; ++ u64 devid; + u64 phys; + ++ devid = btrfs_raid_stride_devid(leaf, stride); ++ btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid); + phys = btrfs_raid_stride_physical(leaf, stride) + frontpad; + btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys); + } +-- +2.53.0 + diff --git a/queue-7.0/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch b/queue-7.0/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch new file mode 100644 index 0000000000..35591e6cba --- /dev/null +++ b/queue-7.0/btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch @@ -0,0 +1,73 @@ +From 72b6bd4bb0592450586cb7bcdd0ad5c34fabc3ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:35:01 +0000 +Subject: btrfs: don't allow log trees to consume global reserve or overcommit + metadata + +From: Filipe Manana + +[ Upstream commit 40f2b11c1b7c593bbbfbf6bf333228ee53ed4050 ] + +For a fsync we never reserve space in advance, we just start a transaction +without reserving space and we use an empty block reserve for a log tree. +We reserve space as we need while updating a log tree, we end up in +btrfs_use_block_rsv() when reserving space for the allocation of a log +tree extent buffer and we attempt first to reserve without flushing, +and if that fails we attempt to consume from the global reserve or +overcommit metadata. This makes us consume space that may be the last +resort for a transaction commit to succeed, therefore increasing the +chances for a transaction abort with -ENOSPC. + +So make btrfs_use_block_rsv() fail if we can't reserve metadata space for +a log tree extent buffer allocation without flushing, making the fsync +fallback to a transaction commit and avoid using critical space that could +be the only resort for a transaction commit to succeed when we are in a +critical space situation. + +Reviewed-by: Leo Martins +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-rsv.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c +index 6064dd00d041b..9efb3016ef116 100644 +--- a/fs/btrfs/block-rsv.c ++++ b/fs/btrfs/block-rsv.c +@@ -541,6 +541,31 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, + BTRFS_RESERVE_NO_FLUSH); + if (!ret) + return block_rsv; ++ ++ /* ++ * If we are being used for updating a log tree, fail immediately, which ++ * makes the fsync fallback to a transaction commit. ++ * ++ * We don't want to consume from the global block reserve, as that is ++ * precious space that may be needed to do updates to some trees for ++ * which we don't reserve space during a transaction commit (update root ++ * items in the root tree, device stat items in the device tree and ++ * quota tree updates, see btrfs_init_root_block_rsv()), or to fallback ++ * to in case we did not reserve enough space to run delayed items, ++ * delayed references, or anything else we need in order to avoid a ++ * transaction abort. ++ * ++ * We also don't want to do a reservation in flush emergency mode, as ++ * we end up using metadata that could be critical to allow a ++ * transaction to complete successfully and therefore increase the ++ * chances for a transaction abort. ++ * ++ * Log trees are an optimization and should never consume from the ++ * global reserve or be allowed overcommitting metadata. ++ */ ++ if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) ++ return ERR_PTR(ret); ++ + /* + * If we couldn't reserve metadata bytes try and use some from + * the global reserve if its space type is the same as the global +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch b/queue-7.0/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch new file mode 100644 index 0000000000..ba8fd61cab --- /dev/null +++ b/queue-7.0/btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch @@ -0,0 +1,66 @@ +From ddc5e4061410845e2e76af0a910c87a4c3b5a64d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:33 +0800 +Subject: btrfs: fix raid stripe search missing entries at leaf boundaries + +From: robbieko + +[ Upstream commit 2aef5cb1dcf9b3e1be3895a6477dc065e618aab8 ] + +In btrfs_delete_raid_extent(), the search key uses offset=0. When the +target stripe entry is the first item on a leaf, btrfs_search_slot() +may land on the previous leaf and decrementing the slot from nritems +still points to the wrong entry, causing the stripe extent to be +silently missed. + +Fix this by searching with offset=(u64)-1 instead. Since no real stripe +entry has this offset, btrfs_search_slot() always returns 1 with the +slot pointing past the last matching objectid entry. Then unconditionally +decrement the slot with a proper slots[0]==0 early-exit check to handle +the case where no matching entry exists. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index d2b8995febec9..dd924048c6659 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -95,14 +95,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + while (1) { + key.objectid = start; + key.type = BTRFS_RAID_STRIPE_KEY; +- key.offset = 0; ++ key.offset = (u64)-1; + + ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); + if (ret < 0) + break; + +- if (path->slots[0] == btrfs_header_nritems(path->nodes[0])) +- path->slots[0]--; ++ /* ++ * Search with offset=(u64)-1 ensures we land on the correct ++ * leaf even when the target entry is the first item on a leaf. ++ * Since no real entry has offset=(u64)-1, ret is always 1 and ++ * slot points past the last entry with objectid==start (or ++ * past the end of the leaf if that entry is the last item). ++ * Back up one slot to find the actual entry. ++ */ ++ if (path->slots[0] == 0) { ++ /* No entry with objectid <= start exists. */ ++ ret = 0; ++ break; ++ } ++ path->slots[0]--; + + leaf = path->nodes[0]; + slot = path->slots[0]; +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch b/queue-7.0/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch new file mode 100644 index 0000000000..48fde985a4 --- /dev/null +++ b/queue-7.0/btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch @@ -0,0 +1,61 @@ +From 9f14637933e0e2c7a669d54bb997faf520164528 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 09:06:44 -0700 +Subject: btrfs: fix silent IO error loss in encoded writes and zoned split + +From: Michal Grzedzicki + +[ Upstream commit 3cd181cc46d36aa7bd4af85f14639d86a25beaec ] + +can_finish_ordered_extent() and btrfs_finish_ordered_zoned() set +BTRFS_ORDERED_IOERR via bare set_bit(). Later, +btrfs_mark_ordered_extent_error() in btrfs_finish_one_ordered() uses +test_and_set_bit(), finds it already set, and skips +mapping_set_error(). The error is never recorded on the inode's +address_space, making it invisible to fsync. For encoded writes this +causes btrfs receive to silently produce files with zero-filled holes. + +Fix: replace bare set_bit(BTRFS_ORDERED_IOERR) with +btrfs_mark_ordered_extent_error() which pairs test_and_set_bit() with +mapping_set_error(), guaranteeing the error is recorded exactly once. + +Reviewed-by: Qu Wenruo +Reviewed-by: Johannes Thumshirn +Reviewed-by: Mark Harmstone +Signed-off-by: Michal Grzedzicki +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ordered-data.c | 2 +- + fs/btrfs/zoned.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c +index 5df02c707aee6..b65c1f1e2956e 100644 +--- a/fs/btrfs/ordered-data.c ++++ b/fs/btrfs/ordered-data.c +@@ -385,7 +385,7 @@ static bool can_finish_ordered_extent(struct btrfs_ordered_extent *ordered, + } + + if (!uptodate) +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + + if (ordered->bytes_left) + return false; +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index 0cd7fd3fcfa3a..d728c3bafc092 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -2136,7 +2136,7 @@ void btrfs_finish_ordered_zoned(struct btrfs_ordered_extent *ordered) + continue; + } + if (!btrfs_zoned_split_ordered(ordered, logical, len)) { +- set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); ++ btrfs_mark_ordered_extent_error(ordered); + btrfs_err(fs_info, "failed to split ordered extent"); + goto out; + } +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch b/queue-7.0/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch new file mode 100644 index 0000000000..b7bdfbc215 --- /dev/null +++ b/queue-7.0/btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch @@ -0,0 +1,43 @@ +From 8ca8b9f6e0aff778b00360f702798cf2ed69913f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:34 +0800 +Subject: btrfs: fix wrong min_objectid in btrfs_previous_item() call + +From: robbieko + +[ Upstream commit 1871ae78ffa5ce7c0458e9ba5867958c1753e425 ] + +When found_start > start and slot == 0, btrfs_previous_item() is called +with min_objectid=start to find the previous stripe extent. However, the +previous stripe extent we are looking for has objectid < start (it starts +before our deletion range), so passing start as min_objectid prevents +finding it. + +Fix by passing 0 as min_objectid to allow finding any preceding stripe +extent regardless of its objectid. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index 2987cb7c686ea..d2b8995febec9 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -123,7 +123,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + */ + if (found_start > start) { + if (slot == 0) { +- ret = btrfs_previous_item(stripe_root, path, start, ++ ret = btrfs_previous_item(stripe_root, path, 0, + BTRFS_RAID_STRIPE_KEY); + if (ret) { + if (ret > 0) +-- +2.53.0 + diff --git a/queue-7.0/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch b/queue-7.0/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch new file mode 100644 index 0000000000..d1ddfee3c3 --- /dev/null +++ b/queue-7.0/btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch @@ -0,0 +1,60 @@ +From e6b9b1c111185cf20b0a274a6e0f3a11ba8e8dc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:36 +0800 +Subject: btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale + leaf pointer + +From: robbieko + +[ Upstream commit fe0cdfd7118d8b40a21bfac221bb4982c5e10e10 ] + +In the 'punch a hole' case of btrfs_delete_raid_extent(), +btrfs_duplicate_item() can return -EAGAIN when the leaf needs to be +split and the path becomes invalid. The old code treats any error as +fatal and breaks out of the loop. + +Additionally, btrfs_duplicate_item() may trigger setup_leaf_for_split() +which can reallocate the leaf node. The code continues using the old +leaf pointer, leading to use-after-free or stale data access. + +Fix both issues by: + +- Handling -EAGAIN specifically: release the path and retry the loop. +- Refreshing leaf = path->nodes[0] after successful duplication. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index 86ddc3ecb4060..22327f4833113 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -194,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + + /* The "right" item. */ + ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); ++ if (ret == -EAGAIN) { ++ btrfs_release_path(path); ++ continue; ++ } + if (ret) + break; + ++ /* ++ * btrfs_duplicate_item() may have triggered a leaf ++ * split via setup_leaf_for_split(), so we must refresh ++ * our leaf pointer from the path. ++ */ ++ leaf = path->nodes[0]; + item_size = btrfs_item_size(leaf, path->slots[0]); + extent = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_stripe_extent); +-- +2.53.0 + diff --git a/queue-7.0/btrfs-handle-unexpected-free-space-tree-key-types.patch b/queue-7.0/btrfs-handle-unexpected-free-space-tree-key-types.patch new file mode 100644 index 0000000000..23a9e9f99d --- /dev/null +++ b/queue-7.0/btrfs-handle-unexpected-free-space-tree-key-types.patch @@ -0,0 +1,66 @@ +From affb0ed742d82a7fce3c7b17a68fe5bd0e23636a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 17:30:31 +0200 +Subject: btrfs: handle unexpected free-space-tree key types + +From: David Sterba + +[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ] + +Replace the conditional assertions with proper error handling and +transaction abort if we find an unexpected key type in the free space +tree. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/free-space-tree.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index 9efd1ec90f031..472b3060e5ac3 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -259,7 +259,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -405,7 +409,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans, + + nr++; + } else { +- ASSERT(0); ++ btrfs_err(fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ goto out; + } + } + +@@ -1518,7 +1526,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans, + nr++; + path->slots[0]--; + } else { +- ASSERT(0); ++ btrfs_err(trans->fs_info, "unexpected free space tree key type %u", ++ found_key.type); ++ ret = -EUCLEAN; ++ btrfs_abort_transaction(trans, ret); ++ return ret; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-replace-assert-with-proper-error-handling-in-s.patch b/queue-7.0/btrfs-replace-assert-with-proper-error-handling-in-s.patch new file mode 100644 index 0000000000..a9871e2b1e --- /dev/null +++ b/queue-7.0/btrfs-replace-assert-with-proper-error-handling-in-s.patch @@ -0,0 +1,46 @@ +From 4cd52fb1081c374c2c136293bd93d7f7cfed5952 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 14:52:35 +0800 +Subject: btrfs: replace ASSERT with proper error handling in stripe lookup + fallback + +From: robbieko + +[ Upstream commit 653361585d251fbca0e19ac58b04ba95dd01e378 ] + +After falling back to the previous item in btrfs_delete_raid_extent(), +the code uses ASSERT(found_start <= start) to verify the found extent +actually precedes our target range. If the B-tree state is unexpected +(e.g. no overlapping extent exists), this triggers a kernel BUG/panic +in debug builds, or silently continues with wrong data otherwise. + +Replace the ASSERT with a proper bounds check that returns -ENOENT if +the found extent does not actually overlap with the start position. + +Signed-off-by: robbieko +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/raid-stripe-tree.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index dd924048c6659..a2e9ac2d97988 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -151,7 +151,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le + btrfs_item_key_to_cpu(leaf, &key, slot); + found_start = key.objectid; + found_end = found_start + key.offset; +- ASSERT(found_start <= start); ++ if (found_start > start || found_end <= start) { ++ ret = -ENOENT; ++ break; ++ } + } + + if (key.type != BTRFS_RAID_STRIPE_KEY) +-- +2.53.0 + diff --git a/queue-7.0/btrfs-replace-bug_on-with-error-return-in-cache_save.patch b/queue-7.0/btrfs-replace-bug_on-with-error-return-in-cache_save.patch new file mode 100644 index 0000000000..40a132dd42 --- /dev/null +++ b/queue-7.0/btrfs-replace-bug_on-with-error-return-in-cache_save.patch @@ -0,0 +1,49 @@ +From 1d6c3bf67520db777d45c78a347d36840e3294a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 07:40:59 +0100 +Subject: btrfs: replace BUG_ON() with error return in cache_save_setup() + +From: Teng Liu <27rabbitlt@gmail.com> + +[ Upstream commit 30d537f723d6f37a8ddfb17fe668bb9808f5b49f ] + +In cache_save_setup(), if create_free_space_inode() succeeds but the +subsequent lookup_free_space_inode() still fails on retry, the +BUG_ON(retries) will crash the kernel. This can happen due to I/O +errors or transient failures, not just programming bugs. + +Replace the BUG_ON with proper error handling that returns the original +error code through the existing cleanup path. The callers already handle +this gracefully: disk_cache_state defaults to BTRFS_DC_ERROR, so the +space cache simply won't be written for that block group. + +Reviewed-by: Qu Wenruo +Signed-off-by: Teng Liu <27rabbitlt@gmail.com> +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index c0d17a369bda5..ccabcad1a3fc3 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3343,7 +3343,13 @@ static int cache_save_setup(struct btrfs_block_group *block_group, + } + + if (IS_ERR(inode)) { +- BUG_ON(retries); ++ if (retries) { ++ ret = PTR_ERR(inode); ++ btrfs_err(fs_info, ++ "failed to lookup free space inode after creation for block group %llu: %d", ++ block_group->start, ret); ++ goto out_free; ++ } + retries++; + + if (block_group->ro) +-- +2.53.0 + diff --git a/queue-7.0/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch b/queue-7.0/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch new file mode 100644 index 0000000000..15646f0743 --- /dev/null +++ b/queue-7.0/btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch @@ -0,0 +1,75 @@ +From 55edc1316f68a365a709a50bf5888eb1911ffe96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:58:56 +0100 +Subject: btrfs: tracepoints: fix sleep while in atomic context in + btrfs_sync_file() + +From: Filipe Manana + +[ Upstream commit c73370c677646e86fc4b1780fb07027bdf847375 ] + +The trace event btrfs_sync_file() is called in an atomic context (all trace +events are) and its call to dput(), which is needed due to the call to +dget_parent(), can sleep, triggering a kernel splat. + +This can be reproduced by enabling the trace event and running btrfs/056 +from fstests for example. The splat shown in dmesg is the following: + + [53.919] BUG: sleeping function called from invalid context at fs/dcache.c:970 + [53.947] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 32773, name: xfs_io + [53.988] preempt_count: 2, expected: 0 + [53.967] RCU nest depth: 0, expected: 0 + [53.943] Preemption disabled at: + [53.944] [<0000000000000000>] 0x0 + [54.078] CPU: 0 UID: 0 PID: 32773 Comm: xfs_io Tainted: G W 7.1.0-rc1-btrfs-next-232+ #1 PREEMPT(full) + [54.070] Tainted: [W]=WARN + [54.071] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014 + [54.072] Call Trace: + [54.074] + [54.076] dump_stack_lvl+0x56/0x80 + [54.079] __might_resched.cold+0xd6/0x10f + [54.072] dput.part.0+0x24/0x110 + [54.078] trace_event_raw_event_btrfs_sync_file+0x75/0x140 [btrfs] + [54.089] btrfs_sync_file+0x1ed/0x530 [btrfs] + [54.087] ? __handle_mm_fault+0x8ae/0xed0 + [54.089] btrfs_do_write_iter+0x172/0x210 [btrfs] + [54.091] vfs_write+0x21f/0x450 + [54.094] __x64_sys_pwrite64+0x8d/0xc0 + [54.096] ? do_user_addr_fault+0x20c/0x670 + [54.099] do_syscall_64+0x60/0xf20 + [54.092] ? clear_bhb_loop+0x60/0xb0 + [54.094] entry_SYSCALL_64_after_hwframe+0x76/0x7e + +So stop using dget_parent() and dput() and access the parent dentry +directly as dentry->d_parent. This is also what ext4 is doing in +its equivalent trace event ext4_sync_file_enter(). + +Fixes: a85b46db143f ("btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file()") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + include/trace/events/btrfs.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index 0864700f76e0a..fa090a455037a 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -771,10 +771,8 @@ TRACE_EVENT(btrfs_sync_file, + TP_fast_assign( + struct dentry *dentry = file_dentry(file); + struct inode *inode = file_inode(file); +- struct dentry *parent = dget_parent(dentry); +- struct inode *parent_inode = d_inode(parent); ++ struct inode *parent_inode = d_inode(dentry->d_parent); + +- dput(parent); + TP_fast_assign_fsid(btrfs_sb(inode->i_sb)); + __entry->ino = btrfs_ino(BTRFS_I(inode)); + __entry->parent = btrfs_ino(BTRFS_I(parent_inode)); +-- +2.53.0 + diff --git a/queue-7.0/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch b/queue-7.0/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch new file mode 100644 index 0000000000..d25c271e23 --- /dev/null +++ b/queue-7.0/btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch @@ -0,0 +1,54 @@ +From c827d3717fc49360cf03d9e642cc9dd81e794716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:36:24 +0800 +Subject: btrfs: use BTRFS_FS_UPDATE_UUID_TREE_GEN flag for UUID tree rescan + check + +From: Dave Chen + +[ Upstream commit e70e3f858e084aee34a2206e5f4dd49a47673f6a ] + +The UUID tree rescan check in open_ctree() compares +fs_info->generation with the superblock's uuid_tree_generation. +This comparison is not reliable because fs_info->generation is +bumped at transaction start time in join_transaction(), while +uuid_tree_generation is only updated at commit time via +update_super_roots(). + +Between the early BTRFS_FS_UPDATE_UUID_TREE_GEN flag check and the +late rescan decision, mount operations such as file orphan cleanup +from an unclean shutdown start transactions without committing +them. This advances fs_info->generation past uuid_tree_generation +and produces a false-positive mismatch. + +Use the BTRFS_FS_UPDATE_UUID_TREE_GEN flag directly instead. The +flag was already set earlier in open_ctree() when the generations +were known to match, and accurately represents "UUID tree is up to +date" without being affected by subsequent transaction starts. + +Reviewed-by: Filipe Manana +Signed-off-by: Dave Chen +Signed-off-by: Robbie Ko +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 37ca4ef879029..ed95010bf4562 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -3674,7 +3674,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device + + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +- fs_info->generation != btrfs_super_uuid_tree_generation(disk_super))) { ++ !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))) { + btrfs_info(fs_info, "checking UUID tree"); + ret = btrfs_check_uuid_tree(fs_info); + if (ret) { +-- +2.53.0 + diff --git a/queue-7.0/btrfs-zoned-cap-delayed-refs-metadata-reservation-to.patch b/queue-7.0/btrfs-zoned-cap-delayed-refs-metadata-reservation-to.patch new file mode 100644 index 0000000000..3048dc519a --- /dev/null +++ b/queue-7.0/btrfs-zoned-cap-delayed-refs-metadata-reservation-to.patch @@ -0,0 +1,145 @@ +From e5644e9adc9e62580d188e0c09288da5c950b33f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 12:04:21 +0100 +Subject: btrfs: zoned: cap delayed refs metadata reservation to avoid + overcommit + +From: Johannes Thumshirn + +[ Upstream commit 7bcb04de982ff0718870112ad9f38c35cbca528b ] + +On zoned filesystems metadata space accounting can become overly optimistic +due to delayed refs reservations growing without a hard upper bound. + +The delayed_refs_rsv block reservation is allowed to speculatively grow and +is only backed by actual metadata space when refilled. On zoned devices this +can result in delayed_refs_rsv reserving a large portion of metadata space +that is already effectively unusable due to zone write pointer constraints. +As a result, space_info->may_use can grow far beyond the usable metadata +capacity, causing the allocator to believe space is available when it is not. + +This leads to premature ENOSPC failures and "cannot satisfy tickets" reports +even though commits would be able to make progress by flushing delayed refs. + +Analysis of "-o enospc_debug" dumps using a Python debug script +confirmed that delayed_refs_rsv was responsible for the majority of +metadata overcommit on zoned devices. By correlating space_info counters +(total, used, may_use, zone_unusable) across transactions, the analysis +showed that may_use continued to grow even after usable metadata space +was exhausted, with delayed refs refills accounting for the excess +reservations. + +Here's the output of the analysis: + + ====================================================================== + Space Type: METADATA + ====================================================================== + + Raw Values: + Total: 256.00 MB (268435456 bytes) + Used: 128.00 KB (131072 bytes) + Pinned: 16.00 KB (16384 bytes) + Reserved: 144.00 KB (147456 bytes) + May Use: 255.48 MB (267894784 bytes) + Zone Unusable: 192.00 KB (196608 bytes) + + Calculated Metrics: + Actually Usable: 255.81 MB (total - zone_unusable) + Committed: 255.77 MB (used + pinned + reserved + may_use) + Consumed: 320.00 KB (used + zone_unusable) + + Percentages: + Zone Unusable: 0.07% of total + May Use: 99.80% of total + +Fix this by adding a zoned-specific cap in btrfs_delayed_refs_rsv_refill(): +Before reserving additional metadata bytes, limit the delayed refs +reservation based on the usable metadata space (total bytes minus +zone_unusable). If the reservation would exceed this cap, return -EAGAIN +to trigger the existing flush/commit logic instead of overcommitting +metadata space. + +This preserves the existing reservation and flushing semantics while +preventing metadata overcommit on zoned devices. The change is limited to +metadata space and does not affect non-zoned filesystems. + +This patch addresses premature metadata ENOSPC conditions on zoned devices +and ensures delayed refs are throttled before exhausting usable metadata. + +Reviewed-by: Filipe Manana +Signed-off-by: Johannes Thumshirn +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/delayed-ref.c | 28 ++++++++++++++++++++++++++++ + fs/btrfs/transaction.c | 8 ++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c +index 3766ff29fbbb1..605858c2d9a95 100644 +--- a/fs/btrfs/delayed-ref.c ++++ b/fs/btrfs/delayed-ref.c +@@ -207,6 +207,30 @@ void btrfs_dec_delayed_refs_rsv_bg_updates(struct btrfs_fs_info *fs_info) + * This will refill the delayed block_rsv up to 1 items size worth of space and + * will return -ENOSPC if we can't make the reservation. + */ ++static int btrfs_zoned_cap_metadata_reservation(struct btrfs_space_info *space_info) ++{ ++ struct btrfs_fs_info *fs_info = space_info->fs_info; ++ struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv; ++ u64 usable; ++ u64 cap; ++ int ret = 0; ++ ++ if (!btrfs_is_zoned(fs_info)) ++ return 0; ++ ++ spin_lock(&space_info->lock); ++ usable = space_info->total_bytes - space_info->bytes_zone_unusable; ++ spin_unlock(&space_info->lock); ++ cap = usable >> 1; ++ ++ spin_lock(&block_rsv->lock); ++ if (block_rsv->size > cap) ++ ret = -EAGAIN; ++ spin_unlock(&block_rsv->lock); ++ ++ return ret; ++} ++ + int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info, + enum btrfs_reserve_flush_enum flush) + { +@@ -228,6 +252,10 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info, + if (!num_bytes) + return 0; + ++ ret = btrfs_zoned_cap_metadata_reservation(space_info); ++ if (ret) ++ return ret; ++ + ret = btrfs_reserve_metadata_bytes(space_info, num_bytes, flush); + if (ret) + return ret; +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index ec3c15fc7ae39..cc82d80a10670 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -678,6 +678,14 @@ start_transaction(struct btrfs_root *root, unsigned int num_items, + * here. + */ + ret = btrfs_delayed_refs_rsv_refill(fs_info, flush); ++ if (ret == -EAGAIN) { ++ ASSERT(btrfs_is_zoned(fs_info)); ++ ret = btrfs_commit_current_transaction(root); ++ if (ret) ++ goto reserve_fail; ++ ret = btrfs_delayed_refs_rsv_refill(fs_info, flush); ++ } ++ + if (ret) + goto reserve_fail; + } +-- +2.53.0 + diff --git a/queue-7.0/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch b/queue-7.0/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch new file mode 100644 index 0000000000..fbc5b2c157 --- /dev/null +++ b/queue-7.0/bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch @@ -0,0 +1,57 @@ +From fc266d0e707afb4fdd9c56cc1000cef4604a6707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:16:17 +0530 +Subject: bus: mhi: host: pci_generic: Add Qualcomm SDX35 modem + +From: Krishna Chaitanya Chundru + +[ Upstream commit 6a7084102bb9659f699005c420eb59eade6d3b4f ] + +Add support for sdx35 modem. Similar to SDX75, SDX35 can take longer to +transition to ready during power up, so use modem_qcom_v2_mhiv_config +configurations. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Qualcomm Device 011a + +Signed-off-by: Krishna Chaitanya Chundru +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260123-mhi_sdx35-v1-1-79440abf0c92@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index 51456cee70a21..0395a8ea52b0e 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -407,6 +407,16 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { + .sideband_wake = false, + }; + ++static const struct mhi_pci_dev_info mhi_qcom_sdx35_info = { ++ .name = "qcom-sdx35m", ++ .config = &modem_qcom_v2_mhiv_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .mru_default = 32768, ++ .sideband_wake = false, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { + .name = "qcom-sdx24", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -909,6 +919,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), ++ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), +-- +2.53.0 + diff --git a/queue-7.0/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch b/queue-7.0/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch new file mode 100644 index 0000000000..f83a40b9d5 --- /dev/null +++ b/queue-7.0/bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch @@ -0,0 +1,56 @@ +From dc1a75f1b578f6bae46bcac64b3e4e6e6b92f0c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:28:37 +0100 +Subject: bus: mhi: host: pci_generic: Add Telit FE912C04 modem support + +From: Daniele Palmas + +[ Upstream commit ac12b852b4ead4a586299c8f68cdcbcaf1bf6cbc ] + +Add SDX35 based modem Telit FE912C04, reusing FN920C04 configuration. + +01:00.0 Unassigned class [ff00]: Qualcomm Device 011a + Subsystem: Device 1c5d:2045 + +Signed-off-by: Daniele Palmas +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260323122837.3406521-1-dnlplm@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/host/pci_generic.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index 0395a8ea52b0e..66c282c5ffdc2 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -892,6 +892,16 @@ static const struct mhi_pci_dev_info mhi_telit_fe990b40_info = { + .edl_trigger = true, + }; + ++static const struct mhi_pci_dev_info mhi_telit_fe912c04_info = { ++ .name = "telit-fe912c04", ++ .config = &modem_telit_fn920c04_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++ .mru_default = 32768, ++ .edl_trigger = true, ++}; ++ + static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = { + .name = "netprisma-lcur57", + .edl = "qcom/prog_firehose_sdx24.mbn", +@@ -919,6 +929,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN920C04 (sdx35) */ + {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020), + .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info }, ++ /* Telit FE912C04 (sdx35) */ ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2045), ++ .driver_data = (kernel_ulong_t) &mhi_telit_fe912c04_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x011a), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx35_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), +-- +2.53.0 + diff --git a/queue-7.0/cachefiles-fix-error-return-when-vfs_mkdir-fails.patch b/queue-7.0/cachefiles-fix-error-return-when-vfs_mkdir-fails.patch new file mode 100644 index 0000000000..67d66e11bb --- /dev/null +++ b/queue-7.0/cachefiles-fix-error-return-when-vfs_mkdir-fails.patch @@ -0,0 +1,42 @@ +From a9bb0998d23f6da35ab4f628f86ed87427a5f622 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 18:34:06 +0800 +Subject: cachefiles: Fix error return when vfs_mkdir() fails + +From: Hongling Zeng + +[ Upstream commit 8a220d1c312c66194f4a33dd52d1fba42bc2b341 ] + +When vfs_mkdir() fails, the error code is not extracted from the +returned error pointer. This causes mkdir_error to be reached with +ret=0, which leads to returning ERR_PTR(0) (NULL) instead of a +proper error pointer. + +Fix this by extracting the error code from the error pointer when +vfs_mkdir() fails. + +Fixes: 406fad7698f5 ("cachefiles: Fix oops in vfs_mkdir from cachefiles_get_directory") +Signed-off-by: Hongling Zeng +Link: https://patch.msgid.link/20260513103406.202320-1-zenghongling@kylinos.cn +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/cachefiles/namei.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c +index eb9eb7683e3cc..6336d976d469b 100644 +--- a/fs/cachefiles/namei.c ++++ b/fs/cachefiles/namei.c +@@ -130,6 +130,8 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, + ret = cachefiles_inject_write_error(); + if (ret == 0) { + subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700, NULL); ++ if (IS_ERR(subdir)) ++ ret = PTR_ERR(subdir); + } else { + end_creating(subdir); + subdir = ERR_PTR(ret); +-- +2.53.0 + diff --git a/queue-7.0/cifs-client-stage-smb3_reconfigure-updates-and-resto.patch b/queue-7.0/cifs-client-stage-smb3_reconfigure-updates-and-resto.patch new file mode 100644 index 0000000000..f96ec30447 --- /dev/null +++ b/queue-7.0/cifs-client-stage-smb3_reconfigure-updates-and-resto.patch @@ -0,0 +1,317 @@ +From e816edeff0b476fcafc66b14df74c51870359489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 22:26:22 +0900 +Subject: cifs: client: stage smb3_reconfigure() updates and restore ctx on + failure + +From: DaeMyung Kang + +[ Upstream commit ab26dfeba278b0efbcea012f1698cf524d9b5695 ] + +smb3_reconfigure() moves strings out of cifs_sb->ctx before the +multichannel update, so a later failure can leave the live context +with NULL strings or options that do not match the session. + +Stage the new ctx separately, commit it only on success, and restore +the snapshot on failure. Also make smb3_sync_session_ctx_passwords() +all-or-nothing. + +Commit session passwords before channel updates so newly added channels +authenticate with the staged credentials. + +Fixes: ef529f655a2c ("cifs: client: allow changing multichannel mount options on remount") +Reported-by: RAJASI MANDAL +Closes: https://lore.kernel.org/lkml/CAEY6_V1+dzW3OD5zqXhsWyXwrDTrg5tAMGZ1AJ7_GAuRE+aevA@mail.gmail.com/ +Link: https://lore.kernel.org/lkml/xkr2dlvgibq5j6gkcxd3yhhnj4atgxw2uy4eug2pxm7wy7nbms@iq6cf5taa65v/ +Reviewed-by: Henrique Carvalho +Signed-off-by: DaeMyung Kang +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/fs_context.c | 161 +++++++++++++++++++++++++------------ + 1 file changed, 108 insertions(+), 53 deletions(-) + +diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c +index a46764c247107..59598d334bae1 100644 +--- a/fs/smb/client/fs_context.c ++++ b/fs/smb/client/fs_context.c +@@ -761,7 +761,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + static int smb3_fs_context_parse_monolithic(struct fs_context *fc, + void *data); + static int smb3_get_tree(struct fs_context *fc); +-static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels); ++static void smb3_sync_ses_chan_max(struct cifs_ses *ses, size_t max_channels); + static int smb3_reconfigure(struct fs_context *fc); + + static const struct fs_context_operations smb3_fs_context_ops = { +@@ -1035,25 +1035,34 @@ do { \ + + int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) + { ++ char *password = NULL, *password2 = NULL; ++ + if (ses->password && + cifs_sb->ctx->password && + strcmp(ses->password, cifs_sb->ctx->password)) { +- kfree_sensitive(cifs_sb->ctx->password); +- cifs_sb->ctx->password = kstrdup(ses->password, GFP_KERNEL); +- if (!cifs_sb->ctx->password) ++ password = kstrdup(ses->password, GFP_KERNEL); ++ if (!password) + return -ENOMEM; + } + if (ses->password2 && + cifs_sb->ctx->password2 && + strcmp(ses->password2, cifs_sb->ctx->password2)) { +- kfree_sensitive(cifs_sb->ctx->password2); +- cifs_sb->ctx->password2 = kstrdup(ses->password2, GFP_KERNEL); +- if (!cifs_sb->ctx->password2) { +- kfree_sensitive(cifs_sb->ctx->password); +- cifs_sb->ctx->password = NULL; ++ password2 = kstrdup(ses->password2, GFP_KERNEL); ++ if (!password2) { ++ kfree_sensitive(password); + return -ENOMEM; + } + } ++ ++ if (password) { ++ kfree_sensitive(cifs_sb->ctx->password); ++ cifs_sb->ctx->password = password; ++ } ++ if (password2) { ++ kfree_sensitive(cifs_sb->ctx->password2); ++ cifs_sb->ctx->password2 = password2; ++ } ++ + return 0; + } + +@@ -1066,7 +1075,7 @@ int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_se + * with the session's channel lock. This should be called whenever the maximum + * allowed channels for a session changes (e.g., after a remount or reconfigure). + */ +-static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels) ++static void smb3_sync_ses_chan_max(struct cifs_ses *ses, size_t max_channels) + { + spin_lock(&ses->chan_lock); + ses->chan_max = max_channels; +@@ -1076,12 +1085,15 @@ static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channe + static int smb3_reconfigure(struct fs_context *fc) + { + struct smb3_fs_context *ctx = smb3_fc2context(fc); ++ struct smb3_fs_context *new_ctx = NULL; ++ struct smb3_fs_context *old_ctx = NULL; + struct dentry *root = fc->root; + struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); + struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses; + unsigned int rsize = ctx->rsize, wsize = ctx->wsize; + char *new_password = NULL, *new_password2 = NULL; + bool need_recon = false; ++ bool need_mchan_update; + int rc; + + if (ses->expired_pwd) +@@ -1091,6 +1103,16 @@ static int smb3_reconfigure(struct fs_context *fc) + if (rc) + return rc; + ++ old_ctx = kzalloc_obj(*old_ctx); ++ if (!old_ctx) ++ return -ENOMEM; ++ ++ rc = smb3_fs_context_dup(old_ctx, cifs_sb->ctx); ++ if (rc) { ++ kfree(old_ctx); ++ return rc; ++ } ++ + /* + * We can not change UNC/username/password/domainname/ + * workstation_name/nodename/iocharset +@@ -1100,16 +1122,22 @@ static int smb3_reconfigure(struct fs_context *fc) + STEAL_STRING(cifs_sb, ctx, UNC); + STEAL_STRING(cifs_sb, ctx, source); + STEAL_STRING(cifs_sb, ctx, username); ++ STEAL_STRING(cifs_sb, ctx, domainname); ++ STEAL_STRING(cifs_sb, ctx, nodename); ++ STEAL_STRING(cifs_sb, ctx, iocharset); + +- if (need_recon == false) ++ if (!need_recon) { + STEAL_STRING_SENSITIVE(cifs_sb, ctx, password); +- else { ++ } else { + if (ctx->password) { + new_password = kstrdup(ctx->password, GFP_KERNEL); +- if (!new_password) +- return -ENOMEM; +- } else ++ if (!new_password) { ++ rc = -ENOMEM; ++ goto restore_ctx; ++ } ++ } else { + STEAL_STRING_SENSITIVE(cifs_sb, ctx, password); ++ } + } + + /* +@@ -1119,11 +1147,29 @@ static int smb3_reconfigure(struct fs_context *fc) + if (ctx->password2) { + new_password2 = kstrdup(ctx->password2, GFP_KERNEL); + if (!new_password2) { +- kfree_sensitive(new_password); +- return -ENOMEM; ++ rc = -ENOMEM; ++ goto restore_ctx; + } +- } else ++ } else { + STEAL_STRING_SENSITIVE(cifs_sb, ctx, password2); ++ } ++ ++ /* if rsize or wsize not passed in on remount, use previous values */ ++ ctx->rsize = rsize ? CIFS_ALIGN_RSIZE(fc, rsize) : cifs_sb->ctx->rsize; ++ ctx->wsize = wsize ? CIFS_ALIGN_WSIZE(fc, wsize) : cifs_sb->ctx->wsize; ++ ++ new_ctx = kzalloc_obj(*new_ctx); ++ if (!new_ctx) { ++ rc = -ENOMEM; ++ goto restore_ctx; ++ } ++ ++ rc = smb3_fs_context_dup(new_ctx, ctx); ++ if (rc) ++ goto restore_ctx; ++ ++ need_mchan_update = ctx->multichannel != cifs_sb->ctx->multichannel || ++ ctx->max_channels != cifs_sb->ctx->max_channels; + + /* + * we may update the passwords in the ses struct below. Make sure we do +@@ -1134,54 +1180,55 @@ static int smb3_reconfigure(struct fs_context *fc) + /* + * smb2_reconnect may swap password and password2 in case session setup + * failed. First get ctx passwords in sync with ses passwords. It should +- * be okay to do this even if this function were to return an error at a +- * later stage ++ * be done before committing new passwords. + */ + rc = smb3_sync_session_ctx_passwords(cifs_sb, ses); + if (rc) { + mutex_unlock(&ses->session_mutex); +- kfree_sensitive(new_password); +- kfree_sensitive(new_password2); +- return rc; ++ goto cleanup_new_ctx; ++ } ++ ++ /* ++ * If multichannel or max_channels has changed, update the session's channels accordingly. ++ * This may add or remove channels to match the new configuration. ++ */ ++ if (need_mchan_update) { ++ /* Prevent concurrent scaling operations */ ++ spin_lock(&ses->ses_lock); ++ if (ses->flags & CIFS_SES_FLAG_SCALE_CHANNELS) { ++ spin_unlock(&ses->ses_lock); ++ mutex_unlock(&ses->session_mutex); ++ rc = -EINVAL; ++ goto cleanup_new_ctx; ++ } ++ ses->flags |= CIFS_SES_FLAG_SCALE_CHANNELS; ++ spin_unlock(&ses->ses_lock); + } + + /* +- * now that allocations for passwords are done, commit them ++ * Commit session passwords before any channel work so newly added ++ * channels authenticate with the new credentials. + */ + if (new_password) { + kfree_sensitive(ses->password); + ses->password = new_password; ++ new_password = NULL; + } + if (new_password2) { + kfree_sensitive(ses->password2); + ses->password2 = new_password2; ++ new_password2 = NULL; + } + +- /* +- * If multichannel or max_channels has changed, update the session's channels accordingly. +- * This may add or remove channels to match the new configuration. +- */ +- if ((ctx->multichannel != cifs_sb->ctx->multichannel) || +- (ctx->max_channels != cifs_sb->ctx->max_channels)) { +- ++ if (need_mchan_update) { + /* Synchronize ses->chan_max with the new mount context */ + smb3_sync_ses_chan_max(ses, ctx->max_channels); +- /* Now update the session's channels to match the new configuration */ +- /* Prevent concurrent scaling operations */ +- spin_lock(&ses->ses_lock); +- if (ses->flags & CIFS_SES_FLAG_SCALE_CHANNELS) { +- spin_unlock(&ses->ses_lock); +- mutex_unlock(&ses->session_mutex); +- return -EINVAL; +- } +- ses->flags |= CIFS_SES_FLAG_SCALE_CHANNELS; +- spin_unlock(&ses->ses_lock); + + mutex_unlock(&ses->session_mutex); + +- rc = smb3_update_ses_channels(ses, ses->server, +- false /* from_reconnect */, +- false /* disable_mchan */); ++ smb3_update_ses_channels(ses, ses->server, ++ false /* from_reconnect */, ++ false /* disable_mchan */); + + /* Clear scaling flag after operation */ + spin_lock(&ses->ses_lock); +@@ -1191,22 +1238,30 @@ static int smb3_reconfigure(struct fs_context *fc) + mutex_unlock(&ses->session_mutex); + } + +- STEAL_STRING(cifs_sb, ctx, domainname); +- STEAL_STRING(cifs_sb, ctx, nodename); +- STEAL_STRING(cifs_sb, ctx, iocharset); +- +- /* if rsize or wsize not passed in on remount, use previous values */ +- ctx->rsize = rsize ? CIFS_ALIGN_RSIZE(fc, rsize) : cifs_sb->ctx->rsize; +- ctx->wsize = wsize ? CIFS_ALIGN_WSIZE(fc, wsize) : cifs_sb->ctx->wsize; +- + smb3_cleanup_fs_context_contents(cifs_sb->ctx); +- rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); ++ memcpy(cifs_sb->ctx, new_ctx, sizeof(*new_ctx)); ++ kfree(new_ctx); ++ new_ctx = NULL; ++ smb3_cleanup_fs_context(old_ctx); ++ old_ctx = NULL; + smb3_update_mnt_flags(cifs_sb); + #ifdef CONFIG_CIFS_DFS_UPCALL + if (!rc) + rc = dfs_cache_remount_fs(cifs_sb); + #endif + ++ return rc; ++ ++cleanup_new_ctx: ++ smb3_cleanup_fs_context_contents(new_ctx); ++restore_ctx: ++ kfree(new_ctx); ++ kfree_sensitive(new_password); ++ kfree_sensitive(new_password2); ++ smb3_cleanup_fs_context_contents(cifs_sb->ctx); ++ memcpy(cifs_sb->ctx, old_ctx, sizeof(*old_ctx)); ++ kfree(old_ctx); ++ + return rc; + } + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch b/queue-7.0/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch new file mode 100644 index 0000000000..2b734b45e2 --- /dev/null +++ b/queue-7.0/clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch @@ -0,0 +1,70 @@ +From fdc2ba675872118a3dd18c05b5e31a581110780b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:50:28 +0800 +Subject: clk: qcom: rcg2: expand frac table for mdss_pixel_clk_src + +From: Pengyu Luo + +[ Upstream commit 0f5c8f03d990f9be9908a08a701c324e113554d2 ] + +Recently, when testing 10-bit dsi C-PHY panel, clks are different +from the usual. (dsi0_phy_pll_out_dsiclk's parent is dsi0_pll_bit_clk +now (dsiclk_sel = 0)) And we failed to set dsiclk's children. + +dsi_link_clk_set_rate_6g: Set clk rates: pclk=172992000, byteclk=108120000 + +byteclk was set first to 108120000, so the vco rate was set to +108120000 * 7 * 1 * 1 = 756840000. When we was trying to set +172992000 on mdss_pixel_clk_src later. + +Since there was no matched ratio, we failed to set it. And dsiclk +divider ratio was set to 15:1 (wrong cached register value 0xf and +didn't update), we finally got 50455997, apparently wrong. + + dsi0vco_clk 1 1 0 756839941 + dsi0_pll_out_div_clk 1 1 0 756839941 + dsi0_pll_post_out_div_clk 0 0 0 216239983 + dsi0_pll_bit_clk 2 2 0 756839941 + dsi0_phy_pll_out_dsiclk 2 2 0 50455997 + disp_cc_mdss_pclk1_clk_src 1 1 0 50455997 + dsi0_pll_by_2_bit_clk 0 0 0 378419970 + dsi0_phy_pll_out_byteclk 2 2 0 108119991 + disp_cc_mdss_byte1_clk_src 2 2 0 108119991 + +Downstream clk_summary shows the mdss_pixel_clk_src support the +ratio(35:16) + + dsi0_phy_pll_out_dsiclk 2 2 0 378420000 + disp_cc_mdss_pclk1_clk_src 1 1 0 172992000 + dsi0_phy_pll_out_byteclk 2 2 0 108120000 + disp_cc_mdss_byte1_clk_src 2 2 0 108120000 + +After checking downstream source, 15:4 also seems to be supported, +add them two. + +Signed-off-by: Pengyu Luo +Reviewed-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260321095029.2259489-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/clk-rcg2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index fc696b66ccda9..6064a0e17d519 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -1117,6 +1117,8 @@ static const struct frac_entry frac_table_pixel[] = { + { 4, 9 }, + { 1, 1 }, + { 2, 3 }, ++ { 16, 35}, ++ { 4, 15}, + { } + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch b/queue-7.0/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch new file mode 100644 index 0000000000..914186f7af --- /dev/null +++ b/queue-7.0/clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch @@ -0,0 +1,45 @@ +From abf0fec465f44ac0860c943535fe17e3f59b3477 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:22:04 +0800 +Subject: clk: spear: fix resource leak in clk_register_vco_pll() + +From: Haoxiang Li + +[ Upstream commit a0ac82cbed1007afd89e30940fe2335b61666783 ] + +Add a goto label in clk_register_vco_pll(), unregister vco_clk +if tpll_clk is failed to be registered. + +Signed-off-by: Haoxiang Li +Acked-by: Viresh Kumar +Link: https://lore.kernel.org/r/20260325062204.169648-1-lihaoxiang@isrc.iscas.ac.cn +Signed-off-by: Arnd Bergmann +Signed-off-by: Sasha Levin +--- + drivers/clk/spear/clk-vco-pll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c +index 601e123f5c4b5..faba727e2f843 100644 +--- a/drivers/clk/spear/clk-vco-pll.c ++++ b/drivers/clk/spear/clk-vco-pll.c +@@ -343,13 +343,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) +- goto free_pll; ++ goto unregister_clk; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + ++unregister_clk: ++ clk_unregister(vco_clk); + free_pll: + kfree(pll); + free_vco: +-- +2.53.0 + diff --git a/queue-7.0/coda_flag_children-fix-a-uaf.patch b/queue-7.0/coda_flag_children-fix-a-uaf.patch new file mode 100644 index 0000000000..562a94c5b1 --- /dev/null +++ b/queue-7.0/coda_flag_children-fix-a-uaf.patch @@ -0,0 +1,44 @@ +From 5e0b3758ff73212f1ac88f09e2d51ce12bcc3902 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:33:37 -0500 +Subject: coda_flag_children(): fix a UAF + +From: Al Viro + +[ Upstream commit e252ed8988578f01da5a4f5aa4c2269f96f03951 ] + +if de goes negative right under us, there's nothing to prevent inode +getting freed just as we call coda_flag_inode(). We are not holding +->d_lock, so it's not impossible. Not going to be reproducible on +bare hardware unless it's a realtime config, but it could happen on KVM. + +Trivial to fix - just hold rcu_read_lock() over that loop. + +Signed-off-by: Al Viro +Signed-off-by: Sasha Levin +--- + fs/coda/cache.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/coda/cache.c b/fs/coda/cache.c +index 970f0022ec528..2451312963004 100644 +--- a/fs/coda/cache.c ++++ b/fs/coda/cache.c +@@ -93,12 +93,14 @@ static void coda_flag_children(struct dentry *parent, int flag) + struct dentry *de; + + spin_lock(&parent->d_lock); ++ rcu_read_lock(); + hlist_for_each_entry(de, &parent->d_children, d_sib) { + struct inode *inode = d_inode_rcu(de); + /* don't know what to do with negative dentries */ + if (inode) + coda_flag_inode(inode, flag); + } ++ rcu_read_unlock(); + spin_unlock(&parent->d_lock); + } + +-- +2.53.0 + diff --git a/queue-7.0/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch b/queue-7.0/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch new file mode 100644 index 0000000000..1d840c4167 --- /dev/null +++ b/queue-7.0/crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch @@ -0,0 +1,46 @@ +From 0c96642fd5ef1d9d4249c3e736886f944c27cc33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:59:14 -0800 +Subject: crypto: tcrypt - clamp num_mb to avoid divide-by-zero + +From: Saeed Mirzamohammadi + +[ Upstream commit 32e76e3757e89f370bf2ac8dba8aeb133071834e ] + +Passing num_mb=0 to the multibuffer speed tests leaves test_mb_aead_cycles() +and test_mb_acipher_cycles() dividing by (8 * num_mb). With sec=0 (the +default), the module prints "1 operation in ..." and hits a divide-by-zero +fault. + +Force num_mb to at least 1 during module init and warn the caller so the +warm-up loop and the final report stay well-defined. + +To reproduce: +sudo modprobe tcrypt mode=600 num_mb=0 + +Signed-off-by: Saeed Mirzamohammadi +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/tcrypt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index aded375461374..61c8cf55c4f1e 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -2808,6 +2808,11 @@ static int __init tcrypt_mod_init(void) + goto err_free_tv; + } + ++ if (!num_mb) { ++ pr_warn("num_mb must be at least 1; forcing to 1\n"); ++ num_mb = 1; ++ } ++ + err = do_test(alg, type, mask, mode, num_mb); + + if (err) { +-- +2.53.0 + diff --git a/queue-7.0/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch b/queue-7.0/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch new file mode 100644 index 0000000000..e4784f738a --- /dev/null +++ b/queue-7.0/cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch @@ -0,0 +1,102 @@ +From d25081e0fd6ea40e8735b54c44079cbcda81e6aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 15:06:32 +0800 +Subject: cxl/pci: Hold memdev lock in cxl_event_trace_record() + +From: Li Ming + +[ Upstream commit dc372e5f429ced834d81ff12a945397dc43585a8 ] + +cxl_event_config() invokes cxl_mem_get_event_record() to get remain +event logs from CXL device during cxl_pci_probe(). If CXL memdev probing +failed before that, it is possible to access an invalid endpoint. So +adding a cxlmd->driver binding status checking inside +cxl_dpa_to_region() to ensure the corresponding endpoint is valid. + +Besides, cxl_event_trace_record() needs to hold memdev lock to invoke +cxl_dpa_to_region() to ensure the memdev probing completed. It is +possible that cxl_event_trace_record() is invoked during the CXL memdev +probing, especially user or cxl_acpi triggers CXL memdev re-probing. + +Suggested-by: Dan Williams +Reviewed-by: Dan Williams +Reviewed-by: Dave Jiang +Signed-off-by: Li Ming +Link: https://patch.msgid.link/20260314-fix_access_endpoint_without_drv_check-v2-3-4c09edf2e1db@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/mbox.c | 5 +++-- + drivers/cxl/core/region.c | 8 +++++--- + drivers/cxl/cxlmem.h | 2 +- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c +index 12386d9127054..c4a2a1ba13ca6 100644 +--- a/drivers/cxl/core/mbox.c ++++ b/drivers/cxl/core/mbox.c +@@ -893,7 +893,7 @@ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) + } + EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, "CXL"); + +-void cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++void cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt) +@@ -920,6 +920,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + * translations. Take topology mutation locks and lookup + * { HPA, REGION } from { DPA, MEMDEV } in the event record. + */ ++ guard(device)(&cxlmd->dev); + guard(rwsem_read)(&cxl_rwsem.region); + guard(rwsem_read)(&cxl_rwsem.dpa); + +@@ -968,7 +969,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + } + EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, "CXL"); + +-static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++static void __cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + struct cxl_event_record_raw *record) + { +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index c37ae0b28bbbc..373551022a2b3 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -2950,13 +2950,15 @@ static int __cxl_dpa_to_region(struct device *dev, void *arg) + struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) + { + struct cxl_dpa_to_region_context ctx; +- struct cxl_port *port; ++ struct cxl_port *port = cxlmd->endpoint; ++ ++ if (!cxlmd->dev.driver) ++ return NULL; + + ctx = (struct cxl_dpa_to_region_context) { + .dpa = dpa, + }; +- port = cxlmd->endpoint; +- if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) ++ if (cxl_num_decoders_committed(port)) + device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); + + return ctx.cxlr; +diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h +index e21d744d639bd..7a34a19c02c87 100644 +--- a/drivers/cxl/cxlmem.h ++++ b/drivers/cxl/cxlmem.h +@@ -864,7 +864,7 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, + void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, + unsigned long *cmds); + void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status); +-void cxl_event_trace_record(const struct cxl_memdev *cxlmd, ++void cxl_event_trace_record(struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt); +-- +2.53.0 + diff --git a/queue-7.0/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch b/queue-7.0/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch new file mode 100644 index 0000000000..3e53349228 --- /dev/null +++ b/queue-7.0/cxl-region-fix-use-after-free-from-auto-assembly-fai.patch @@ -0,0 +1,137 @@ +From ba1aba13793aa64b7c90235dffa68253b6267e57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:28:13 -0700 +Subject: cxl/region: Fix use-after-free from auto assembly failure + +From: Dan Williams + +[ Upstream commit 87805c32e6ad7b5ce2d9f7f47e76081857a4a335 ] + +The following crash signature results from region destruction while an +endpoint decoder is staged, but not fully attached. + +[ dj: Moved bus_find_device( to next line. ] + +Signed-off-by: Dan Williams +Reviewed-by: Ira Weiny +Reviewed-by: Alison Schofield +Reviewed-by: Dave Jiang +Link: https://patch.msgid.link/20260327052821.440749-2-dan.j.williams@intel.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/region.c | 54 ++++++++++++++++++++++++++++++++++++++- + drivers/cxl/cxl.h | 6 +++-- + 2 files changed, 57 insertions(+), 3 deletions(-) + +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index 373551022a2b3..1e97443535167 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -1063,6 +1063,14 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr, + + if (!cxld->region) { + cxld->region = cxlr; ++ ++ /* ++ * Now that cxld->region is set the intermediate staging state ++ * can be cleared. ++ */ ++ if (cxld == &cxled->cxld && ++ cxled->state == CXL_DECODER_STATE_AUTO_STAGED) ++ cxled->state = CXL_DECODER_STATE_AUTO; + get_device(&cxlr->dev); + } + +@@ -1804,6 +1812,7 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr, + pos = p->nr_targets; + p->targets[pos] = cxled; + cxled->pos = pos; ++ cxled->state = CXL_DECODER_STATE_AUTO_STAGED; + p->nr_targets++; + + return 0; +@@ -2153,6 +2162,47 @@ static int cxl_region_attach(struct cxl_region *cxlr, + return 0; + } + ++static int cxl_region_by_target(struct device *dev, const void *data) ++{ ++ const struct cxl_endpoint_decoder *cxled = data; ++ struct cxl_region_params *p; ++ struct cxl_region *cxlr; ++ ++ if (!is_cxl_region(dev)) ++ return 0; ++ ++ cxlr = to_cxl_region(dev); ++ p = &cxlr->params; ++ return p->targets[cxled->pos] == cxled; ++} ++ ++/* ++ * When an auto-region fails to assemble the decoder may be listed as a target, ++ * but not fully attached. ++ */ ++static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled) ++{ ++ struct cxl_region_params *p; ++ struct cxl_region *cxlr; ++ int pos = cxled->pos; ++ ++ if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED) ++ return; ++ ++ struct device *dev __free(put_device) = ++ bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target); ++ if (!dev) ++ return; ++ ++ cxlr = to_cxl_region(dev); ++ p = &cxlr->params; ++ ++ p->nr_targets--; ++ cxled->state = CXL_DECODER_STATE_AUTO; ++ cxled->pos = -1; ++ p->targets[pos] = NULL; ++} ++ + static struct cxl_region * + __cxl_decoder_detach(struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled, int pos, +@@ -2176,8 +2226,10 @@ __cxl_decoder_detach(struct cxl_region *cxlr, + cxled = p->targets[pos]; + } else { + cxlr = cxled->cxld.region; +- if (!cxlr) ++ if (!cxlr) { ++ cxl_cancel_auto_attach(cxled); + return NULL; ++ } + p = &cxlr->params; + } + +diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h +index 9b947286eb9b0..30a31968f2663 100644 +--- a/drivers/cxl/cxl.h ++++ b/drivers/cxl/cxl.h +@@ -378,12 +378,14 @@ struct cxl_decoder { + }; + + /* +- * Track whether this decoder is reserved for region autodiscovery, or +- * free for userspace provisioning. ++ * Track whether this decoder is free for userspace provisioning, reserved for ++ * region autodiscovery, whether it is started connecting (awaiting other ++ * peers), or has completed auto assembly. + */ + enum cxl_decoder_state { + CXL_DECODER_STATE_MANUAL, + CXL_DECODER_STATE_AUTO, ++ CXL_DECODER_STATE_AUTO_STAGED, + }; + + /** +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-prevent-entering-passthrough-mode-after-unc.patch b/queue-7.0/dm-cache-prevent-entering-passthrough-mode-after-unc.patch new file mode 100644 index 0000000000..d54832050c --- /dev/null +++ b/queue-7.0/dm-cache-prevent-entering-passthrough-mode-after-unc.patch @@ -0,0 +1,167 @@ +From b28930b204f3249458e456507728dee1b6931216 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:11 +0800 +Subject: dm cache: prevent entering passthrough mode after unclean shutdown + +From: Ming-Hung Tsai + +[ Upstream commit a373b3d5289e50ab26d4cf776bf5891436ff3658 ] + +dm-cache assumes all cache blocks are dirty when it recovers from an +unclean shutdown. Given that the passthrough mode doesn't handle dirty +blocks, we should not load a cache in passthrough mode if it was not +cleanly shut down; or we'll risk data loss while updating an actually +dirty block. + +Also bump the target version to 2.4.0 to mark completion of passthrough +mode fixes. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty blocks. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Write the first cache block dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Ensure the number of dirty blocks is 1. This status query triggers + metadata commit without flushing the dirty bitset, setting up the + unclean shutdown state. + +dmsetup status cache | awk '{print $14}' + +4. Force reboot, leaving the cache uncleanly shutdown. + +echo b > /proc/sysrq-trigger + +5. Activate the above cache components, and verify the first data block + remains dirty. + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/mapper/cdata of=/tmp/cb0.bin bs=64k count=1 +dd if=/dev/mapper/corig of=/tmp/ob0.bin bs=64k count=1 +md5sum /tmp/cb0.bin /tmp/ob0.bin # expected to be different + +6. Try bringing up the cache in passthrough mode. It succeeds, while the + first cache block was loaded dirty due to unclean shutdown, violates + the passthrough mode's constraints. + +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup status cache | awk '{print $14}' + +7. (Optional) Demonstrate the integrity issue: invalidating the dirty + block in passthrough mode doesn't write back the dirty data, causing + data loss. + +fio --filename=/dev/mapper/cache --name=invalidate --rw=write --bs=4k \ +--direct=1 --size=4k # overwrite the first 4k to trigger invalidation +dmsetup remove cache +dd if=/dev/mapper/corig of=/tmp/ob0new.bin bs=64k count=1 +cb0sum=$(dd if=/tmp/cb0.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +ob0newsum=$(dd if=/tmp/ob0new.bin bs=4k count=15 skip=1 | md5sum | \ +awk '{print $1}') +echo "$cb0sum, $ob0newsum" # remaining 60k should differ (data loss) + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 9 +++++++++ + drivers/md/dm-cache-metadata.h | 5 +++++ + drivers/md/dm-cache-target.c | 19 ++++++++++++++++++- + 3 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index ddfc1a3cf2f53..acd9b179fcb3f 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1816,3 +1816,12 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + + return r; + } ++ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result) ++{ ++ READ_LOCK(cmd); ++ *result = cmd->clean_when_opened; ++ READ_UNLOCK(cmd); ++ ++ return 0; ++} +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 2f107e7c67d0a..91f8706b41fdd 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -141,6 +141,11 @@ void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); + int dm_cache_metadata_abort(struct dm_cache_metadata *cmd); + ++/* ++ * Query method. Was the metadata cleanly shut down when opened? ++ */ ++int dm_cache_metadata_clean_when_opened(struct dm_cache_metadata *cmd, bool *result); ++ + /*----------------------------------------------------------------*/ + + #endif /* DM_CACHE_METADATA_H */ +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index af7a2571988b4..097315a9bf0f1 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2954,6 +2954,9 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) + + static bool can_resume(struct cache *cache) + { ++ bool clean_when_opened; ++ int r; ++ + /* + * Disallow retrying the resume operation for devices that failed the + * first resume attempt, as the failure leaves the policy object partially +@@ -2970,6 +2973,20 @@ static bool can_resume(struct cache *cache) + return false; + } + ++ if (passthrough_mode(cache)) { ++ r = dm_cache_metadata_clean_when_opened(cache->cmd, &clean_when_opened); ++ if (r) { ++ DMERR("%s: failed to query metadata flags", cache_device_name(cache)); ++ return false; ++ } ++ ++ if (!clean_when_opened) { ++ DMERR("%s: unable to resume into passthrough mode after unclean shutdown", ++ cache_device_name(cache)); ++ return false; ++ } ++ } ++ + return true; + } + +@@ -3535,7 +3552,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 3, 0}, ++ .version = {2, 4, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-7.0/dm-integrity-fix-mismatched-queue-limits.patch b/queue-7.0/dm-integrity-fix-mismatched-queue-limits.patch new file mode 100644 index 0000000000..f47c5d7e8b --- /dev/null +++ b/queue-7.0/dm-integrity-fix-mismatched-queue-limits.patch @@ -0,0 +1,48 @@ +From bb08d50907b16f520b44d7f3ff36b953997ee131 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:36:06 -0700 +Subject: dm-integrity: fix mismatched queue limits + +From: Keith Busch + +[ Upstream commit 6ebf3b6c6f16fda0568aa4207c6cd398f983c354 ] + +A user can integritysetup a device with a backing device using a 4k +logical block size, but request the dm device use 1k or 2k. This +mismatch creates an inconsistency such that the dm device would report +limits for IO that it can't actually execute. Fix this by using the +backing device's limits if they are larger. + +Signed-off-by: Keith Busch +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-integrity.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index 06e805902151c..8dfd498ed1ffd 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -4047,9 +4047,15 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim + struct dm_integrity_c *ic = ti->private; + + if (ic->sectors_per_block > 1) { +- limits->logical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->physical_block_size = ic->sectors_per_block << SECTOR_SHIFT; +- limits->io_min = ic->sectors_per_block << SECTOR_SHIFT; ++ limits->logical_block_size = ++ max(limits->logical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->physical_block_size = ++ max(limits->physical_block_size, ++ ic->sectors_per_block << SECTOR_SHIFT); ++ limits->io_min = ++ max(limits->io_min, ++ ic->sectors_per_block << SECTOR_SHIFT); + limits->dma_alignment = limits->logical_block_size - 1; + limits->discard_granularity = ic->sectors_per_block << SECTOR_SHIFT; + } +-- +2.53.0 + diff --git a/queue-7.0/dm-vdo-indexer-validate-saved-zone-count.patch b/queue-7.0/dm-vdo-indexer-validate-saved-zone-count.patch new file mode 100644 index 0000000000..eb053d68ab --- /dev/null +++ b/queue-7.0/dm-vdo-indexer-validate-saved-zone-count.patch @@ -0,0 +1,36 @@ +From 5e825401fd20400c3ba69430d2529b01716ecdc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:54 -0500 +Subject: dm vdo indexer: validate saved zone count + +From: Matthew Sakai + +[ Upstream commit 9e809bb1defe9be7fed2e21552c6b03b2694394d ] + +Verify that the loaded zone count is in the valid range +before using it as a loop iterator. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/indexer/index-layout.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/md/dm-vdo/indexer/index-layout.c b/drivers/md/dm-vdo/indexer/index-layout.c +index 61edf2b72427d..37144249f7ba6 100644 +--- a/drivers/md/dm-vdo/indexer/index-layout.c ++++ b/drivers/md/dm-vdo/indexer/index-layout.c +@@ -1445,6 +1445,9 @@ static int __must_check reconstruct_index_save(struct index_save_layout *isl, + u64 last_block = next_block + isl->index_save.block_count; + + isl->zone_count = table->header.region_count - 3; ++ if (isl->zone_count > MAX_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); + + last_region = &table->regions[table->header.region_count - 1]; + if (last_region->kind == RL_KIND_EMPTY) { +-- +2.53.0 + diff --git a/queue-7.0/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch b/queue-7.0/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch new file mode 100644 index 0000000000..0e87f59f7b --- /dev/null +++ b/queue-7.0/dm-vdo-slab-depot-validate-old-zone-count-on-load.patch @@ -0,0 +1,37 @@ +From bdb314c27594e21c48e2a33dfa752427b8d87f53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 10:05:55 -0500 +Subject: dm vdo slab-depot: validate old zone count on load + +From: Matthew Sakai + +[ Upstream commit b3929b2cc2a6003b8e301e6540c651e60d24dcb4 ] + +Verify the old zone count has a valid value before using +it to compute slab summary entry offsets. + +Signed-off-by: Matthew Sakai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-vdo/slab-depot.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c +index 034ecaa51f481..ad00afc2c168d 100644 +--- a/drivers/md/dm-vdo/slab-depot.c ++++ b/drivers/md/dm-vdo/slab-depot.c +@@ -4262,6 +4262,10 @@ int vdo_decode_slab_depot(struct slab_depot_state_2_0 state, struct vdo *vdo, + } + slab_size_shift = ilog2(slab_size); + ++ if (state.zone_count > MAX_VDO_PHYSICAL_ZONES) ++ return vdo_log_error_strerror(UDS_CORRUPT_DATA, ++ "invalid zone count"); ++ + result = vdo_allocate_extended(struct slab_depot, + vdo->thread_config.physical_zone_count, + struct block_allocator, __func__, &depot); +-- +2.53.0 + diff --git a/queue-7.0/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch b/queue-7.0/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch new file mode 100644 index 0000000000..0cda632625 --- /dev/null +++ b/queue-7.0/drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch @@ -0,0 +1,40 @@ +From 0fc02b8ac9584e40b972689f82ed0e5d87946426 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:48:39 +0100 +Subject: drivers/virt: pkvm: Add Kconfig dependency on DMA_RESTRICTED_POOL + +From: Will Deacon + +[ Upstream commit 61135967fa76d37883d90ccccc5a1cb73e90b94d ] + +pKVM guests practically rely on CONFIG_DMA_RESTRICTED_POOL=y in order +to establish shared memory regions with the host for virtio buffers. + +Make CONFIG_ARM_PKVM_GUEST depend on CONFIG_DMA_RESTRICTED_POOL to avoid +the inevitable segmentation faults experience if you have the former but +not the latter. + +Reported-by: Marc Zyngier +Signed-off-by: Will Deacon +Link: https://patch.msgid.link/20260330144841.26181-39-will@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Sasha Levin +--- + drivers/virt/coco/pkvm-guest/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/virt/coco/pkvm-guest/Kconfig b/drivers/virt/coco/pkvm-guest/Kconfig +index d2f344f1f98f7..928b8e1668ccc 100644 +--- a/drivers/virt/coco/pkvm-guest/Kconfig ++++ b/drivers/virt/coco/pkvm-guest/Kconfig +@@ -1,6 +1,6 @@ + config ARM_PKVM_GUEST + bool "Arm pKVM protected guest driver" +- depends on ARM64 ++ depends on ARM64 && DMA_RESTRICTED_POOL + help + Protected guests running under the pKVM hypervisor on arm64 + are isolated from the host and must issue hypercalls to enable +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch b/queue-7.0/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch new file mode 100644 index 0000000000..902bf969d1 --- /dev/null +++ b/queue-7.0/drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch @@ -0,0 +1,113 @@ +From 9d917afe5777267d333178915619bf7b26e2de26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:25:25 -0400 +Subject: drm/amd/display: Avoid turning off the PHY when OTG is running for + DVI + +From: Nicholas Kazlauskas + +[ Upstream commit ee212b0208a18831d2b537865da56708c17af90d ] + +[Why] +The OTG's virtual pixel clock source for DVI comes from the PHY. + +If the signal type is DVI then the OTG can become stuck on pre DCN401 +ASIC when DPMS off occurs because the OTG remains running but the +PHY transmitter is disabled. + +[How] +There exists logic to keep track of the OTG running refcount on the +link to determine if the link needs to go to PLL_EN instead of TX_EN +but the logic only checks for HDMI TMDS on older ASIC. + +DVI is still a TMDS signal type so the constraint should also apply. + +Replace the checks for dc_is_hdmi_tmds_signal with dc_is_tmds_signal to +cover both HDMI and DVI for the symclk refcount workaround. + +Reviewed-by: Dillon Varone +Reviewed-by: Charlene Liu +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 4 ++-- + drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 4 ++-- + drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 2 +- + drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 2 +- + 4 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +index 699a756bbc405..9e7085057f8ba 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +@@ -1534,7 +1534,7 @@ static enum dc_status dce110_enable_stream_timing( + return DC_ERROR_UNEXPECTED; + } + +- if (dc_is_hdmi_tmds_signal(stream->signal)) { ++ if (dc_is_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; +@@ -2334,7 +2334,7 @@ static void dce110_reset_hw_ctx_wrap( + BREAK_TO_DEBUGGER(); + } + pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); +- if (dc_is_hdmi_tmds_signal(pipe_ctx_old->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx_old->stream->signal)) + pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; + pipe_ctx_old->plane_res.mi->funcs->free_mem_input( + pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +index 307e8f8060e6d..a673ab0803a8f 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +@@ -893,7 +893,7 @@ enum dc_status dcn20_enable_stream_timing( + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + +- if (dc_is_hdmi_tmds_signal(stream->signal)) { ++ if (dc_is_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; +@@ -2856,7 +2856,7 @@ void dcn20_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +index db2f7cbb12ff5..d6b027c06205e 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +@@ -549,7 +549,7 @@ static void dcn31_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + + if (pipe_ctx->top_pipe == NULL) { +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index a3d33d10853b8..9d9dcd2dd5fae 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -2040,7 +2040,7 @@ void dcn401_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ if (dc_is_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch b/queue-7.0/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch new file mode 100644 index 0000000000..54bd304a4f --- /dev/null +++ b/queue-7.0/drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch @@ -0,0 +1,41 @@ +From 90be6546ced4a29e2300ac39a082c87453d016e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 16:51:30 +0800 +Subject: drm/amd/display: bios_parser: fix GPIO I2C line off-by-one + +From: Pengpeng Hou + +[ Upstream commit 12fa1fd6dffff4eed15f1414eb7474127b2c5a24 ] + +get_gpio_i2c_info() computes the number of GPIO I2C assignment records +present in the BIOS table and then uses bfI2C_LineMux as an array index +into header->asGPIO_Info[]. The current check only rejects values +strictly larger than the record count, so an index equal to count still +falls through and reaches the fixed table one element past the end. + +Reject indices at or above the number of available records before using +them as an array index. + +Signed-off-by: Pengpeng Hou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index bbd8d52330b55..25f34f211cfd2 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -2016,7 +2016,7 @@ static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, + count = (le16_to_cpu(header->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) + / sizeof(ATOM_GPIO_I2C_ASSIGMENT); +- if (count < record->sucI2cId.bfI2C_LineMux) ++ if (count <= record->sucI2cId.bfI2C_LineMux) + return BP_RESULT_BADBIOSTABLE; + + /* get the GPIO_I2C_INFO */ +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-clamp-dc_cursor_position-x_hotspot-t.patch b/queue-7.0/drm-amd-display-clamp-dc_cursor_position-x_hotspot-t.patch new file mode 100644 index 0000000000..a9d17f5afa --- /dev/null +++ b/queue-7.0/drm-amd-display-clamp-dc_cursor_position-x_hotspot-t.patch @@ -0,0 +1,66 @@ +From 2a5bd9ecf28b316bdf1a350feaa58bda77c8b674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 12:49:44 -0500 +Subject: drm/amd/display: Clamp dc_cursor_position x_hotspot to prevent + integer overflow + +From: Benjamin Nwankwo + +[ Upstream commit a2aa7987de1169548c465f6cc1019d2112e0e8b5 ] + +why: +Workaround for duplicate cursor. Cursor offsetting via x_hotspot attempts +to write a 32 bit unsigned integer to the 8 bit field CURSOR_HOT_SPOT_X. +This wraps cursor position back into focus if x_hotspot exceeds 8 bits, +making duplicate cursors visible + +how: +Clamp x_hotspot before writing to hardware + +Reviewed-by: Charlene Liu +Reviewed-by: Nevenko Stupar +Signed-off-by: Benjamin Nwankwo +Signed-off-by: Chuanyu Tseng +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +index c205500290ecd..806b9bd9a3fcf 100644 +--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c ++++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +@@ -739,9 +739,8 @@ void hubp401_cursor_set_position( + int x_pos_viewport = 0; + int x_hot_viewport = 0; + uint32_t cur_en = pos->enable ? 1 : 0; +- ++ uint32_t x_hotspot_clamped = pos->x_hotspot; + hubp->curs_pos = *pos; +- + /* Recout is zero for pipes if the entire dst_rect is contained + * within preceeding ODM slices. + */ +@@ -772,6 +771,8 @@ void hubp401_cursor_set_position( + + ASSERT(param->h_scale_ratio.value); + ++ if (x_hotspot_clamped > 0xFF) ++ x_hotspot_clamped = 0xFF; + if (param->h_scale_ratio.value) + dst_x_offset = dc_fixpt_floor(dc_fixpt_div( + dc_fixpt_from_int(dst_x_offset), +@@ -792,7 +793,7 @@ void hubp401_cursor_set_position( + CURSOR_Y_POSITION, pos->y); + + REG_SET_2(CURSOR_HOT_SPOT, 0, +- CURSOR_HOT_SPOT_X, pos->x_hotspot, ++ CURSOR_HOT_SPOT_X, x_hotspot_clamped, + CURSOR_HOT_SPOT_Y, pos->y_hotspot); + + REG_SET(CURSOR_DST_OFFSET, 0, +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch b/queue-7.0/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch new file mode 100644 index 0000000000..3ef162ac8a --- /dev/null +++ b/queue-7.0/drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch @@ -0,0 +1,64 @@ +From a6d6e3e54867273aea3cff859b0a2df444658ca2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 17:08:01 -0500 +Subject: drm/amd/display: Exit IPS w/ DC helper for all dc_set_power_state + cases + +From: Ovidiu Bunea + +[ Upstream commit f44c094449669c7d9ac403cc73ce23e255f0828b ] + +[why & how] +On D3 path during dc_set_power_state, we may be in idle_allowed=true, +at which point we will exit idle via dc_wake_and_execute_dmub_cmd_list +which doesn't update dc->idle_optimizations_allowed to false. This +would cause any future attempts to allow idle optimizations via the DC +helper to get skipped because the value is stale and not reflective of +the actual HW state. + +Move dc_exit_ips_for_hw_access() to the top of the function. +Additionally ensure that dc_power_down_on_boot thread holds the DC +lock and only runs if there are 0 streams. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ovidiu Bunea +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 3e87b6a553be9..4c5ecbb97d5b0 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -5540,6 +5540,9 @@ void dc_power_down_on_boot(struct dc *dc) + { + if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW && + dc->hwss.power_down_on_boot) { ++ if (dc->current_state->stream_count > 0) ++ return; ++ + if (dc->caps.ips_support) + dc_exit_ips_for_hw_access(dc); + dc->hwss.power_down_on_boot(dc); +@@ -5551,12 +5554,12 @@ void dc_set_power_state(struct dc *dc, enum dc_acpi_cm_power_state power_state) + if (!dc->current_state) + return; + ++ dc_exit_ips_for_hw_access(dc); ++ + switch (power_state) { + case DC_ACPI_CM_POWER_STATE_D0: + dc_state_construct(dc, dc->current_state); + +- dc_exit_ips_for_hw_access(dc); +- + dc_z10_restore(dc); + + dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, power_state); +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch b/queue-7.0/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch new file mode 100644 index 0000000000..82a522d150 --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch @@ -0,0 +1,61 @@ +From f27d313689b304b41aa539f810d91d50b8efe100 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 15:57:19 -0500 +Subject: drm/amd/display: Fix cursor pos at overlay plane edges on DCN4 + +From: Ivan Lipski + +[ Upstream commit d8f6c978fd3d12ae129879dd1c514cec2e8cf2f8 ] + +[Why&How] +On DCN4, when cursor straddles the left/top edge of an overlay plane, the +recout-relative position becomes negative. These negative values wrap +to large positive numbers when cast to uint32_t, causing the cursor on the +the overlay plane to disappear. + +Fix by adding hotspot adjustment and position clamping after the +recout-relative calculation, matching the existing ODM/MPC slice +boundary handling. + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index 4dfb6c8658312..4973d36aadc5d 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1211,6 +1211,25 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) + x_pos = pos_cpy.x - param.recout.x; + y_pos = pos_cpy.y - param.recout.y; + ++ /** ++ * If the cursor position is negative after recout adjustment, we need ++ * to shift the hotspot to compensate and clamp position to 0. This ++ * handles the case where cursor straddles the left/top edge of an ++ * overlay plane - the cursor is partially visible and needs correct ++ * hotspot adjustment to render the visible portion. ++ */ ++ if (x_pos < 0) { ++ pos_cpy.x_hotspot -= x_pos; ++ if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION) ++ adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy); ++ x_pos = 0; ++ } ++ ++ if (y_pos < 0) { ++ pos_cpy.y_hotspot -= y_pos; ++ y_pos = 0; ++ } ++ + recout_x_pos = x_pos - pos_cpy.x_hotspot; + recout_y_pos = y_pos - pos_cpy.y_hotspot; + +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-dcn401_optimize_bandwidth.patch b/queue-7.0/drm-amd-display-fix-dcn401_optimize_bandwidth.patch new file mode 100644 index 0000000000..43b5d85d3a --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-dcn401_optimize_bandwidth.patch @@ -0,0 +1,49 @@ +From cddd435c243d98fc78e5b2096c787726d0b195e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 16:53:44 -0500 +Subject: drm/amd/display: Fix dcn401_optimize_bandwidth + +From: Charlene Liu + +[ Upstream commit 002f32db0d4292f117994c330928d2374887b28e ] + +[Why&How] +We should check for != zstate disallow and programming extend blank from a +different struct. + +Reviewed-by: Leo Chen +Reviewed-by: Dmytro Laktyushkin +Signed-off-by: Charlene Liu +Signed-off-by: Ivan Lipski +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +index 4973d36aadc5d..a3d33d10853b8 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +@@ -1492,7 +1492,7 @@ void dcn401_optimize_bandwidth( + dc->clk_mgr, + context, + true); +- if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { ++ if (context->bw_ctx.bw.dcn.clk.zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW) { + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + +@@ -1500,7 +1500,7 @@ void dcn401_optimize_bandwidth( + && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max + && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) + pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, +- pipe_ctx->dlg_regs.min_dst_y_next_start); ++ pipe_ctx->hubp_regs.dlg_regs.min_dst_y_next_start); + } + } + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch b/queue-7.0/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch new file mode 100644 index 0000000000..cbe553123e --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch @@ -0,0 +1,93 @@ +From 6196959e08f5f07f897aa66b0834db97c81bf26c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:28:12 -0400 +Subject: drm/amd/display: Fix HostVMMinPageSize unit mismatch in DML2.1 + +From: Nicholas Kazlauskas + +[ Upstream commit 5721b5b9c9c792233d7817239bd81925fb3ad9d1 ] + +[Why] +This was found back on DML2 but was missed when creating DML2.1. + +The bottom layer calculation (CalculateHostVMDynamicLevels) expects +a value in bytes, not KB, but we pass in the value in KB (eg. 4). + +This causes an extra page table level to be required in the prefetch +bytes which can be significant overhead - preventing some modes +from being supported that should otherwise be. + +[How] +Correct the units by multiplying the input and override values by 1024. + +Reviewed-by: Austin Zheng +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Roman Li +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +index ca5ac3c0deb56..cdd7c771afff9 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +@@ -7381,7 +7381,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter + s->tdlut_bytes_per_group, + s->HostVMInefficiencyFactor, + s->HostVMInefficiencyFactorPrefetch, +- mode_lib->soc.hostvm_min_page_size_kbytes, ++ mode_lib->soc.hostvm_min_page_size_kbytes * 1024, + mode_lib->soc.qos_parameters.qos_type, + !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), + mode_lib->soc.max_outstanding_reqs, +@@ -7477,7 +7477,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter + CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; + CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; + CalculatePrefetchSchedule_params->VStartup = s->MaximumVStartup[k]; +- CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; + CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; + CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; +@@ -8965,7 +8965,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthY; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthC; +- CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; + +@@ -10755,7 +10755,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->soc.mall_allocated_for_dcn_mbytes; + CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->mp.SwathWidthY; + CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->mp.SwathWidthC; +- CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ip.dcc_meta_buffer_size_bytes; + CalculateVMRowAndSwath_params->mrq_present = mode_lib->ip.dcn_mrq_present; + +@@ -10971,7 +10971,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + s->tdlut_bytes_per_group, + s->HostVMInefficiencyFactor, + s->HostVMInefficiencyFactorPrefetch, +- mode_lib->soc.hostvm_min_page_size_kbytes, ++ mode_lib->soc.hostvm_min_page_size_kbytes * 1024, + mode_lib->soc.qos_parameters.qos_type, + !(display_cfg->overrides.max_outstanding_when_urgent_expected_disable), + mode_lib->soc.max_outstanding_reqs, +@@ -11264,7 +11264,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex + CalculatePrefetchSchedule_params->OutputFormat = display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_format; + CalculatePrefetchSchedule_params->MaxInterDCNTileRepeaters = mode_lib->ip.max_inter_dcn_tile_repeaters; + CalculatePrefetchSchedule_params->VStartup = s->MaxVStartupLines[k]; +- CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes; ++ CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->soc.hostvm_min_page_size_kbytes * 1024; + CalculatePrefetchSchedule_params->DynamicMetadataEnable = display_cfg->plane_descriptors[k].dynamic_meta_data.enable; + CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ip.dynamic_metadata_vm_enabled; + CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = display_cfg->plane_descriptors[k].dynamic_meta_data.lines_before_active_required; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-hwss-v3-fast-path-determination.patch b/queue-7.0/drm-amd-display-fix-hwss-v3-fast-path-determination.patch new file mode 100644 index 0000000000..10fedcfe20 --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-hwss-v3-fast-path-determination.patch @@ -0,0 +1,91 @@ +From 808eddc89f04857a32de999cf51678d5e93f3fe6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 16:49:46 -0500 +Subject: drm/amd/display: Fix HWSS v3 fast path determination + +From: Nicholas Kazlauskas + +[ Upstream commit d3e79f333d90f6d3d268c3b073cf3afc0b019036 ] + +[WHY] +We're checking surface and stream updates after they've been applied to +their respective states within `update_planes_and_stream_state`. + +Medium updates under the HWSS V3 fast path that are not supported or +tested are getting implicitly if they don't trigger a DML validation +and getting updated in place on the dc->current_state context. + +[HOW] +Fix this issue by moving up the fast path determination check prior +to `update_planes_and_stream_state`. This is how the V2 path works +and how the V3 path used to work prior to the refactors in this area. + +Reviewed-by: Dillon Varone +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Alex Hung +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 38 +++++++++++------------- + 1 file changed, 18 insertions(+), 20 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 4c5ecbb97d5b0..47064e9bc08ad 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -7285,6 +7285,23 @@ static bool update_planes_and_stream_prepare_v3( + ASSERT(scratch->flow == UPDATE_V3_FLOW_INVALID); + dc_exit_ips_for_hw_access(scratch->dc); + ++ /* HWSS path determination needs to be done prior to updating the surface and stream states. */ ++ struct dc_fast_update fast_update[MAX_SURFACES] = { 0 }; ++ ++ populate_fast_updates(fast_update, ++ scratch->surface_updates, ++ scratch->surface_count, ++ scratch->stream_update); ++ ++ const bool is_hwss_fast_path_only = ++ fast_update_only(scratch->dc, ++ fast_update, ++ scratch->surface_updates, ++ scratch->surface_count, ++ scratch->stream_update, ++ scratch->stream) && ++ !scratch->dc->check_config.enable_legacy_fast_update; ++ + if (!update_planes_and_stream_state( + scratch->dc, + scratch->surface_updates, +@@ -7300,26 +7317,7 @@ static bool update_planes_and_stream_prepare_v3( + if (scratch->new_context == scratch->dc->current_state) { + ASSERT(scratch->update_type < UPDATE_TYPE_FULL); + +- // TODO: Do we need this to be alive in execute? +- struct dc_fast_update fast_update[MAX_SURFACES] = { 0 }; +- +- populate_fast_updates( +- fast_update, +- scratch->surface_updates, +- scratch->surface_count, +- scratch->stream_update +- ); +- const bool fast = fast_update_only( +- scratch->dc, +- fast_update, +- scratch->surface_updates, +- scratch->surface_count, +- scratch->stream_update, +- scratch->stream +- ) +- // TODO: Can this be used to skip `populate_fast_updates`? +- && !scratch->dc->check_config.enable_legacy_fast_update; +- scratch->flow = fast ++ scratch->flow = is_hwss_fast_path_only + ? UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST + : UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL; + return true; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-number-of-opp.patch b/queue-7.0/drm-amd-display-fix-number-of-opp.patch new file mode 100644 index 0000000000..1be3a5afd1 --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-number-of-opp.patch @@ -0,0 +1,37 @@ +From 114a0b3123d215684541449213a89982298a5b21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 15:33:13 -0500 +Subject: drm/amd/display: Fix number of opp + +From: Austin Zheng + +[ Upstream commit 2c5f15ee2c760514c5be0f02cf9c9f1ff68b9ac8 ] + +[Why/How] +Patch number of opp based on IP caps + +Reviewed-by: Dillon Varone +Signed-off-by: Austin Zheng +Signed-off-by: Chuanyu Tseng +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +index eba948e187c11..93d479083acde 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c +@@ -107,6 +107,7 @@ static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, + { + ip_params->max_num_dpp = ip_caps->pipe_count; + ip_params->max_num_otg = ip_caps->otg_count; ++ ip_params->max_num_opp = ip_caps->otg_count; + ip_params->num_dsc = ip_caps->num_dsc; + ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams; + ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-merge-pipes-for-validate.patch b/queue-7.0/drm-amd-display-merge-pipes-for-validate.patch new file mode 100644 index 0000000000..323b072d44 --- /dev/null +++ b/queue-7.0/drm-amd-display-merge-pipes-for-validate.patch @@ -0,0 +1,43 @@ +From 518d5c1a226b1834019c77448df050e77203a0de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 11:48:11 -0500 +Subject: drm/amd/display: Merge pipes for validate + +From: Harry Wentland + +[ Upstream commit 606f6b171326152ef08d0ef0ad49f52034edca07 ] + +Validation expects to operate on non-split pipes. This is +seen in dcn20_fast_validate_bw, which merges pipes for +validation. We weren't doing that in the non-fast path +which lead to validation failures when operating with +4-to-1 MPC and a writeback connector. + +Co-developed by Claude Sonnet 4.5 + +Assisted-by: Claude:claude-sonnet-4.5 +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Harry Wentland +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +index 87b7b4ee04c64..b00054ea18178 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +@@ -1675,6 +1675,8 @@ noinline bool dcn30_internal_validate_bw( + if (!pipes) + return false; + ++ dcn20_merge_pipes_for_validate(dc, context); ++ + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch b/queue-7.0/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch new file mode 100644 index 0000000000..7b968a9043 --- /dev/null +++ b/queue-7.0/drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch @@ -0,0 +1,102 @@ +From a6fc5ced1aeb3129e50b3e5058e9dbaf612a69f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:34:56 -0400 +Subject: drm/amd/display: Pass min page size from SOC BB to dml2_1 plane + config + +From: Nicholas Kazlauskas + +[ Upstream commit 07ac59230d5fd603d56af2363dae80d3e973e4bc ] + +[Why] +Like dml2_0 this isn't guaranteed to be constant for every ASIC. + +This can cause corruption or underflow for linear surfaces due to a +wrong PTE_ROW_HEIGHT_LINEAR value if not correctly specified. + +[How] +Like dml2_0 pass in the SOC bb into the plane configuration population +functions. + +Set both GPUVM and HostVM page sizes in the overrides. + +Reviewed-by: Dillon Varone +Signed-off-by: Nicholas Kazlauskas +Signed-off-by: Roman Li +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../dml2_0/dml21/dml21_translation_helper.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +index bf5e7f4e04167..a64c0407ad515 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +@@ -381,7 +381,9 @@ static void populate_dml21_dummy_surface_cfg(struct dml2_surface_cfg *surface, c + surface->tiling = dml2_sw_64kb_2d; + } + +-static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, const struct dc_stream_state *stream) ++static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, ++ const struct dc_stream_state *stream, ++ const struct dml2_soc_bb *soc_bb) + { + unsigned int width, height; + +@@ -425,7 +427,8 @@ static void populate_dml21_dummy_plane_cfg(struct dml2_plane_parameters *plane, + plane->pixel_format = dml2_444_32; + + plane->dynamic_meta_data.enable = false; +- plane->overrides.gpuvm_min_page_size_kbytes = 256; ++ plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; ++ plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; + } + + static void populate_dml21_surface_config_from_plane_state( +@@ -495,7 +498,7 @@ static const struct scaler_data *get_scaler_data_for_plane( + + static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dml_ctx, + struct dml2_plane_parameters *plane, const struct dc_plane_state *plane_state, +- const struct dc_state *context, unsigned int stream_index) ++ const struct dc_state *context, unsigned int stream_index, const struct dml2_soc_bb *soc_bb) + { + const struct scaler_data *scaler_data = get_scaler_data_for_plane(dml_ctx, plane_state, context); + struct dc_stream_state *stream = context->streams[stream_index]; +@@ -631,7 +634,8 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm + plane->composition.rotation_angle = (enum dml2_rotation_angle) plane_state->rotation; + plane->stream_index = stream_index; + +- plane->overrides.gpuvm_min_page_size_kbytes = 256; ++ plane->overrides.gpuvm_min_page_size_kbytes = soc_bb->gpuvm_min_page_size_kbytes; ++ plane->overrides.hostvm_min_page_size_kbytes = soc_bb->hostvm_min_page_size_kbytes; + + plane->immediate_flip = plane_state->flip_immediate; + +@@ -765,7 +769,9 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s + if (context->stream_status[stream_index].plane_count == 0) { + disp_cfg_plane_location = dml_dispcfg->num_planes++; + populate_dml21_dummy_surface_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->streams[stream_index]); +- populate_dml21_dummy_plane_cfg(&dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->streams[stream_index]); ++ populate_dml21_dummy_plane_cfg( ++ &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], ++ context->streams[stream_index], &dml_ctx->v21.dml_init.soc_bb); + dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; + } else { + for (plane_index = 0; plane_index < context->stream_status[stream_index].plane_count; plane_index++) { +@@ -777,7 +783,10 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s + ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location < __DML2_WRAPPER_MAX_STREAMS_PLANES__); + + populate_dml21_surface_config_from_plane_state(in_dc, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location].surface, context->stream_status[stream_index].plane_states[plane_index]); +- populate_dml21_plane_config_from_plane_state(dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], context->stream_status[stream_index].plane_states[plane_index], context, stream_index); ++ populate_dml21_plane_config_from_plane_state( ++ dml_ctx, &dml_dispcfg->plane_descriptors[disp_cfg_plane_location], ++ context->stream_status[stream_index].plane_states[plane_index], ++ context, stream_index, &dml_ctx->v21.dml_init.soc_bb); + dml_dispcfg->plane_descriptors[disp_cfg_plane_location].stream_index = disp_cfg_stream_location; + + if (dml21_wrapper_get_plane_id(context, context->streams[stream_index]->stream_id, context->stream_status[stream_index].plane_states[plane_index], &dml_ctx->v21.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[disp_cfg_plane_location])) +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-remove-duplicate-format-modifier.patch b/queue-7.0/drm-amd-display-remove-duplicate-format-modifier.patch new file mode 100644 index 0000000000..819b1f46df --- /dev/null +++ b/queue-7.0/drm-amd-display-remove-duplicate-format-modifier.patch @@ -0,0 +1,60 @@ +From eaca07a42d5d9b67d7e2106842633d3a827c602a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:08:15 -0500 +Subject: drm/amd/display: remove duplicate format modifier + +From: Erik Kurzinger + +[ Upstream commit 6736c8ff9d63e847a3b694aeaeb78d4e8ad42464 ] + +amdgpu_dm_plane_get_plane_modifiers always adds DRM_FORMAT_MOD_LINEAR to +the list of modifiers. However, with gfx12, +amdgpu_dm_plane_add_gfx12_modifiers also adds that modifier to the list. +So we end up with two copies. Most apps just ignore this but some +(Weston) don't like it. + +As a fix, we change amdgpu_dm_plane_add_gfx12_modifiers to not add +DRM_FORMAT_MOD_LINEAR to the list, matching the behavior of analogous +functions for other chips. + +Signed-off-by: Erik Kurzinger +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 127207e18dcb0..bc19438211dd3 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -704,21 +704,21 @@ static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, + uint8_t max_comp_block[] = {2, 1, 0}; + uint64_t max_comp_block_mod[ARRAY_SIZE(max_comp_block)] = {0}; + uint8_t i = 0, j = 0; +- uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b, DRM_FORMAT_MOD_LINEAR}; ++ /* Note, linear (no DCC) gets added to the modifier list for all chips by the caller. */ ++ uint64_t gfx12_modifiers[] = {mod_256k, mod_64k, mod_4k, mod_256b}; + + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + max_comp_block_mod[i] = AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, max_comp_block[i]); + + /* With DCC: Best choice should be kept first. Hence, add all 256k modifiers of different + * max compressed blocks first and then move on to the next smaller sized layouts. +- * Do not add the linear modifier here, and hence the condition of size-1 for the loop + */ +- for (j = 0; j < ARRAY_SIZE(gfx12_modifiers) - 1; j++) ++ for (j = 0; j < ARRAY_SIZE(gfx12_modifiers); j++) + for (i = 0; i < ARRAY_SIZE(max_comp_block); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, + ver | dcc | max_comp_block_mod[i] | gfx12_modifiers[j]); + +- /* Without DCC. Add all modifiers including linear at the end */ ++ /* Without DCC. */ + for (i = 0; i < ARRAY_SIZE(gfx12_modifiers); i++) + amdgpu_dm_plane_add_modifier(mods, size, capacity, gfx12_modifiers[i]); + +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch b/queue-7.0/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch new file mode 100644 index 0000000000..86e862de90 --- /dev/null +++ b/queue-7.0/drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch @@ -0,0 +1,63 @@ +From b0c7aab5bd83a2555eb410854bd95ed2b76be1bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:45:47 -0400 +Subject: drm/amd/display: Remove invalid DPSTREAMCLK mask usage + +From: Roman Li + +[ Upstream commit 8de2559ec172b04301d6e53c4f30388e40fad08c ] + +[Why] +The invalid register field access causes ASSERT(mask != 0) to fire +in set_reg_field_values() during display enable. + +WARNING: at drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:100 +set_reg_field_values.isra.0+0xcf/0xf0 [amdgpu] +Call Trace: + +generic_reg_update_ex+0x66/0x1d0 [amdgpu] +dccg401_set_dpstreamclk+0xed/0x350 [amdgpu] +dcn401_enable_stream+0x165/0x370 [amdgpu] +link_set_dpms_on+0x6e9/0xe90 [amdgpu] +dce110_apply_single_controller_ctx_to_hw+0x343/0x530 [amdgpu] +dce110_apply_ctx_to_hw+0x1f6/0x2d0 [amdgpu] +dc_commit_state_no_check+0x49a/0xe20 [amdgpu] +dc_commit_streams+0x354/0x570 [amdgpu] +amdgpu_dm_atomic_commit_tail+0x6f8/0x3fc0 [amdgpu] + +DCN4.x hardware does not have DPSTREAMCLK_GATE_DISABLE and +DPSTREAMCLK_ROOT_GATE_DISABLE fields in DCCG_GATE_DISABLE_CNTL3. +These global fields only exist in DCN3.1.x hardware. + +[How] +Remove the call that tries to update non-existent fields in CNTL3. +DCN4.x uses per-instance fields in CNTL5 instead, +which are already correctly programmed in the switch cases above. + +Reviewed-by: Dillon Varone +Signed-off-by: Roman Li +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +index a37f94dec6f2f..44c4a53f14ad8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c ++++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +@@ -526,10 +526,6 @@ static void dccg401_enable_dpstreamclk(struct dccg *dccg, int otg_inst, int dp_h + BREAK_TO_DEBUGGER(); + return; + } +- if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) +- REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3, +- DPSTREAMCLK_GATE_DISABLE, 1, +- DPSTREAMCLK_ROOT_GATE_DISABLE, 1); + } + + void dccg401_disable_dpstreamclk(struct dccg *dccg, int dp_hpo_inst) +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-restore-full-update-for-tiling-chang.patch b/queue-7.0/drm-amd-display-restore-full-update-for-tiling-chang.patch new file mode 100644 index 0000000000..5b60cb8eaa --- /dev/null +++ b/queue-7.0/drm-amd-display-restore-full-update-for-tiling-chang.patch @@ -0,0 +1,86 @@ +From 2455a6709050f7f6053bdade35ac6e37a0a67860 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 18:33:49 -0400 +Subject: drm/amd/display: Restore full update for tiling change to linear + +From: Joshua Aberback + +[ Upstream commit 3967ab83a5075c05be3c614f1dc8460f66ee77ad ] + +[Why] +There was previously a dc debug flag to indicate that tiling +changes should only be a medium update instead of full. The +function get_plane_info_type was refactored to not rely on dc +state, but in the process the logic was unintentionally changed, +which leads to screen corruption in some cases. + +[How] + - add flag to tiling struct to avoid full update when necessary + +Reviewed-by: Nicholas Kazlauskas +Reviewed-by: Aric Cyr +Signed-off-by: Joshua Aberback +Signed-off-by: Chuanyu Tseng +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 26 ++++---------------- + drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 4 +++ + 2 files changed, 9 insertions(+), 21 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 47064e9bc08ad..7107529e90295 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -2749,28 +2749,12 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct + + if (memcmp(tiling, &u->surface->tiling_info, sizeof(*tiling)) != 0) { + update_flags->bits.swizzle_change = 1; +- elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); + +- switch (tiling->gfxversion) { +- case DcGfxVersion9: +- case DcGfxVersion10: +- case DcGfxVersion11: +- if (tiling->gfx9.swizzle != DC_SW_LINEAR) { +- update_flags->bits.bandwidth_change = 1; +- elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); +- } +- break; +- case DcGfxAddr3: +- if (tiling->gfx_addr3.swizzle != DC_ADDR3_SW_LINEAR) { +- update_flags->bits.bandwidth_change = 1; +- elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); +- } +- break; +- case DcGfxVersion7: +- case DcGfxVersion8: +- case DcGfxVersionUnknown: +- default: +- break; ++ if (tiling->flags.avoid_full_update_on_tiling_change) { ++ elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); ++ } else { ++ update_flags->bits.bandwidth_change = 1; ++ elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); + } + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +index cfa569a7bff1b..face23e0559d5 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +@@ -436,6 +436,10 @@ enum dc_gfxversion { + enum swizzle_mode_addr3_values swizzle; + } gfx_addr3;/*gfx with addr3 and above*/ + }; ++ ++ struct { ++ bool avoid_full_update_on_tiling_change; ++ } flags; + }; + + /* Rotation angle */ +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-use-overlay-cursor-when-color-pipeli.patch b/queue-7.0/drm-amd-display-use-overlay-cursor-when-color-pipeli.patch new file mode 100644 index 0000000000..d00fa5b5d1 --- /dev/null +++ b/queue-7.0/drm-amd-display-use-overlay-cursor-when-color-pipeli.patch @@ -0,0 +1,131 @@ +From a061c65e215645428dce3ab671a153d5093e409f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:03:25 -0600 +Subject: drm/amd/display: Use overlay cursor when color pipeline is active + +From: Alex Hung + +[ Upstream commit d3a549f4df7864bca8612c8bcfce1ec72b2874fb ] + +Force overlay cursor mode when an underlying plane has a non-bypassed +color pipeline to avoid incorrect cursor transformation. + +Reviewed-by: Sun peng (Leo) Li +Signed-off-by: Alex Hung +Signed-off-by: Aurabindo Pillai +Tested-by: Dan Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 53 +++++++++++++++++-- + 1 file changed, 49 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 0aee65503642d..5052533a2be45 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -94,6 +94,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -12282,6 +12283,38 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm + * available. + */ + ++/** ++ * dm_plane_color_pipeline_active() - Check if a plane's color pipeline active. ++ * @state: DRM atomic state ++ * @plane: DRM plane to check ++ * @use_old: if true, inspect the old colorop states; otherwise the new ones ++ * ++ * A color pipeline may be selected (color_pipeline != NULL) but still is ++ * inactive if every colorop in the chain is bypassed. Only return ++ * true when at least one colorop has bypass == false, meaning the cursor ++ * would be subjected to the transformation in native mode. ++ * ++ * Return: true if the pipeline modifies pixels, false otherwise. ++ */ ++static bool dm_plane_color_pipeline_active(struct drm_atomic_state *state, ++ struct drm_plane *plane, ++ bool use_old) ++{ ++ struct drm_colorop *colorop; ++ struct drm_colorop_state *old_colorop_state, *new_colorop_state; ++ int i; ++ ++ for_each_oldnew_colorop_in_state(state, colorop, old_colorop_state, new_colorop_state, i) { ++ struct drm_colorop_state *cstate = use_old ? old_colorop_state : new_colorop_state; ++ ++ if (cstate->colorop->plane != plane) ++ continue; ++ if (!cstate->bypass) ++ return true; ++ } ++ return false; ++} ++ + /** + * dm_crtc_get_cursor_mode() - Determine the required cursor mode on crtc + * @adev: amdgpu device +@@ -12293,8 +12326,8 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm + * the dm_crtc_state. + * + * The cursor should be enabled in overlay mode if there exists an underlying +- * plane - on which the cursor may be blended - that is either YUV formatted, or +- * scaled differently from the cursor. ++ * plane - on which the cursor may be blended - that is either YUV formatted, ++ * scaled differently from the cursor, or has a color pipeline active. + * + * Since zpos info is required, drm_atomic_normalize_zpos must be called before + * calling this function. +@@ -12331,7 +12364,7 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, + + /* + * Cursor mode can change if a plane's format changes, scale changes, is +- * enabled/disabled, or z-order changes. ++ * enabled/disabled, z-order changes, or color management properties change. + */ + for_each_oldnew_plane_in_state(state, plane, old_plane_state, plane_state, i) { + int new_scale_w, new_scale_h, old_scale_w, old_scale_h; +@@ -12356,6 +12389,12 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, + consider_mode_change = true; + break; + } ++ ++ if (dm_plane_color_pipeline_active(state, plane, true) != ++ dm_plane_color_pipeline_active(state, plane, false)) { ++ consider_mode_change = true; ++ break; ++ } + } + + if (!consider_mode_change && !crtc_state->zpos_changed) +@@ -12396,6 +12435,12 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, + return 0; + } + ++ /* Underlying plane has an active color pipeline - cursor would be transformed */ ++ if (dm_plane_color_pipeline_active(state, plane, false)) { ++ *cursor_mode = DM_CURSOR_OVERLAY_MODE; ++ return 0; ++ } ++ + dm_get_plane_scale(plane_state, + &underlying_scale_w, &underlying_scale_h); + dm_get_plane_scale(cursor_state, +@@ -12774,7 +12819,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + } else if (required_cursor_mode == DM_CURSOR_OVERLAY_MODE) { + drm_dbg_driver(crtc->dev, +- "[CRTC:%d:%s] Cannot enable native cursor due to scaling or YUV restrictions\n", ++ "[CRTC:%d:%s] Cannot enable native cursor due to scaling, YUV, or color pipeline restrictions\n", + crtc->base.id, crtc->name); + ret = -EINVAL; + goto fail; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-avoid-overflow-when-sorting-pp_feature-li.patch b/queue-7.0/drm-amd-pm-avoid-overflow-when-sorting-pp_feature-li.patch new file mode 100644 index 0000000000..f2dce0a14f --- /dev/null +++ b/queue-7.0/drm-amd-pm-avoid-overflow-when-sorting-pp_feature-li.patch @@ -0,0 +1,38 @@ +From c43d6cab8bc43bf5c0f774c90dc919fb952b14b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:35:30 +0800 +Subject: drm/amd/pm: Avoid overflow when sorting pp_feature list + +From: Asad Kamal + +[ Upstream commit 8e8f6bda8a84f41c4002bca44ac89a5b3f8c7df2 ] + +pp_features sorting uses int8_t sort_feature[] to store driver +feature enum indices. On newer ASICs the enum index can exceed 127, +causing signed overflow and silently dropping entries from the output. +Switch the array to int16_t so all enum indices are preserved. + +Signed-off-by: Asad Kamal +Reviewed-by: Lijo Lazar +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +index 6fd50c2fd20e0..97ed66cb47472 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +@@ -880,7 +880,7 @@ static const char *smu_get_feature_name(struct smu_context *smu, + size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, + char *buf) + { +- int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; ++ int16_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; + struct smu_feature_bits feature_mask; + uint32_t features[2]; + int i, feature_index; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-update-emit-clock-logic.patch b/queue-7.0/drm-amd-pm-update-emit-clock-logic.patch new file mode 100644 index 0000000000..844ba03bfb --- /dev/null +++ b/queue-7.0/drm-amd-pm-update-emit-clock-logic.patch @@ -0,0 +1,38 @@ +From 04ccaa44b81839c5b8aa976e9930fb24b9564657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:17:41 +0530 +Subject: drm/amd/pm: Update emit clock logic + +From: Lijo Lazar + +[ Upstream commit d6b99885b122528651d554a7bd907211a81579c2 ] + +If only one level is enabled in clock table, there is no need to +follow the fine grained clock logic which expects a minimum of +two levels (min/max). + +Signed-off-by: Lijo Lazar +Reviewed-by: Asad Kamal +Signed-off-by: Alex Deucher +(cherry picked from commit 7f19097af1496dd908a044ca95862f32d05f02df) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +index 97ed66cb47472..587a5593c2142 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +@@ -1310,7 +1310,7 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, + level_index = 1; + } + +- if (!is_fine_grained) { ++ if (!is_fine_grained || count == 1) { + for (i = 0; i < count; i++) { + freq_match = !is_deep_sleep && + smu_cmn_freqs_match( +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-add-default-reset-method-for-soc_v1_0.patch b/queue-7.0/drm-amdgpu-add-default-reset-method-for-soc_v1_0.patch new file mode 100644 index 0000000000..d351f4052d --- /dev/null +++ b/queue-7.0/drm-amdgpu-add-default-reset-method-for-soc_v1_0.patch @@ -0,0 +1,69 @@ +From 817964cec8c7a1fe942762d12f57969f350aef70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 01:42:42 +0800 +Subject: drm/amdgpu: Add default reset method for soc_v1_0 + +From: Asad Kamal + +[ Upstream commit eb737fb303dd73ceb0f646fc2e696595e576056f ] + +Add mode2 as default reset method for soc_v1_0 + +v2: Remove unnecessary overrides while selecting reset method (Lijo) +v4: Add dev_warn_once (Lijo) + +Signed-off-by: Asad Kamal +Reviewed-by: Lijo Lazar +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/soc_v1_0.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c +index 59ab952d5cce4..ca66a0169c781 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c +@@ -229,8 +229,31 @@ static bool soc_v1_0_need_reset_on_init(struct amdgpu_device *adev) + return false; + } + ++static enum amd_reset_method ++soc_v1_0_asic_reset_method(struct amdgpu_device *adev) ++{ ++ if ((adev->gmc.xgmi.supported && adev->gmc.xgmi.connected_to_cpu) || ++ (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 8))) { ++ if (amdgpu_reset_method != -1) ++ dev_warn_once(adev->dev, "Reset override isn't supported, using Mode2 instead.\n"); ++ ++ return AMD_RESET_METHOD_MODE2; ++ } ++ ++ return amdgpu_reset_method; ++} ++ + static int soc_v1_0_asic_reset(struct amdgpu_device *adev) + { ++ switch (soc_v1_0_asic_reset_method(adev)) { ++ case AMD_RESET_METHOD_MODE2: ++ dev_info(adev->dev, "MODE2 reset\n"); ++ return amdgpu_dpm_mode2_reset(adev); ++ default: ++ dev_info(adev->dev, "Invalid reset method Not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ + return 0; + } + +@@ -244,6 +267,7 @@ static const struct amdgpu_asic_funcs soc_v1_0_asic_funcs = { + .need_reset_on_init = &soc_v1_0_need_reset_on_init, + .encode_ext_smn_addressing = &soc_v1_0_encode_ext_smn_addressing, + .reset = soc_v1_0_asic_reset, ++ .reset_method = &soc_v1_0_asic_reset_method, + }; + + static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block) +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch b/queue-7.0/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch new file mode 100644 index 0000000000..819fdd8629 --- /dev/null +++ b/queue-7.0/drm-amdgpu-check-for-multiplication-overflow-in-chec.patch @@ -0,0 +1,162 @@ +From c3a010a14f789acfe8132ffe97098fc5a68e7955 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 10:21:15 -0500 +Subject: drm/amdgpu: Check for multiplication overflow in checkpoint stack + size + +From: David Francis + +[ Upstream commit 421c0f19043337a553e802b2dfe4b56d538ef4d6 ] + +get_checkpoint_info() in kfd_mqd_manager_v9.c finds 32-bit value +ctl_stack_size by multiplying two 32-bit values. This can overflow to a +lower value, which could result in copying outside the bounds of +a buffer in checkpoint_mqd() in the same file. + +Put in a check for the overflow, and fail with -EINVAL if detected. + +v2: use check_mul_overflow() + +Signed-off-by: David Francis +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 7 +++++-- + drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 3 ++- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 7 +++++-- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 3 ++- + drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 8 +++++++- + 6 files changed, 22 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index c4cf595abca6c..9185ebe4c079a 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2720,7 +2720,7 @@ static int get_wave_state(struct device_queue_manager *dqm, + ctl_stack, ctl_stack_used_size, save_area_used_size); + } + +-static void get_queue_checkpoint_info(struct device_queue_manager *dqm, ++static int get_queue_checkpoint_info(struct device_queue_manager *dqm, + const struct queue *q, + u32 *mqd_size, + u32 *ctl_stack_size) +@@ -2728,6 +2728,7 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm, + struct mqd_manager *mqd_mgr; + enum KFD_MQD_TYPE mqd_type = + get_mqd_type_from_queue_type(q->properties.type); ++ int ret = 0; + + dqm_lock(dqm); + mqd_mgr = dqm->mqd_mgrs[mqd_type]; +@@ -2735,9 +2736,11 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm, + *ctl_stack_size = 0; + + if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info) +- mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size); ++ ret = mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size); + + dqm_unlock(dqm); ++ ++ return ret; + } + + static int checkpoint_mqd(struct device_queue_manager *dqm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +index ef07e44916f80..3272328da11f9 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +@@ -192,7 +192,7 @@ struct device_queue_manager_ops { + + int (*reset_queues)(struct device_queue_manager *dqm, + uint16_t pasid); +- void (*get_queue_checkpoint_info)(struct device_queue_manager *dqm, ++ int (*get_queue_checkpoint_info)(struct device_queue_manager *dqm, + const struct queue *q, u32 *mqd_size, + u32 *ctl_stack_size); + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +index 2429d278ef0eb..06ca6235ff1b7 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +@@ -102,7 +102,8 @@ struct mqd_manager { + u32 *ctl_stack_used_size, + u32 *save_area_used_size); + +- void (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, uint32_t *ctl_stack_size); ++ int (*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, ++ uint32_t *ctl_stack_size); + + void (*checkpoint_mqd)(struct mqd_manager *mm, + void *mqd, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +index e856bee628058..e8f97de9d6e47 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +@@ -392,11 +392,14 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, + return 0; + } + +-static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) ++static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) + { + struct v9_mqd *m = get_mqd(mqd); + +- *ctl_stack_size = m->cp_hqd_cntl_stack_size * NUM_XCC(mm->dev->xcc_mask); ++ if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size)) ++ return -EINVAL; ++ ++ return 0; + } + + static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +index f02ef2d44a07f..431a20323146b 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +@@ -274,10 +274,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, + return 0; + } + +-static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) ++static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) + { + /* Control stack is stored in user mode */ + *ctl_stack_size = 0; ++ return 0; + } + + static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index 3d172e35e57ce..44e39ce222b78 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -1071,6 +1071,7 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm, + uint32_t *ctl_stack_size) + { + struct process_queue_node *pqn; ++ int ret; + + pqn = get_queue_by_qid(pqm, qid); + if (!pqn) { +@@ -1083,9 +1084,14 @@ int pqm_get_queue_checkpoint_info(struct process_queue_manager *pqm, + return -EOPNOTSUPP; + } + +- pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm, ++ ret = pqn->q->device->dqm->ops.get_queue_checkpoint_info(pqn->q->device->dqm, + pqn->q, mqd_size, + ctl_stack_size); ++ if (ret) { ++ pr_debug("amdkfd: Overflow while computing stack size for queue %d\n", qid); ++ return ret; ++ } ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch b/queue-7.0/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch new file mode 100644 index 0000000000..792f524794 --- /dev/null +++ b/queue-7.0/drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch @@ -0,0 +1,36 @@ +From c664cd43b477337c76d6c6bc2d1edd1d8f0b1d61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Feb 2026 20:11:03 +0800 +Subject: drm/amdgpu: clear related counter after RAS eeprom reset + +From: Tao Zhou + +[ Upstream commit 3d77ca68eb0b48f88cc891d1b98f109b68e2ffcf ] + +Make eeprom data and its counter consistent. + +Signed-off-by: Tao Zhou +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +index ee271f43d5ad0..b5ab19bf6bbfc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -508,6 +508,9 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) + control->bad_channel_bitmap = 0; + amdgpu_dpm_send_hbm_bad_channel_flag(adev, control->bad_channel_bitmap); + con->update_channel_flag = false; ++ /* there is no record on eeprom now, clear the counter */ ++ if (con->eh_data) ++ con->eh_data->count_saved = 0; + + amdgpu_ras_debugfs_set_ret_size(control); + +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch b/queue-7.0/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch new file mode 100644 index 0000000000..b977a04ccc --- /dev/null +++ b/queue-7.0/drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch @@ -0,0 +1,133 @@ +From 83b2ed06837062b79c5beb442bc5bac7ce16ff77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:00:04 +0800 +Subject: drm/amdgpu: drop userq fence driver refs out of fence process() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Prike Liang + +[ Upstream commit dd88d42d9ca0dd7a4ed327dd33f6ead76cedf726 ] + +amdgpu_userq_wait_ioctl() takes extra references on waited-on fence +drivers and stores them in waitq->fence_drv_xa. When a new userq fence is +created, those references are transferred into userq_fence->fence_drv_array +so they can be released when the fence completes. + +However, those inherited references are currently only dropped from +amdgpu_userq_fence_driver_process(). If a fence never reaches that path, +such as it is already signaled when created, so we need to explicitly release +those fences in that case. + +v2: use a list(list_cut_before) for managing the signal userq driver fences.(Christian) + Link: https://patchwork.freedesktop.org/patch/718078/?series=164763&rev=2 +v3: Doesn't cache the userq first unsignaled fence and use the cut before list + head directly.(Christian) + +Cc: Alex Deucher +Signed-off-by: Prike Liang +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 47 +++++++++++++------ + 1 file changed, 33 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +index bb390067c26ef..26d0bbbd34b78 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +@@ -151,13 +151,22 @@ amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) + amdgpu_userq_fence_driver_put(userq->fence_drv); + } + ++static void ++amdgpu_userq_fence_put_fence_drv_array(struct amdgpu_userq_fence *userq_fence) ++{ ++ unsigned long i; ++ for (i = 0; i < userq_fence->fence_drv_array_count; i++) ++ amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); ++ userq_fence->fence_drv_array_count = 0; ++} ++ + void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv) + { + struct amdgpu_userq_fence *userq_fence, *tmp; ++ LIST_HEAD(to_be_signaled); + struct dma_fence *fence; + unsigned long flags; + u64 rptr; +- int i; + + if (!fence_drv) + return; +@@ -165,21 +174,26 @@ void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_d + spin_lock_irqsave(&fence_drv->fence_list_lock, flags); + rptr = amdgpu_userq_fence_read(fence_drv); + +- list_for_each_entry_safe(userq_fence, tmp, &fence_drv->fences, link) { +- fence = &userq_fence->base; +- +- if (rptr < fence->seqno) ++ list_for_each_entry(userq_fence, &fence_drv->fences, link) { ++ if (rptr < userq_fence->base.seqno) + break; ++ } + +- dma_fence_signal(fence); +- +- for (i = 0; i < userq_fence->fence_drv_array_count; i++) +- amdgpu_userq_fence_driver_put(userq_fence->fence_drv_array[i]); ++ list_cut_before(&to_be_signaled, &fence_drv->fences, ++ &userq_fence->link); ++ spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + +- list_del(&userq_fence->link); ++ list_for_each_entry_safe(userq_fence, tmp, &to_be_signaled, link) { ++ fence = &userq_fence->base; ++ list_del_init(&userq_fence->link); ++ dma_fence_signal(fence); ++ /* Drop fence_drv_array outside fence_list_lock ++ * to avoid the recursion lock. ++ */ ++ amdgpu_userq_fence_put_fence_drv_array(userq_fence); + dma_fence_put(fence); + } +- spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); ++ + } + + void amdgpu_userq_fence_driver_destroy(struct kref *ref) +@@ -242,6 +256,7 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, + struct amdgpu_userq_fence_driver *fence_drv; + struct dma_fence *fence; + unsigned long flags; ++ bool signaled = false; + + fence_drv = userq->fence_drv; + if (!fence_drv) +@@ -288,13 +303,17 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq, + + /* Check if hardware has already processed the job */ + spin_lock_irqsave(&fence_drv->fence_list_lock, flags); +- if (!dma_fence_is_signaled(fence)) ++ if (!dma_fence_is_signaled(fence)) { + list_add_tail(&userq_fence->link, &fence_drv->fences); +- else ++ } else { ++ signaled = true; + dma_fence_put(fence); +- ++ } + spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); + ++ if (signaled) ++ amdgpu_userq_fence_put_fence_drv_array(userq_fence); ++ + *f = fence; + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-amdgpu_userq_evict.patch b/queue-7.0/drm-amdgpu-fix-amdgpu_userq_evict.patch new file mode 100644 index 0000000000..72947fff0f --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-amdgpu_userq_evict.patch @@ -0,0 +1,47 @@ +From f5484ea77b3e8cfab1d3fe9c7db5898e998a6922 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 15:27:25 +0100 +Subject: drm/amdgpu: fix amdgpu_userq_evict +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 98dc529a27c57e184ab47453993ba9cfcfcec0ca ] + +Canceling the resume worker synchonized can deadlock because it can in +turn wait for the eviction worker through the userq_mutex. + +Signed-off-by: Christian König +Reviewed-by: Alex Deucher +Reviewed-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index be75e8de99683..a0e816ca471ec 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -1390,13 +1390,8 @@ amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, + /* Signal current eviction fence */ + amdgpu_eviction_fence_signal(evf_mgr, ev_fence); + +- if (evf_mgr->fd_closing) { +- cancel_delayed_work_sync(&uq_mgr->resume_work); +- return; +- } +- +- /* Schedule a resume work */ +- schedule_delayed_work(&uq_mgr->resume_work, 0); ++ if (!evf_mgr->fd_closing) ++ schedule_delayed_work(&uq_mgr->resume_work, 0); + } + + int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-array-out-of-bounds-accesses-for-mes-.patch b/queue-7.0/drm-amdgpu-fix-array-out-of-bounds-accesses-for-mes-.patch new file mode 100644 index 0000000000..20d853d610 --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-array-out-of-bounds-accesses-for-mes-.patch @@ -0,0 +1,63 @@ +From 801620d0537ff3b889c09a2142ae301b8810e8c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:43:20 +0800 +Subject: drm/amdgpu: fix array out of bounds accesses for mes sw_fini + +From: Le Ma + +[ Upstream commit 418b4e397570f1b0ffb6d5c8aa0872bc33071d49 ] + +The mes.fw[] is per-pipe resource shared accross xcc inst. +And enlarge hung_queue array to max inst_pipes. + +Signed-off-by: Le Ma +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 6 +++--- + drivers/gpu/drm/amd/amdgpu/mes_v12_1.c | 4 +++- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +index bcf2a067dc410..f80e3aca9c78e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +@@ -159,9 +159,9 @@ struct amdgpu_mes { + + int hung_queue_db_array_size; + int hung_queue_hqd_info_offset; +- struct amdgpu_bo *hung_queue_db_array_gpu_obj[AMDGPU_MAX_MES_PIPES]; +- uint64_t hung_queue_db_array_gpu_addr[AMDGPU_MAX_MES_PIPES]; +- void *hung_queue_db_array_cpu_addr[AMDGPU_MAX_MES_PIPES]; ++ struct amdgpu_bo *hung_queue_db_array_gpu_obj[AMDGPU_MAX_MES_INST_PIPES]; ++ uint64_t hung_queue_db_array_gpu_addr[AMDGPU_MAX_MES_INST_PIPES]; ++ void *hung_queue_db_array_cpu_addr[AMDGPU_MAX_MES_INST_PIPES]; + + /* cooperative dispatch */ + bool enable_coop_mode; +diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +index 7b8c670d0a9ed..d8e4b52bdfd50 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +@@ -1611,7 +1611,6 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block) + amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[inst], + &adev->mes.eop_gpu_addr[inst], + NULL); +- amdgpu_ucode_release(&adev->mes.fw[inst]); + + if (adev->enable_uni_mes || pipe == AMDGPU_MES_SCHED_PIPE) { + amdgpu_bo_free_kernel(&adev->mes.ring[inst].mqd_obj, +@@ -1622,6 +1621,9 @@ static int mes_v12_1_sw_fini(struct amdgpu_ip_block *ip_block) + } + } + ++ for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) ++ amdgpu_ucode_release(&adev->mes.fw[pipe]); ++ + for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) { + if (!adev->enable_uni_mes) { + amdgpu_bo_free_kernel(&adev->gfx.kiq[xcc_id].ring.mqd_obj, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-cper-ring-header-parsing.patch b/queue-7.0/drm-amdgpu-fix-cper-ring-header-parsing.patch new file mode 100644 index 0000000000..269fa05911 --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-cper-ring-header-parsing.patch @@ -0,0 +1,107 @@ +From 95c43aab892bee8f298cc4eadc49cf4ce257843e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 17:10:21 +0800 +Subject: drm/amdgpu: fix CPER ring header parsing + +From: Xiang Liu + +[ Upstream commit b8939bd764c9c8bf6488dc0d71d9c718c25d8cfc ] + +amdgpu_cper_ring_get_ent_sz() parses CPER headers directly from the +circular ring buffer to determine the current entry size. When the ring +is full and the write pointer lands near the end of the buffer, the +header can wrap across the ring boundary. + +The existing code treats the 4-byte CPER signature as a C string and +uses strcmp() on in-ring binary data, then reads record_length through a +direct struct pointer cast. Both assumptions are unsafe for wrapped +entries and can read past the end of the ring mapping. + +Fix the parser by comparing the signature as raw bytes and by copying +the header into a local buffer before reading record_length, handling +wraparound explicitly in both cases. This avoids out-of-bounds reads in +amdgpu_cper_ring_get_ent_sz() when the CPER ring is full or the current +entry starts at the tail of the ring. + +Signed-off-by: Xiang Liu +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c | 36 ++++++++++++++++++------ + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +index c72c345334d01..4e6e390854e6e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +@@ -32,6 +32,8 @@ static const guid_t BOOT = BOOT_TYPE; + static const guid_t CRASHDUMP = AMD_CRASHDUMP; + static const guid_t RUNTIME = AMD_GPU_NONSTANDARD_ERROR; + ++#define CPER_SIGNATURE_SZ (sizeof(((struct cper_hdr *)0)->signature)) ++ + static void __inc_entry_length(struct cper_hdr *hdr, uint32_t size) + { + hdr->record_length += size; +@@ -425,23 +427,40 @@ int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev, + + static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos) + { +- struct cper_hdr *chdr; ++ char signature[CPER_SIGNATURE_SZ]; ++ ++ if ((pos << 2) >= ring->ring_size) ++ return false; + +- chdr = (struct cper_hdr *)&(ring->ring[pos]); +- return strcmp(chdr->signature, "CPER") ? false : true; ++ if ((pos << 2) + CPER_SIGNATURE_SZ <= ring->ring_size) { ++ memcpy(signature, &ring->ring[pos], CPER_SIGNATURE_SZ); ++ } else { ++ u32 chunk = ring->ring_size - (pos << 2); ++ ++ memcpy(signature, &ring->ring[pos], chunk); ++ memcpy(signature + chunk, ring->ring, CPER_SIGNATURE_SZ - chunk); ++ } ++ ++ return !memcmp(signature, "CPER", CPER_SIGNATURE_SZ); + } + + static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) + { +- struct cper_hdr *chdr; ++ struct cper_hdr chdr; + u64 p; + u32 chunk, rec_len = 0; + +- chdr = (struct cper_hdr *)&(ring->ring[pos]); + chunk = ring->ring_size - (pos << 2); + +- if (!strcmp(chdr->signature, "CPER")) { +- rec_len = chdr->record_length; ++ if (amdgpu_cper_is_hdr(ring, pos)) { ++ if (chunk >= sizeof(chdr)) { ++ memcpy(&chdr, &ring->ring[pos], sizeof(chdr)); ++ } else { ++ memcpy(&chdr, &ring->ring[pos], chunk); ++ memcpy((u8 *)&chdr + chunk, ring->ring, sizeof(chdr) - chunk); ++ } ++ ++ rec_len = chdr.record_length; + goto calc; + } + +@@ -450,8 +469,7 @@ static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos) + goto calc; + + for (p = pos + 1; p <= ring->buf_mask; p++) { +- chdr = (struct cper_hdr *)&(ring->ring[p]); +- if (!strcmp(chdr->signature, "CPER")) { ++ if (amdgpu_cper_is_hdr(ring, p)) { + rec_len = (p - pos) << 2; + goto calc; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch b/queue-7.0/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch new file mode 100644 index 0000000000..9dcd9eddb3 --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch @@ -0,0 +1,36 @@ +From 807273c6e5045f27611b03bcba8f2250acea6648 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 09:33:17 +0800 +Subject: drm/amdgpu: fix DF NULL pointer issue for soc24 + +From: Likun Gao + +[ Upstream commit 50808826a64b4957b7088c789e539dd0a75a1560 ] + +If DF function not initialized, NULL pointer issue +will happen on soc24. + +Signed-off-by: Likun Gao +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/soc24.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c +index ecb6c3fcfbd15..984262936545f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc24.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc24.c +@@ -484,7 +484,7 @@ static int soc24_common_hw_init(struct amdgpu_ip_block *ip_block) + if (adev->nbio.funcs->remap_hdp_registers) + adev->nbio.funcs->remap_hdp_registers(adev); + +- if (adev->df.funcs->hw_init) ++ if (adev->df.funcs && adev->df.funcs->hw_init) + adev->df.funcs->hw_init(adev); + + /* enable the doorbell aperture */ +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch b/queue-7.0/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch new file mode 100644 index 0000000000..207279f174 --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch @@ -0,0 +1,46 @@ +From 0292fba29747115bbf3643a2de177a7a004cf163 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 18:53:40 +0800 +Subject: drm/amdgpu: fix shift-out-of-bounds when updating umc active mask + +From: Hawking Zhang + +[ Upstream commit 1394a4926f4bcff0dc6ac6deea5beeb2844297f0 ] + +UMC node_inst_num can exceed 32, causing +(1 << node_inst_num) to shift a 32-bit int +out of bounds + +Signed-off-by: Hawking Zhang +Reviewed-by: Likun Gao +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index 3459d356151ef..ad93dffd59dd1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -774,7 +774,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + struct harvest_table *harvest_info; + u16 offset; + int i; +- uint32_t umc_harvest_config = 0; ++ u64 umc_harvest_config = 0; + + bhdr = (struct binary_header *)discovery_bin; + offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset); +@@ -830,7 +830,7 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev, + } + } + +- adev->umc.active_mask = ((1 << adev->umc.node_inst_num) - 1) & ++ adev->umc.active_mask = ((1ULL << adev->umc.node_inst_num) - 1ULL) & + ~umc_harvest_config; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch b/queue-7.0/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch new file mode 100644 index 0000000000..e7efe7732a --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch @@ -0,0 +1,166 @@ +From 656c01dd8c89a059f0c62fe35910b2a7b43f217d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 17:30:57 +0100 +Subject: drm/amdgpu: fix some more bug in amdgpu_gem_va_ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 68bd4f6b8310f309eb63b41e15088690c9cec0a9 ] + +Some illegal combination of input flags were not checked and we need to +take the PDEs into account when returning the fence as well. + +Signed-off-by: Christian König +Acked-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 76 +++++++++++-------------- + 1 file changed, 34 insertions(+), 42 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index a6107109a2b86..c4839cf2dce37 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -744,11 +745,10 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + struct dma_fence *fence; + int r = 0; + +- /* Always start from the VM's existing last update fence. */ +- fence = dma_fence_get(vm->last_update); +- ++ /* If the VM is not ready return only a stub. */ + if (!amdgpu_vm_ready(vm)) +- return fence; ++ return dma_fence_get_stub(); ++ + + /* + * First clean up any freed mappings in the VM. +@@ -757,7 +757,7 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + * schedules GPU work. If nothing needs clearing, @fence can remain as + * the original vm->last_update. + */ +- r = amdgpu_vm_clear_freed(adev, vm, &fence); ++ r = amdgpu_vm_clear_freed(adev, vm, &vm->last_update); + if (r) + goto error; + +@@ -774,47 +774,34 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, + if (r) + goto error; + +- /* +- * Decide which fence best represents the last update: +- * +- * MAP/REPLACE: +- * - For always-valid mappings, use vm->last_update. +- * - Otherwise, export bo_va->last_pt_update. +- * +- * UNMAP/CLEAR: +- * Keep the fence returned by amdgpu_vm_clear_freed(). If no work was +- * needed, it can remain as vm->last_pt_update. +- * +- * The VM and BO update fences are always initialized to a valid value. +- * vm->last_update and bo_va->last_pt_update always start as valid fences. +- * and are never expected to be NULL. +- */ +- switch (operation) { +- case AMDGPU_VA_OP_MAP: +- case AMDGPU_VA_OP_REPLACE: ++ if ((operation == AMDGPU_VA_OP_MAP || ++ operation == AMDGPU_VA_OP_REPLACE) && ++ !amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) { ++ + /* +- * For MAP/REPLACE, return the page table update fence for the +- * mapping we just modified. bo_va is expected to be valid here. ++ * For MAP/REPLACE of non per-VM BOs we need to sync to both the ++ * bo_va->last_pt_update and vm->last_update or otherwise we ++ * potentially miss the PDE updates. + */ +- dma_fence_put(fence); +- +- if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) +- fence = dma_fence_get(vm->last_update); +- else +- fence = dma_fence_get(bo_va->last_pt_update); +- break; +- case AMDGPU_VA_OP_UNMAP: +- case AMDGPU_VA_OP_CLEAR: +- default: +- /* keep @fence as returned by amdgpu_vm_clear_freed() */ +- break; ++ fence = dma_fence_unwrap_merge(vm->last_update, ++ bo_va->last_pt_update); ++ if (!fence) { ++ /* As fallback in OOM situations */ ++ dma_fence_wait(vm->last_update, false); ++ dma_fence_wait(bo_va->last_pt_update, false); ++ fence = dma_fence_get_stub(); ++ } ++ } else { ++ fence = dma_fence_get(vm->last_update); + } + ++ return fence; ++ + error: + if (r && r != -ERESTARTSYS) + DRM_ERROR("Couldn't update BO_VA (%d)\n", r); + +- return fence; ++ return dma_fence_get(vm->last_update); + } + + int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, +@@ -835,7 +822,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + struct amdgpu_bo_va *bo_va; + struct drm_syncobj *timeline_syncobj = NULL; + struct dma_fence_chain *timeline_chain = NULL; +- struct dma_fence *fence; + struct drm_exec exec; + uint64_t vm_size; + int r = 0; +@@ -887,6 +873,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + return -EINVAL; + } + ++ if (args->flags & AMDGPU_VM_DELAY_UPDATE && ++ args->vm_timeline_syncobj_out) ++ return -EINVAL; ++ + if ((args->operation != AMDGPU_VA_OP_CLEAR) && + !(args->flags & AMDGPU_VM_PAGE_PRT)) { + gobj = drm_gem_object_lookup(filp, args->handle); +@@ -976,11 +966,13 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + * that represents the last relevant update for this mapping. This + * fence can then be exported to the user-visible VM timeline. + */ +- if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !adev->debug_vm) { ++ if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && ++ (!adev->debug_vm || timeline_syncobj)) { ++ struct dma_fence *fence; ++ + fence = amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, + args->operation); +- +- if (timeline_syncobj && fence) { ++ if (timeline_syncobj) { + if (!args->vm_timeline_point) { + /* Replace the existing fence when no point is given. */ + drm_syncobj_replace_fence(timeline_syncobj, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch b/queue-7.0/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch new file mode 100644 index 0000000000..b738366e3b --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch @@ -0,0 +1,56 @@ +From 469c286839d4d0803111a736c252f4687856c239 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:47:11 +0800 +Subject: drm/amdgpu: fix syncobj leak for amdgpu_gem_va_ioctl() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Prike Liang + +[ Upstream commit a0f0b6d31a53a7607ed44f7623faafc628333258 ] + +It requires freeing the syncobj and chain +alloction resource. + +Signed-off-by: Prike Liang +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index c4839cf2dce37..3f95aca700264 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -107,6 +107,7 @@ amdgpu_gem_update_timeline_node(struct drm_file *filp, + *chain = dma_fence_chain_alloc(); + if (!*chain) { + drm_syncobj_put(*syncobj); ++ *syncobj = NULL; + return -ENOMEM; + } + +@@ -983,6 +984,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + timeline_chain, + fence, + args->vm_timeline_point); ++ timeline_chain = NULL; + } + } + dma_fence_put(fence); +@@ -990,6 +992,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, + } + + error: ++ dma_fence_chain_free(timeline_chain); ++ if (timeline_syncobj) ++ drm_syncobj_put(timeline_syncobj); + drm_exec_fini(&exec); + error_put_gobj: + drm_gem_object_put(gobj); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch b/queue-7.0/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch new file mode 100644 index 0000000000..8d58de29ef --- /dev/null +++ b/queue-7.0/drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch @@ -0,0 +1,95 @@ +From 23891f14f5ca863531194f495d5e5140137d1915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:28:59 +0800 +Subject: drm/amdgpu: guard atom_context in devcoredump VBIOS dump + +From: Jesse Zhang + +[ Upstream commit 557fa5a453c9ccb49a22f30a7ad0545573d434b7 ] + +During GPU reset coredump generation, amdgpu_devcoredump_fw_info() unconditionally +dereferences adev->mode_info.atom_context to print VBIOS fields. On reset/teardown +paths this pointer can be NULL, causing a kernel page fault from the deferred +coredump workqueue. + +Fix by checking ctx before printing VBIOS fields: + +if ctx is valid, print full VBIOS information as before; +This prevents NULL-dereference crashes while preserving coredump output. + +Observed page fault log: +[ 667.933329] RIP: 0010:amdgpu_devcoredump_format+0x780/0xc00 [amdgpu] +[ 667.941517] amdgpu 0002:01:00.0: Dumping IP State +[ 667.949660] Code: 8d 57 74 48 c7 c6 01 65 9f c2 48 8d 7d 98 e8 97 96 7a ff 49 8d 97 b4 00 00 00 48 c7 c6 18 65 9f c2 48 8d 7d 98 e8 80 96 7a ff <41> 8b 97 f4 00 00 00 48 c7 c6 2f 65 9f c2 48 8d 7d 98 e8 69 96 7a +[ 667.949666] RSP: 0018:ffffc9002302bd50 EFLAGS: 00010246 +[ 667.949673] RAX: 0000000000000000 RBX: ffff888110600000 RCX: 0000000000000000 +[ 667.949676] RDX: 000000000000a9b5 RSI: 0000000000000405 RDI: 000000000000a999 +[ 667.949680] RBP: ffffc9002302be00 R08: ffffffffc09c3084 R09: ffffffffc09c3085 +[ 667.949684] R10: 0000000000000000 R11: 0000000000000004 R12: 00000000000048e0 +[ 667.993908] amdgpu 0002:01:00.0: Dumping IP State Completed +[ 667.994229] R13: 0000000000000025 R14: 000000000000000c R15: 0000000000000000 +[ 667.994233] FS: 0000000000000000(0000) GS:ffff88c44c2c9000(0000) knlGS:0000000000000000 +[ 668.000076] amdgpu 0002:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.008025] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 668.008030] CR2: 00000000000000f4 CR3: 000000011195f001 CR4: 0000000000770ef0 +[ 668.008035] PKRU: 55555554 +[ 668.008040] Call Trace: +[ 668.008045] +[ 668.016010] amdgpu 0002:01:00.0: [drm] Check your /sys/class/drm/card16/device/devcoredump/data +[ 668.023967] ? srso_alias_return_thunk+0x5/0xfbef5 +[ 668.023988] ? __pfx___drm_printfn_coredump+0x10/0x10 [drm] +[ 668.031950] amdgpu 0003:01:00.0: Dumping IP State +[ 668.038159] ? __pfx___drm_puts_coredump+0x10/0x10 [drm] +[ 668.083017] amdgpu 0003:01:00.0: Dumping IP State Completed +[ 668.083824] amdgpu_devcoredump_deferred_work+0x26/0xc0 [amdgpu] +[ 668.086163] amdgpu 0003:01:00.0: [drm] AMDGPU device coredump file has been created +[ 668.095863] process_scheduled_works+0xa6/0x420 +[ 668.095880] worker_thread+0x12a/0x270 +[ 668.101223] amdgpu 0003:01:00.0: [drm] Check your /sys/class/drm/card24/device/devcoredump/data +[ 668.107441] kthread+0x10d/0x230 +[ 668.107451] ? __pfx_worker_thread+0x10/0x10 +[ 668.107458] ? __pfx_kthread+0x10/0x10 +[ 668.112709] amdgpu 0000:01:00.0: ring vcn_unified_1 timeout, signaled seq=9, emitted seq=10 +[ 668.118630] ret_from_fork+0x17c/0x1f0 +[ 668.118640] ? __pfx_kthread+0x10/0x10 +[ 668.118647] ret_from_fork_asm+0x1a/0x30 + +Reviewed-by: Lijo Lazar +Suggested-by: Lijo Lazar +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +index c38e7371bafce..fed4e73d3492f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +@@ -187,12 +187,16 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev, + drm_printf(p, "VPE feature version: %u, fw version: 0x%08x\n", + adev->vpe.feature_version, adev->vpe.fw_version); + +- drm_printf(p, "\nVBIOS Information\n"); +- drm_printf(p, "vbios name : %s\n", ctx->name); +- drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); +- drm_printf(p, "vbios version : %d\n", ctx->version); +- drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); +- drm_printf(p, "vbios date : %s\n", ctx->date); ++ if (adev->bios) { ++ drm_printf(p, "\nVBIOS Information\n"); ++ drm_printf(p, "vbios name : %s\n", ctx->name); ++ drm_printf(p, "vbios pn : %s\n", ctx->vbios_pn); ++ drm_printf(p, "vbios version : %d\n", ctx->version); ++ drm_printf(p, "vbios ver_str : %s\n", ctx->vbios_ver_str); ++ drm_printf(p, "vbios date : %s\n", ctx->date); ++ }else { ++ drm_printf(p, "\nVBIOS Information: NA\n"); ++ } + } + + static ssize_t +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-handle-ih-v7_1-reg-offset-differences.patch b/queue-7.0/drm-amdgpu-handle-ih-v7_1-reg-offset-differences.patch new file mode 100644 index 0000000000..04f5fa0f0b --- /dev/null +++ b/queue-7.0/drm-amdgpu-handle-ih-v7_1-reg-offset-differences.patch @@ -0,0 +1,99 @@ +From 23b7fdd764b2193c6ac75a9037ae908570bd8977 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 21:36:19 +0800 +Subject: drm/amdgpu: Handle IH v7_1 reg offset differences + +From: Hawking Zhang + +[ Upstream commit 41c61e60f82d55e9a3a3f3f04d192d732230a91c ] + +IH v7_1 changes the offsets of some registers relative to +IH v7_0. Introduce IH v7_1-specific register access + +Signed-off-by: Hawking Zhang +Reviewed-by: Lijo Lazar +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/ih_v7_0.c | 36 ++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c +index 451828bf583e4..1fbe904f4223b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c +@@ -289,6 +289,13 @@ static uint32_t ih_v7_0_setup_retry_doorbell(u32 doorbell_index) + return val; + } + ++#define regIH_RING1_CLIENT_CFG_INDEX_V7_1 0x122 ++#define regIH_RING1_CLIENT_CFG_INDEX_V7_1_BASE_IDX 0 ++#define regIH_RING1_CLIENT_CFG_DATA_V7_1 0x123 ++#define regIH_RING1_CLIENT_CFG_DATA_V7_1_BASE_IDX 0 ++#define regIH_CHICKEN_V7_1 0x129 ++#define regIH_CHICKEN_V7_1_BASE_IDX 0 ++ + /** + * ih_v7_0_irq_init - init and enable the interrupt ring + * +@@ -307,6 +314,7 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev) + u32 tmp; + int ret; + int i; ++ u32 reg_addr; + + /* disable irqs */ + ret = ih_v7_0_toggle_interrupts(adev, false); +@@ -318,10 +326,15 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev) + if (unlikely((adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) || + (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO))) { + if (ih[0]->use_bus_addr) { +- ih_chicken = RREG32_SOC15(OSSSYS, 0, regIH_CHICKEN); ++ if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0)) ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_CHICKEN_V7_1); ++ else ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_CHICKEN); ++ ih_chicken = RREG32(reg_addr); ++ /* The reg fields definitions are identical in ih v7_0 and ih v7_1 */ + ih_chicken = REG_SET_FIELD(ih_chicken, + IH_CHICKEN, MC_SPACE_GPA_ENABLE, 1); +- WREG32_SOC15(OSSSYS, 0, regIH_CHICKEN, ih_chicken); ++ WREG32(reg_addr, ih_chicken); + } + } + +@@ -358,17 +371,26 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev) + + /* Redirect the interrupts to IH RB1 for dGPU */ + if (adev->irq.ih1.ring_size) { +- tmp = RREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX); ++ if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0)) ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX_V7_1); ++ else ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX); ++ tmp = RREG32(reg_addr); ++ /* The reg fields definitions are identical in ih v7_0 and ih v7_1 */ + tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_INDEX, INDEX, 0); +- WREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_INDEX, tmp); ++ WREG32(reg_addr, tmp); + +- tmp = RREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA); ++ if (amdgpu_ip_version(adev, OSSSYS_HWIP, 0) == IP_VERSION(7, 1, 0)) ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA_V7_1); ++ else ++ reg_addr = SOC15_REG_OFFSET(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA); ++ tmp = RREG32(reg_addr); ++ /* The reg fields definitions are identical in ih v7_0 and ih v7_1 */ + tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA, CLIENT_ID, 0xa); + tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA, SOURCE_ID, 0x0); + tmp = REG_SET_FIELD(tmp, IH_RING1_CLIENT_CFG_DATA, + SOURCE_ID_MATCH_ENABLE, 0x1); +- +- WREG32_SOC15(OSSSYS, 0, regIH_RING1_CLIENT_CFG_DATA, tmp); ++ WREG32(reg_addr, tmp); + } + + pci_set_master(adev->pdev); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-or-init_pte_flags-into-invalid-leaf-pte-u.patch b/queue-7.0/drm-amdgpu-or-init_pte_flags-into-invalid-leaf-pte-u.patch new file mode 100644 index 0000000000..b29b8227b0 --- /dev/null +++ b/queue-7.0/drm-amdgpu-or-init_pte_flags-into-invalid-leaf-pte-u.patch @@ -0,0 +1,49 @@ +From 020d6d42789b00ce0f51d52c9165b0fd02163fad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:46:54 -0400 +Subject: drm/amdgpu: OR init_pte_flags into invalid leaf PTE updates + +From: Siwei He + +[ Upstream commit 778bf584f2fb0a2b09594f568faf400bf6858091 ] + +Invalid leaf clears that only set AMDGPU_PTE_EXECUTABLE match the old +GMC9 fault-priority workaround but omit adev->gmc.init_pte_flags. +On GFX12 that includes AMDGPU_PTE_IS_PTE; without it, some cleared +PTEs can fault as no-retry and bypass the SVM/XNACK handler when a +VA is reused after a BO unmap. + +Apply init_pte_flags in amdgpu_vm_pte_update_flags() alongside +EXECUTABLE so range-driven clears (e.g. amdgpu_vm_clear_freed) match +amdgpu_vm_pt_clear() for leaf templates. + +Signed-off-by: Siwei He +Reviewed-by: Philip Yang +Signed-off-by: Alex Deucher +(cherry picked from commit 9d47b2c36b9a6c6b844c33cab407a5d7ad102234) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +index 31a437ce95704..a930f1522f962 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +@@ -693,8 +693,11 @@ static void amdgpu_vm_pte_update_flags(struct amdgpu_vm_update_params *params, + !(flags & AMDGPU_PTE_VALID) && + !(flags & AMDGPU_PTE_PRT_FLAG(params->adev))) { + +- /* Workaround for fault priority problem on GMC9 */ +- flags |= AMDGPU_PTE_EXECUTABLE; ++ /* Workaround for fault priority problem on GMC9 and GFX12, ++ * EXECUTABLE for GMC9 fault priority and init_pte_flags ++ * (e.g. AMDGPU_PTE_IS_PTE on GFX12) ++ */ ++ flags |= AMDGPU_PTE_EXECUTABLE | adev->gmc.init_pte_flags; + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-revert-setting-up-retry-based-thrashing-o.patch b/queue-7.0/drm-amdgpu-revert-setting-up-retry-based-thrashing-o.patch new file mode 100644 index 0000000000..c2caec5f05 --- /dev/null +++ b/queue-7.0/drm-amdgpu-revert-setting-up-retry-based-thrashing-o.patch @@ -0,0 +1,60 @@ +From fd1ef48fe77ac26cd3f0b3a27a8d51990d01b5eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Nov 2025 19:15:11 -0500 +Subject: drm/amdgpu: Revert setting up Retry based Thrashing on GFX 12.1 + +From: Sreekant Somasekharan + +[ Upstream commit 29756a7535facdaed39d0b5572201068a7746812 ] + +Bug found with retry based thrashing mechanism. Revert to the old +thrashing method. + +Signed-off-by: Sreekant Somasekharan +Reviewed-by: Mukul Joshi +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 19 ------------------- + 1 file changed, 19 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +index 557d15b90ad27..6c34fda1f28e8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +@@ -2629,24 +2629,6 @@ static void gfx_v12_1_xcc_disable_gpa_mode(struct amdgpu_device *adev, + WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCPG_PSP_DEBUG, data); + } + +-static void gfx_v12_1_xcc_setup_tcp_thrashing_ctrl(struct amdgpu_device *adev, +- int xcc_id) +-{ +- uint32_t val; +- +- /* Set the TCP UTCL0 register to enable atomics */ +- val = RREG32_SOC15(GC, GET_INST(GC, xcc_id), +- regTCP_UTCL0_THRASHING_CTRL); +- val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, THRASHING_EN, 0x2); +- val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, +- RETRY_FRAGMENT_THRESHOLD_UP_EN, 0x1); +- val = REG_SET_FIELD(val, TCP_UTCL0_THRASHING_CTRL, +- RETRY_FRAGMENT_THRESHOLD_DOWN_EN, 0x1); +- +- WREG32_SOC15(GC, GET_INST(GC, xcc_id), +- regTCP_UTCL0_THRASHING_CTRL, val); +-} +- + static void gfx_v12_1_xcc_enable_atomics(struct amdgpu_device *adev, + int xcc_id) + { +@@ -2695,7 +2677,6 @@ static void gfx_v12_1_init_golden_registers(struct amdgpu_device *adev) + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); i++) { + gfx_v12_1_xcc_disable_burst(adev, i); + gfx_v12_1_xcc_enable_atomics(adev, i); +- gfx_v12_1_xcc_setup_tcp_thrashing_ctrl(adev, i); + gfx_v12_1_xcc_disable_early_write_ack(adev, i); + gfx_v12_1_xcc_disable_tcp_spill_cache(adev, i); + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-cleanup-amdgpu_userq_get-put-where-.patch b/queue-7.0/drm-amdgpu-userq-cleanup-amdgpu_userq_get-put-where-.patch new file mode 100644 index 0000000000..6e2d05505c --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-cleanup-amdgpu_userq_get-put-where-.patch @@ -0,0 +1,103 @@ +From 66e009d3efabce6b0de316a8d26f95bec96a5263 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 17:29:01 +0530 +Subject: drm/amdgpu/userq: cleanup amdgpu_userq_get/put where not needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 8f402ddd4f2321485fff7384c003124681a08146 ] + +amdgpu_userq_put/get are not needed in case we already holding +the userq_mutex and reference is valid already from queue create +time or from signal ioctl. These additional get/put could be a +potential reason for deadlock in case the ref count reaches zero +and destroy is called which again try to take the userq_mutex. + +Due to the above change we avoid deadlock between suspend/restore +calling destroy queues trying to take userq_mutex again. + +Cc: Prike Liang +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 21 +++------------------ + 1 file changed, 3 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index c7e2eb09c9435..6a5a214a592a5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -1057,15 +1057,11 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) + + /* Resume all the queues for this process */ + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { +- queue = amdgpu_userq_get(uq_mgr, queue_id); +- if (!queue) +- continue; + + if (!amdgpu_userq_buffer_vas_mapped(queue)) { + drm_file_err(uq_mgr->file, + "trying restore queue without va mapping\n"); + queue->state = AMDGPU_USERQ_STATE_INVALID_VA; +- amdgpu_userq_put(queue); + continue; + } + +@@ -1073,7 +1069,6 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) + if (r) + ret = r; + +- amdgpu_userq_put(queue); + } + + if (ret) +@@ -1308,13 +1303,9 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) + amdgpu_userq_detect_and_reset_queues(uq_mgr); + /* Try to unmap all the queues in this process ctx */ + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { +- queue = amdgpu_userq_get(uq_mgr, queue_id); +- if (!queue) +- continue; + r = amdgpu_userq_preempt_helper(queue); + if (r) + ret = r; +- amdgpu_userq_put(queue); + } + + if (ret) +@@ -1347,24 +1338,18 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) + int ret; + + xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { +- queue = amdgpu_userq_get(uq_mgr, queue_id); +- if (!queue) +- continue; +- + struct dma_fence *f = queue->last_fence; + +- if (!f || dma_fence_is_signaled(f)) { +- amdgpu_userq_put(queue); ++ if (!f || dma_fence_is_signaled(f)) + continue; +- } ++ + ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100)); + if (ret <= 0) { + drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", + f->context, f->seqno); +- amdgpu_userq_put(queue); ++ + return -ETIMEDOUT; + } +- amdgpu_userq_put(queue); + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-defer-queue-publication-until-creat.patch b/queue-7.0/drm-amdgpu-userq-defer-queue-publication-until-creat.patch new file mode 100644 index 0000000000..30223d01cb --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-defer-queue-publication-until-creat.patch @@ -0,0 +1,139 @@ +From 8d0c7fc232ef15484b77a4208bafefb0036dc3a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 00:38:06 +0530 +Subject: drm/amdgpu/userq: defer queue publication until create completes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 28cacaace5cde8318b7da967b3955a73cc6de91a ] + +The userq create path publishes queues to global xarrays such as +userq_doorbell_xa and userq_xa before creation was fully complete. +Later on if create queue fails, teardown could free an already +visible queue, opening a UAF race with concurrent queue walkers. +Also calling amdgpu_userq_put in such cases complicates the cleanup. + +Solution is to defer queue publication until create succeeds and no +partially initialized queue is exposed. + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 66 +++++++++++------------ + 1 file changed, 33 insertions(+), 33 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index f2e504c7cde15..be75e8de99683 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -765,7 +765,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) + const struct amdgpu_userq_funcs *uq_funcs; + struct amdgpu_usermode_queue *queue; + struct amdgpu_db_info db_info; +- char *queue_name; + bool skip_map_queue; + u32 qid; + uint64_t index; +@@ -855,32 +854,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) + goto unlock; + } + +- /* drop this refcount during queue destroy */ +- kref_init(&queue->refcount); +- +- /* Wait for mode-1 reset to complete */ +- down_read(&adev->reset_domain->sem); +- r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL)); +- if (r) { +- kfree(queue); +- up_read(&adev->reset_domain->sem); +- goto unlock; +- } +- +- r = xa_alloc(&uq_mgr->userq_xa, &qid, queue, +- XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL); +- if (r) { +- drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n"); +- amdgpu_userq_fence_driver_free(queue); +- xa_erase_irq(&adev->userq_doorbell_xa, index); +- uq_funcs->mqd_destroy(queue); +- kfree(queue); +- r = -ENOMEM; +- up_read(&adev->reset_domain->sem); +- goto unlock; +- } +- up_read(&adev->reset_domain->sem); +- + /* don't map the queue if scheduling is halted */ + if (adev->userq_halt_for_enforce_isolation && + ((queue->queue_type == AMDGPU_HW_IP_GFX) || +@@ -892,28 +865,55 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) + r = amdgpu_userq_map_helper(queue); + if (r) { + drm_file_err(uq_mgr->file, "Failed to map Queue\n"); +- xa_erase_irq(&adev->userq_doorbell_xa, index); +- xa_erase(&uq_mgr->userq_xa, qid); +- amdgpu_userq_fence_driver_free(queue); + uq_funcs->mqd_destroy(queue); ++ amdgpu_userq_fence_driver_free(queue); + kfree(queue); + goto unlock; + } + } + +- queue_name = kasprintf(GFP_KERNEL, "queue-%d", qid); +- if (!queue_name) { ++ /* drop this refcount during queue destroy */ ++ kref_init(&queue->refcount); ++ ++ /* Wait for mode-1 reset to complete */ ++ down_read(&adev->reset_domain->sem); ++ r = xa_alloc(&uq_mgr->userq_xa, &qid, queue, ++ XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL); ++ if (r) { ++ if (!skip_map_queue) ++ amdgpu_userq_unmap_helper(queue); ++ ++ uq_funcs->mqd_destroy(queue); ++ amdgpu_userq_fence_driver_free(queue); ++ kfree(queue); + r = -ENOMEM; ++ up_read(&adev->reset_domain->sem); + goto unlock; + } + ++ r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL)); ++ if (r) { ++ xa_erase(&uq_mgr->userq_xa, qid); ++ if (!skip_map_queue) ++ amdgpu_userq_unmap_helper(queue); ++ ++ uq_funcs->mqd_destroy(queue); ++ amdgpu_userq_fence_driver_free(queue); ++ kfree(queue); ++ up_read(&adev->reset_domain->sem); ++ goto unlock; ++ } ++ up_read(&adev->reset_domain->sem); ++ + #if defined(CONFIG_DEBUG_FS) ++ char queue_name[32]; ++ ++ scnprintf(queue_name, sizeof(queue_name), "queue_%d", qid); + /* Queue dentry per client to hold MQD information */ + queue->debugfs_queue = debugfs_create_dir(queue_name, filp->debugfs_client); + debugfs_create_file("mqd_info", 0444, queue->debugfs_queue, queue, &amdgpu_mqd_info_fops); + #endif + amdgpu_userq_init_hang_detect_work(queue); +- kfree(queue_name); + + args->out.queue_id = qid; + atomic_inc(&uq_mgr->userq_count[queue->queue_type]); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch b/queue-7.0/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch new file mode 100644 index 0000000000..3e19d42b45 --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch @@ -0,0 +1,64 @@ +From e82e0ff66a16d6e7535beff36ff08f96f6e88f6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 12:41:22 +0530 +Subject: drm/amdgpu/userq: fix dma_fence refcount underflow in userq path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 7a14a4e9b3fda05b907d0445a3be9e7c0e887f4e ] + +An extra dma_fence_put() can drop the last reference to a fence while it is +still attached to a dma_resv object. This frees the fence prematurely via +dma_fence_release() while other users still hold the pointer. + +Later accesses through dma_resv iteration may then operate on the freed +fence object, leading to refcount underflow warnings and potential hangs +when walking reservation fences. + +Fix this by correcting the fence lifetime so the dma_resv object retains a +valid reference until it is done with the fence.i + +[ 31.133803] refcount_t: underflow; use-after-free. +[ 31.133805] WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x58/0x90, CPU#18: kworker/u96:1/188 + +Signed-off-by: Sunil Khatri +Reviewed-by: Tvrtko Ursulin +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +index 5239b06b9ab03..bb390067c26ef 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +@@ -947,12 +947,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, + * be good for now + */ + r = dma_fence_wait(fences[i], true); +- if (r) { +- dma_fence_put(fences[i]); ++ if (r) + goto free_fences; +- } + +- dma_fence_put(fences[i]); + continue; + } + +@@ -974,7 +971,6 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, + fence_info[cnt].va = fence_drv->va; + fence_info[cnt].value = fences[i]->seqno; + +- dma_fence_put(fences[i]); + /* Increment the actual userq fence count */ + cnt++; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xa-durin.patch b/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xa-durin.patch new file mode 100644 index 0000000000..0a05783ccf --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xa-durin.patch @@ -0,0 +1,38 @@ +From 4753bd4dcbd8e229718cad5935482f58afe2f654 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 22:30:04 +0530 +Subject: drm/amdgpu/userq: remove queue from doorbell xa during clean up +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit a978ed3d6454e4aa1a2ac74051ffd77b7d263e44 ] + +If function amdgpu_userq_map_helper fails we do need to clean +up and remove the queue from the userq_doorbell_xa. + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index 0158140b8faaa..f2e504c7cde15 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -892,6 +892,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) + r = amdgpu_userq_map_helper(queue); + if (r) { + drm_file_err(uq_mgr->file, "Failed to map Queue\n"); ++ xa_erase_irq(&adev->userq_doorbell_xa, index); + xa_erase(&uq_mgr->userq_xa, qid); + amdgpu_userq_fence_driver_free(queue); + uq_funcs->mqd_destroy(queue); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xarray.patch b/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xarray.patch new file mode 100644 index 0000000000..b82c2992c9 --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-remove-queue-from-doorbell-xarray.patch @@ -0,0 +1,38 @@ +From 379c49b0a876943b1bbfe9b7c45e22006b74b0ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 22:25:57 +0530 +Subject: drm/amdgpu/userq: remove queue from doorbell xarray +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit f0e46fd06c3f7590b0f06aea3c877f441c2cbccc ] + +In case of failure in xa_alloc, remove the queue during +clean up from the userq_doorbell_xa. + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index 0e015741ab24e..0158140b8faaa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -872,6 +872,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) + if (r) { + drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n"); + amdgpu_userq_fence_driver_free(queue); ++ xa_erase_irq(&adev->userq_doorbell_xa, index); + uq_funcs->mqd_destroy(queue); + kfree(queue); + r = -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-userq-unlock-cancel_delayed_work_sync-for.patch b/queue-7.0/drm-amdgpu-userq-unlock-cancel_delayed_work_sync-for.patch new file mode 100644 index 0000000000..aebec15307 --- /dev/null +++ b/queue-7.0/drm-amdgpu-userq-unlock-cancel_delayed_work_sync-for.patch @@ -0,0 +1,83 @@ +From ae27b6c41dfb3ece404429d264ecc32d2eefbf5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:55:32 +0530 +Subject: drm/amdgpu/userq: unlock cancel_delayed_work_sync for + hang_detect_work +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit f802f7b0bc0917023f4b5938246fd7abf23fa5e3 ] + +cancel_delayed_work_sync for work hand_detect_work should not be +locked since the amdgpu_userq_hang_detect_work also need the same +mutex and when they run together it could be a deadlock. + +we do not need to hold the mutex for +cancel_delayed_work_sync(&queue->hang_detect_work). With this in place +if cancel and worker thread run at same time they will not deadlock. + +Due to any failures if there is a hand detect and reset that there a +deadlock scenarios between cancel and running the main thread. + +[ 243.118276] task:kworker/9:0 state:D stack:0 pid:73 tgid:73 ppid:2 task_flags:0x4208060 flags:0x00080000 +[ 243.118283] Workqueue: events amdgpu_userq_hang_detect_work [amdgpu] +[ 243.118636] Call Trace: +[ 243.118639] +[ 243.118644] __schedule+0x581/0x1810 +[ 243.118649] ? srso_return_thunk+0x5/0x5f +[ 243.118656] ? srso_return_thunk+0x5/0x5f +[ 243.118659] ? wake_up_process+0x15/0x20 +[ 243.118665] schedule+0x64/0xe0 +[ 243.118668] schedule_preempt_disabled+0x15/0x30 +[ 243.118671] __mutex_lock+0x346/0x950 +[ 243.118677] __mutex_lock_slowpath+0x13/0x20 +[ 243.118681] mutex_lock+0x2c/0x40 +[ 243.118684] amdgpu_userq_hang_detect_work+0x63/0x90 [amdgpu] +[ 243.118888] process_scheduled_works+0x1f0/0x450 +[ 243.118894] worker_thread+0x27f/0x370 +[ 243.118899] kthread+0x1ed/0x210 +[ 243.118903] ? __pfx_worker_thread+0x10/0x10 +[ 243.118906] ? srso_return_thunk+0x5/0x5f +[ 243.118909] ? __pfx_kthread+0x10/0x10 +[ 243.118913] ret_from_fork+0x10f/0x1b0 +[ 243.118916] ? __pfx_kthread+0x10/0x10 +[ 243.118920] ret_from_fork_asm+0x1a/0x30 + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index a0e816ca471ec..c7e2eb09c9435 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -630,13 +630,14 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que + int r = 0; + + cancel_delayed_work_sync(&uq_mgr->resume_work); ++ ++ /* Cancel any pending hang detection work and cleanup */ ++ cancel_delayed_work_sync(&queue->hang_detect_work); ++ + mutex_lock(&uq_mgr->userq_mutex); ++ queue->hang_detect_fence = NULL; + amdgpu_userq_wait_for_last_fence(queue); +- /* Cancel any pending hang detection work and cleanup */ +- if (queue->hang_detect_fence) { +- cancel_delayed_work_sync(&queue->hang_detect_work); +- queue->hang_detect_fence = NULL; +- } ++ + r = amdgpu_bo_reserve(queue->db_obj.obj, true); + if (!r) { + amdgpu_bo_unpin(queue->db_obj.obj); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch b/queue-7.0/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch new file mode 100644 index 0000000000..6aac4505fa --- /dev/null +++ b/queue-7.0/drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch @@ -0,0 +1,59 @@ +From 1a7ed78330da1c90322ed1e328d6153d4b860b3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 13:12:33 +0800 +Subject: drm/amdgpu: validate fence_count in wait_fences ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jesse.Zhang + +[ Upstream commit 2cef848812a071991c20090cbe051a0a96c50a0c ] + +Add an early parameter check in amdgpu_cs_wait_fences_ioctl() to reject +a zero fence_count with -EINVAL. + +dma_fence_wait_any_timeout() requires count > 0. When userspace passes +fence_count == 0, the call propagates down to dma_fence core which does +not expect a zero-length array and triggers a WARN_ON. + +Return -EINVAL immediately so the caller gets a clear error instead of +hitting an unexpected warning in the DMA fence subsystem. + +No functional change for well-formed userspace callers. + +v2: +- Reworked commit message to clarify the parameter validation rationale +- Removed verbose crash log from commit description +- Simplified inline code comment + +Reviewed-by: Vitaly Prosyak +Reviewed-by: Christian König +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 24e4b4fc91564..142022295fe15 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -1747,6 +1747,13 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_amdgpu_fence *fences; + int r; + ++ /* ++ * fence_count must be non-zero; dma_fence_wait_any_timeout() ++ * does not accept an empty fence array. ++ */ ++ if (!wait->in.fence_count) ++ return -EINVAL; ++ + /* Get the fences from userspace */ + fences = memdup_array_user(u64_to_user_ptr(wait->in.fences), + wait->in.fence_count, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch b/queue-7.0/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch new file mode 100644 index 0000000000..8900b14b3e --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch @@ -0,0 +1,64 @@ +From 3e22458d7268e7a5334ad053defe889863e07006 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:16:16 +0800 +Subject: drm/amdgpu/vcn4.0.3: gate per-queue reset by PSP SOS program version + +From: Jesse Zhang + +[ Upstream commit 16df395a55c635649dd3cf41d61bd685d3fd7a98 ] + +Add a PSP SOS firmware compatibility check before enabling VCN per-queue +reset on vcn_v4_0_3. + +Per review, program check is sufficient: when PSP SOS program is 0x01, +require fw version >= 0x0036015f; otherwise allow per-queue reset. + +Reviewed-by: Lijo Lazar +Suggested-by: Lijo Lazar +Signed-off-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index 210e41cf29374..10e8fc2821f37 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -134,6 +134,21 @@ static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) + return 0; + } + ++static bool vcn_v4_0_3_is_psp_fw_reset_supported(struct amdgpu_device *adev) ++{ ++ uint32_t fw_ver = adev->psp.sos.fw_version; ++ uint32_t pgm = (fw_ver >> 8) & 0xFF; ++ ++ /* ++ * FWDEV-159155: PSP SOS FW must be >= 0x0036015f for program 0x01 ++ * before enabling VCN per-queue reset. ++ */ ++ if (pgm == 1) ++ return fw_ver >= 0x0036015f; ++ ++ return true; ++} ++ + static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; +@@ -141,7 +156,9 @@ static int vcn_v4_0_3_late_init(struct amdgpu_ip_block *ip_block) + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + +- if (amdgpu_dpm_reset_vcn_is_supported(adev) && !amdgpu_sriov_vf(adev)) ++ if (amdgpu_dpm_reset_vcn_is_supported(adev) && ++ vcn_v4_0_3_is_psp_fw_reset_supported(adev) && ++ !amdgpu_sriov_vf(adev)) + adev->vcn.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdkfd-check-if-vm-ready-in-svm-map-and-unmap-to.patch b/queue-7.0/drm-amdkfd-check-if-vm-ready-in-svm-map-and-unmap-to.patch new file mode 100644 index 0000000000..29d4ade59a --- /dev/null +++ b/queue-7.0/drm-amdkfd-check-if-vm-ready-in-svm-map-and-unmap-to.patch @@ -0,0 +1,55 @@ +From e6ff6ca86e55b964ad4114dcb774e00e42051138 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 18:27:30 +0800 +Subject: drm/amdkfd: check if vm ready in svm map and unmap to gpu + +From: YuanShang + +[ Upstream commit d0f5711fa14a09c010537375cf34893cd33bc2ee ] + +Don't map or unmap svm range to gpu if vm is not ready for updates. + +Why: DRM entity may already be killed when the svm worker try to +update gpu vm. + +Signed-off-by: YuanShang +Reviewed-by: Philip Yang +Signed-off-by: Alex Deucher +(cherry picked from commit 55f8e366c326980174a4f2b9501b524d8eb25135) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +index 3d2c603f20858..27445f5d6dd6d 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +@@ -1363,6 +1363,12 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, + + pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, + gpu_start, gpu_end); ++ ++ if (!amdgpu_vm_ready(vm)) { ++ pr_debug("VM not ready, canceling unmap\n"); ++ return -EINVAL; ++ } ++ + return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, + gpu_end, init_pte_value, 0, 0, NULL, NULL, + fence); +@@ -1440,6 +1446,11 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, + pr_debug("svms 0x%p [0x%lx 0x%lx] readonly %d\n", prange->svms, + last_start, last_start + npages - 1, readonly); + ++ if (!amdgpu_vm_ready(vm)) { ++ pr_debug("VM not ready, canceling map\n"); ++ return -EINVAL; ++ } ++ + for (i = offset; i < offset + npages; i++) { + uint64_t gpu_start; + uint64_t gpu_end; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdkfd-fix-kernel-crash-on-releasing-null-sysfs-.patch b/queue-7.0/drm-amdkfd-fix-kernel-crash-on-releasing-null-sysfs-.patch new file mode 100644 index 0000000000..3a113f4cf0 --- /dev/null +++ b/queue-7.0/drm-amdkfd-fix-kernel-crash-on-releasing-null-sysfs-.patch @@ -0,0 +1,48 @@ +From b97e89aebb86843e4a551d37306ff390c6e958bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 09:46:42 -0400 +Subject: drm/amdkfd: fix kernel crash on releasing NULL sysfs entry + +From: Eric Huang + +[ Upstream commit 4ea64d482fc2cc85009fce5abdf4780ece00c31c ] + +there is an abnormal case that When a process re-opens kfd +with different mm_struct(execve() called by user), the +allocated p->kobj will be freed, but missed setting it to NULL, +that will cause sysfs/kernel crash with NULL pointers in p->kobj +on kfd_process_remove_sysfs() when releasing process, and the +similar error on kfd_procfs_del_queue() as well. + +Signed-off-by: Eric Huang +Reviewed-by: Kent Russell +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index 12e24fbf8c463..c6782904d2f1c 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -679,7 +679,7 @@ static void kfd_procfs_add_sysfs_files(struct kfd_process *p) + + void kfd_procfs_del_queue(struct queue *q) + { +- if (!q) ++ if (!q || !q->process->kobj) + return; + + kobject_del(&q->kobj); +@@ -858,6 +858,7 @@ int kfd_create_process_sysfs(struct kfd_process *process) + if (ret) { + pr_warn("Creating procfs pid directory failed"); + kobject_put(process->kobj); ++ process->kobj = NULL; + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch b/queue-7.0/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch new file mode 100644 index 0000000000..2cd82920f8 --- /dev/null +++ b/queue-7.0/drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch @@ -0,0 +1,68 @@ +From af4d95682e5c02b357e0e1933e4ab5f9218b5ecf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 13:57:53 +0100 +Subject: drm/bridge: waveshare-dsi: Register and attach our DSI device at + probe + +From: Marek Vasut + +[ Upstream commit b8eb97ead862de7a321dd55a901542a372f8f1cd ] + +In order to avoid any probe ordering issue, the best practice is to move +the secondary MIPI-DSI device registration and attachment to the +MIPI-DSI host at probe time. + +Besides solving the probe ordering problems, this makes the bridge work +with R-Car DU. The R-Car DU will attempt to locate the DSI host bridge in +its own rcar_du_probe()->rcar_du_modeset_init()->rcar_du_encoder_init() +by calling of_drm_find_bridge() which calls of_drm_find_and_get_bridge() +and iterates over bridge_list to locate the DSI host bridge. + +However, unless the WS driver calls mipi_dsi_attach() in probe(), the +DSI host bridge .attach callback rcar_mipi_dsi_host_attach() is not +called and the DSI host bridge is not added into bridge_list. Therefore +the of_drm_find_and_get_bridge() called from du_probe() will never find +the DSI host bridge and probe will indefinitelly fail with -EPROBE_DEFER. + +The circular dependency here is, that if rcar_du_encoder_init() would +manage to find the DSI host bridge, it would call the WS driver .attach +callback ws_bridge_bridge_attach(), but this is too late and can never +happen. This change avoids the circular dependency. + +Reviewed-by: Luca Ceresoli +Signed-off-by: Marek Vasut +Link: https://patch.msgid.link/20260206125801.78705-1-marek.vasut+renesas@mailbox.org +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/waveshare-dsi.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c +index 43f4e7412d722..9254446f54958 100644 +--- a/drivers/gpu/drm/bridge/waveshare-dsi.c ++++ b/drivers/gpu/drm/bridge/waveshare-dsi.c +@@ -80,11 +80,6 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) + { + struct ws_bridge *ws = bridge_to_ws_bridge(bridge); +- int ret; +- +- ret = ws_bridge_attach_dsi(ws); +- if (ret) +- return ret; + + return drm_bridge_attach(encoder, ws->next_bridge, + &ws->bridge, flags); +@@ -179,7 +174,7 @@ static int ws_bridge_probe(struct i2c_client *i2c) + ws->bridge.of_node = dev->of_node; + devm_drm_bridge_add(dev, &ws->bridge); + +- return 0; ++ return ws_bridge_attach_dsi(ws); + } + + static const struct of_device_id ws_bridge_of_ids[] = { +-- +2.53.0 + diff --git a/queue-7.0/drm-gem-dma-set-vm_dontdump-for-mmap.patch b/queue-7.0/drm-gem-dma-set-vm_dontdump-for-mmap.patch new file mode 100644 index 0000000000..2630f85784 --- /dev/null +++ b/queue-7.0/drm-gem-dma-set-vm_dontdump-for-mmap.patch @@ -0,0 +1,49 @@ +From 6123e58d38714843b55b161b29c31dcf5133a4d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 12:00:32 +0800 +Subject: drm/gem-dma: set VM_DONTDUMP for mmap + +From: Chen-Yu Tsai + +[ Upstream commit e3eb0e70815cc02ea15298818e37d8b0a0930ab1 ] + +When the mmap function was converted from a file op to a GEM object +function in commit f5ca8eb6f9bd ("drm/cma-helper: Implement mmap as GEM +CMA object functions") some VM flags were not lifted from drm_gem_mmap(): + + - VM_IO + - VM_DONTEXPAND + - VM_DONTDUMP + +VM_DONTEXPAND was added back in commit 59f39bfa6553 ("drm/cma-helper: +Set VM_DONTEXPAND for mmap"). VM_IO doesn't make sense since these are +memory buffers, while "IO tells people not to look at these pages +(accesses can have side effects)". + +Add back VM_DONTDUMP. This matches the behavior of most other GEM +implementations. + +Reviewed-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260317040034.617585-1-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gem_dma_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c +index ecb9746f4da86..1911bf6a6a3ed 100644 +--- a/drivers/gpu/drm/drm_gem_dma_helper.c ++++ b/drivers/gpu/drm/drm_gem_dma_helper.c +@@ -534,7 +534,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct * + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); +- vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); ++ vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP); + + if (dma_obj->map_noncoherent) { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); +-- +2.53.0 + diff --git a/queue-7.0/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch b/queue-7.0/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch new file mode 100644 index 0000000000..64e1da07d6 --- /dev/null +++ b/queue-7.0/drm-gpu-msm-forbid-mem-reclaim-from-reset.patch @@ -0,0 +1,150 @@ +From 8fb4534ac88c8c3ef3fcab0a28e3a85ee6a70b07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 16:33:34 +0900 +Subject: drm: gpu: msm: forbid mem reclaim from reset + +From: Sergey Senozhatsky + +[ Upstream commit 4625fe5bbdaccd45be274c30ff0a42e30d4e38cf ] + +We sometimes get into a situtation where GPU hangcheck fails to +recover GPU: + +[..] +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): hangcheck detected gpu lockup rb 0! +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): completed fence: 7840161 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): submitted fence: 7840162 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): hangcheck detected gpu lockup rb 0! +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): completed fence: 7840162 +msm_dpu ae01000.display-controller: [drm:hangcheck_handler] *ERROR* (IPv4: 1): submitted fence: 7840163 +[..] + +The problem is that msm_job worker is blocked on gpu->lock + +INFO: task ring0:155 blocked for more than 122 seconds. +Not tainted 6.6.99-08727-gaac38b365d2c #1 +task:ring0 state:D stack:0 pid:155 ppid:2 flags:0x00000008 +Call trace: +__switch_to+0x108/0x208 +schedule+0x544/0x11f0 +schedule_preempt_disabled+0x30/0x50 +__mutex_lock_common+0x410/0x850 +__mutex_lock_slowpath+0x28/0x40 +mutex_lock+0x5c/0x90 +msm_job_run+0x9c/0x140 +drm_sched_main+0x514/0x938 +kthread+0x114/0x138 +ret_from_fork+0x10/0x20 + +which is owned by recover worker, which is waiting for DMA fences +from a memory reclaim path, under the very same gpu->lock + +INFO: task ring0:155 is blocked on a mutex likely owned by task gpu-worker:154. +task:gpu-worker state:D stack:0 pid:154 ppid:2 flags:0x00000008 +Call trace: +__switch_to+0x108/0x208 +schedule+0x544/0x11f0 +schedule_timeout+0x1f8/0x770 +dma_fence_default_wait+0x108/0x218 +dma_fence_wait_timeout+0x6c/0x1c0 +dma_resv_wait_timeout+0xe4/0x118 +active_purge+0x34/0x98 +drm_gem_lru_scan+0x1d0/0x388 +msm_gem_shrinker_scan+0x1cc/0x2e8 +shrink_slab+0x228/0x478 +shrink_node+0x380/0x730 +try_to_free_pages+0x204/0x510 +__alloc_pages_direct_reclaim+0x90/0x158 +__alloc_pages_slowpath+0x1d4/0x4a0 +__alloc_pages+0x9f0/0xc88 +vm_area_alloc_pages+0x17c/0x260 +__vmalloc_node_range+0x1c0/0x420 +kvmalloc_node+0xe8/0x108 +msm_gpu_crashstate_capture+0x1e4/0x280 +recover_worker+0x1c0/0x638 +kthread_worker_fn+0x150/0x2d8 +kthread+0x114/0x138 + +So no one can make any further progress. + +Forbid recover/fault worker to enter memory reclaim (under +gpu->lock) to address this deadlock scenario. + +Cc: Tomasz Figa +Signed-off-by: Sergey Senozhatsky +Reviewed-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/700978/ +Message-ID: <20260127073341.2862078-1-senozhatsky@chromium.org> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gpu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c +index d178bb9b813ae..930e54d1b0a7d 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + /* + * Power Management: +@@ -468,6 +469,7 @@ static void recover_worker(struct kthread_work *work) + struct msm_gem_submit *submit; + struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); + char *comm = NULL, *cmd = NULL; ++ unsigned int noreclaim_flag; + struct task_struct *task; + int i; + +@@ -505,6 +507,8 @@ static void recover_worker(struct kthread_work *work) + msm_gem_vm_unusable(submit->vm); + } + ++ noreclaim_flag = memalloc_noreclaim_save(); ++ + get_comm_cmdline(submit, &comm, &cmd); + + if (comm && cmd) { +@@ -523,6 +527,8 @@ static void recover_worker(struct kthread_work *work) + pm_runtime_get_sync(&gpu->pdev->dev); + msm_gpu_crashstate_capture(gpu, submit, NULL, comm, cmd); + ++ memalloc_noreclaim_restore(noreclaim_flag); ++ + kfree(cmd); + kfree(comm); + +@@ -585,6 +591,7 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + struct msm_gem_submit *submit; + struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); + char *comm = NULL, *cmd = NULL; ++ unsigned int noreclaim_flag; + + mutex_lock(&gpu->lock); + +@@ -592,6 +599,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + if (submit && submit->fault_dumped) + goto resume_smmu; + ++ noreclaim_flag = memalloc_noreclaim_save(); ++ + if (submit) { + get_comm_cmdline(submit, &comm, &cmd); + +@@ -607,6 +616,8 @@ void msm_gpu_fault_crashstate_capture(struct msm_gpu *gpu, struct msm_gpu_fault_ + msm_gpu_crashstate_capture(gpu, submit, fault_info, comm, cmd); + pm_runtime_put_sync(&gpu->pdev->dev); + ++ memalloc_noreclaim_restore(noreclaim_flag); ++ + kfree(cmd); + kfree(comm); + +-- +2.53.0 + diff --git a/queue-7.0/drm-imx-parallel-display-add-drm_display_helper-for-.patch b/queue-7.0/drm-imx-parallel-display-add-drm_display_helper-for-.patch new file mode 100644 index 0000000000..4e35b09b1f --- /dev/null +++ b/queue-7.0/drm-imx-parallel-display-add-drm_display_helper-for-.patch @@ -0,0 +1,45 @@ +From 9dae661733e9f0f1763128511d9c07d0d35da9a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 11:26:07 +0100 +Subject: drm/imx: parallel-display: add DRM_DISPLAY_HELPER for + DRM_IMX_PARALLEL_DISPLAY + +From: Martin Kepplinger-Novakovic + +[ Upstream commit 02df94d98ff837074788ce921edf67707dbad404 ] + +When I build for an old imx53 platform I see the same as the test robot +saw before: + +arm-buildroot-linux-gnueabihf-ld: drivers/gpu/drm/imx/ipuv3/parallel-display.o: in function `imx_pd_bind': +parallel-display.c:(.text+0xb8): undefined reference to `drm_bridge_connector_init' + +Selecting DRM_DISPLAY_HELPER for DRM_IMX_PARALLEL_DISPLAY fixes the build. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202512241721.jZgcwRfr-lkp@intel.com/ + +Signed-off-by: Martin Kepplinger-Novakovic +Reviewed-by: Philipp Zabel +Signed-off-by: Philipp Zabel +Link: https://patch.msgid.link/20260121102607.4087362-1-martin.kepplinger-novakovic@ginzinger.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/ipuv3/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig +index acaf250890019..b2240998df4f1 100644 +--- a/drivers/gpu/drm/imx/ipuv3/Kconfig ++++ b/drivers/gpu/drm/imx/ipuv3/Kconfig +@@ -15,6 +15,7 @@ config DRM_IMX_PARALLEL_DISPLAY + depends on DRM_IMX + select DRM_BRIDGE + select DRM_BRIDGE_CONNECTOR ++ select DRM_DISPLAY_HELPER + select DRM_IMX_LEGACY_BRIDGE + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS +-- +2.53.0 + diff --git a/queue-7.0/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch b/queue-7.0/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch new file mode 100644 index 0000000000..ccd255cad0 --- /dev/null +++ b/queue-7.0/drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch @@ -0,0 +1,100 @@ +From d1fa899fb5905ec22cd4ea204011b84ea4d9ee06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:36:59 +0100 +Subject: drm/mediatek: mtk_dsi: enable hs clock during pre-enable + +From: Gary Bisson + +[ Upstream commit 76255024cadbe8c40462953f8193d2d78cd3b0ac ] + +Some bridges, such as the TI SN65DSI83, require the HS clock to be +running in order to lock its PLL during its own pre-enable function. + +Without this change, the bridge gives the following error: +sn65dsi83 14-002c: failed to lock PLL, ret=-110 +sn65dsi83 14-002c: Unexpected link status 0x01 +sn65dsi83 14-002c: reset the pipe + +Move the necessary functions from enable to pre-enable. + +Signed-off-by: Gary Bisson +Reviewed-by: CK Hu +Tested-by: Chen-Yu Tsai # Chromebooks +Tested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patchwork.kernel.org/project/dri-devel/patch/20260120-mtkdsi-v1-1-b0f4094f3ac3@gmail.com/ +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 35 +++++++++++++++--------------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index aaf6c9ebd319f..5aa71fcdcfab7 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -673,6 +673,21 @@ static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) + } + } + ++static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) ++{ ++ if (!dsi->lanes_ready) { ++ dsi->lanes_ready = true; ++ mtk_dsi_rxtx_control(dsi); ++ usleep_range(30, 100); ++ mtk_dsi_reset_dphy(dsi); ++ mtk_dsi_clk_ulp_mode_leave(dsi); ++ mtk_dsi_lane0_ulp_mode_leave(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 0); ++ usleep_range(1000, 3000); ++ /* The reaction time after pulling up the mipi signal for dsi_rx */ ++ } ++} ++ + static int mtk_dsi_poweron(struct mtk_dsi *dsi) + { + struct device *dev = dsi->host.dev; +@@ -725,6 +740,8 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) + mtk_dsi_set_vm_cmd(dsi); + mtk_dsi_config_vdo_timing(dsi); + mtk_dsi_set_interrupt_enable(dsi); ++ mtk_dsi_lane_ready(dsi); ++ mtk_dsi_clk_hs_mode(dsi, 1); + + return 0; + err_disable_engine_clk: +@@ -770,30 +787,12 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) + dsi->lanes_ready = false; + } + +-static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +-{ +- if (!dsi->lanes_ready) { +- dsi->lanes_ready = true; +- mtk_dsi_rxtx_control(dsi); +- usleep_range(30, 100); +- mtk_dsi_reset_dphy(dsi); +- mtk_dsi_clk_ulp_mode_leave(dsi); +- mtk_dsi_lane0_ulp_mode_leave(dsi); +- mtk_dsi_clk_hs_mode(dsi, 0); +- usleep_range(1000, 3000); +- /* The reaction time after pulling up the mipi signal for dsi_rx */ +- } +-} +- + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) + { + if (dsi->enabled) + return; + +- mtk_dsi_lane_ready(dsi); + mtk_dsi_set_mode(dsi); +- mtk_dsi_clk_hs_mode(dsi, 1); +- + mtk_dsi_start(dsi); + + dsi->enabled = true; +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch b/queue-7.0/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch new file mode 100644 index 0000000000..5b0947c3e4 --- /dev/null +++ b/queue-7.0/drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch @@ -0,0 +1,60 @@ +From 1e12746c19bebf0c519b34d350fcd9bf089f5911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:17:00 +0100 +Subject: drm/msm/dpu: fix vblank IRQ registration before atomic_mode_set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cédric Bellegarde + +[ Upstream commit 961c900628fef77ad07b4bc4c868e47b9a1269c7 ] + +dpu_encoder_toggle_vblank_for_crtc() can call control_vblank_irq() +at any time in response to a userspace vblank request, independently +of the atomic commit sequence. If this happens before the encoder's +first atomic_mode_set(), irq[INTR_IDX_RDPTR] is still zero. + +Passing irq_idx=0 to dpu_core_irq_register_callback() is treated as +invalid, and DPU_IRQ_REG(0) and DPU_IRQ_BIT(0) produce misleading +values of 134217727 and 31 respectively due to unsigned wraparound +in the (irq_idx - 1) macros, resulting in the confusing error: + + [dpu error]invalid IRQ=[134217727, 31] + +Since irq[INTR_IDX_RDPTR] will be properly populated by +atomic_mode_set() and registered by irq_enable() as part of the +normal modeset sequence, silently skip the vblank IRQ registration +when the index has not yet been initialized. This matches the +existing pattern of the master encoder check above it. + +Signed-off-by: Cédric Bellegarde +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/712752/ +Link: https://lore.kernel.org/r/20260318171700.394945-1-cedric.bellegarde@adishatz.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index 93db1484f6069..45079ee59cf67 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -257,6 +257,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + ++ /* IRQ not yet initialized */ ++ if (!phys_enc->irq[INTR_IDX_RDPTR]) { ++ ret = -EINVAL; ++ goto end; ++ } ++ + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch b/queue-7.0/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch new file mode 100644 index 0000000000..2d991500d2 --- /dev/null +++ b/queue-7.0/drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch @@ -0,0 +1,46 @@ +From 76af5c9502700320c427c1472b6048d22247e2be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 11:29:04 +0800 +Subject: drm/panel-edp: Add AUO B116XAT04.1 (HW: 1A) + +From: Terry Hsiao + +[ Upstream commit 2cb217301e0df17f7107a1b0941b28d4053eae8b ] + +Add support for the AUO - B116XAT04.1 (HW: 1A) panel. +This panel is used on MT8186 Chromebooks + +The raw EDID: +00 ff ff ff ff ff ff 00 06 af ba 89 00 00 00 00 +0c 23 01 04 95 1a 0e 78 02 9e a5 96 59 58 96 28 +1b 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 ce 1d 56 ea 50 00 1a 30 30 20 +46 00 00 90 10 00 00 18 df 13 56 ea 50 00 1a 30 +30 20 46 00 00 90 10 00 00 18 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 +00 10 48 ff 0f 3c 7d 0c 0a 2a 7d 20 20 20 00 21 + +Signed-off-by: Terry Hsiao +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260122032904.3933-1-terry_hsiao@compal.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 679f4af5246d8..108569490ed59 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1915,6 +1915,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), ++ EDP_PANEL_ENTRY('A', 'U', 'O', 0x89ba, &delay_200_500_e50, "B116XAT04.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8bba, &delay_200_500_e50, "B140UAN08.5"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xa199, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"), +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-edp-add-boe-nv153wum-n42-cmn-n153jca-elk-c.patch b/queue-7.0/drm-panel-edp-add-boe-nv153wum-n42-cmn-n153jca-elk-c.patch new file mode 100644 index 0000000000..42520bb027 --- /dev/null +++ b/queue-7.0/drm-panel-edp-add-boe-nv153wum-n42-cmn-n153jca-elk-c.patch @@ -0,0 +1,108 @@ +From 8023265598fe554f77f0cedb0ca70b05f3234b54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:09:38 +0800 +Subject: drm/panel-edp: Add BOE NV153WUM-N42, CMN N153JCA-ELK, CSW MNF307QS3-2 + +From: Alvin1 Chen + +[ Upstream commit d51f217957ca1fa3a151000e86a192231284595b ] + +The raw EDIDs for each panel: + +BOE: NV153WUM-N42 +00 ff ff ff ff ff ff 00 09 e5 b3 0d 00 00 00 00 +11 23 01 04 a5 21 15 78 03 af e5 97 5e 58 92 28 +1f 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 9c 3e 80 c8 70 b0 3c 40 30 20 +36 00 49 ce 10 00 00 1a 00 00 00 fd 00 28 3c 4c +4c 10 01 0a 20 20 20 20 20 20 00 00 00 fe 00 42 +4f 45 20 43 51 0a 20 20 20 20 20 20 00 00 00 fc +00 4e 56 31 35 33 57 55 4d 2d 4e 34 32 0a 01 92 + +70 20 79 02 00 81 00 15 74 1a 00 00 03 01 28 3c +00 00 60 49 60 49 3c 00 00 00 00 80 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 cb 90 + +CMN: N153JCA-ELK +00 ff ff ff ff ff ff 00 0d ae 6b 15 00 00 00 00 +16 23 01 04 a5 21 15 78 03 08 82 93 59 53 8e 27 +1e 4f 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 42 3c 80 a0 70 b0 24 40 30 20 +a6 00 49 cd 10 00 00 1a 00 00 00 fd 00 28 3c 4a +4a 10 01 0a 20 20 20 20 20 20 00 00 00 fe 00 43 +4d 4e 0a 20 20 20 20 20 20 20 20 20 00 00 00 fc +00 4e 31 35 33 4a 43 41 2d 45 4c 4b 0a 20 01 d5 + +70 20 79 02 00 25 01 09 94 5a 02 94 5a 02 28 3c +80 81 00 13 72 1a 00 00 03 01 28 3c 00 00 00 00 +00 00 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 ae 90 + +CSW: MNF307QS3-2 +00 ff ff ff ff ff ff 00 0e 77 29 15 00 00 00 00 +13 23 01 04 a5 21 15 78 03 9c 81 96 5d 5a 94 28 +1e 51 56 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 1a 3f 80 04 71 b0 23 40 30 20 +36 00 49 cd 10 00 00 18 00 00 00 fd 00 28 3c 4a +4a 10 01 0a 20 20 20 20 20 20 00 00 00 fe 00 43 +4f 53 54 20 54 39 0a 20 20 20 20 20 00 00 00 fc +00 4d 4e 46 33 30 37 51 53 33 2d 32 0a 20 01 5c + +70 20 79 02 00 81 00 15 74 1a 00 00 03 01 28 3c +00 00 60 46 60 46 3c 00 00 00 00 8d 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 c4 90 + +Signed-off-by: Alvin1 Chen +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260319050938.556235-1-alvin1.chen@lcfc.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 260fa18b0f78a..c073ea87008de 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1999,6 +1999,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d45, &delay_200_500_e80, "NV116WHM-N4B"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"), ++ EDP_PANEL_ENTRY('B', 'O', 'E', 0x0db3, &delay_200_500_e80, "NV153WUM-N42"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ddf, &delay_200_500_e80, "NV116WHM-T01"), + + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), +@@ -2035,6 +2036,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1565, &delay_200_500_e80, "N156HCA-EAB"), ++ EDP_PANEL_ENTRY('C', 'M', 'N', 0x156b, &delay_200_500_e80_d50, "N153JCA-ELK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x162b, &delay_200_500_e80_d50, "N160JCE-ELL"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x7402, &delay_200_500_e200_d50, "N116BCA-EAK"), + +@@ -2053,6 +2055,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x147c, &delay_200_500_e50_d100, "MNE007QB3-1"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1519, &delay_200_500_e80_d50, "MNF601BS1-3"), ++ EDP_PANEL_ENTRY('C', 'S', 'W', 0x1529, &delay_200_500_e80_d50, "MNF307QS3-2"), + + EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), + +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch b/queue-7.0/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch new file mode 100644 index 0000000000..0d74451b39 --- /dev/null +++ b/queue-7.0/drm-panel-edp-add-cmn-n116bcl-eak-c2.patch @@ -0,0 +1,56 @@ +From 3731850e8d0fa1152436081af4a0557dc443ece4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 11:04:56 +0800 +Subject: drm/panel-edp: Add CMN N116BCL-EAK (C2) + +From: Cong Yang + +[ Upstream commit 3d65e4c276b32c03450261d114e495fda03c8e97 ] + +Add support for the CMN N116BCL-EAK (C2) panel, pleace the EDID here for +subsequent reference. + +edid-decode (hex): + +00 ff ff ff ff ff ff 00 0d ae 7a 11 00 00 00 00 +08 22 01 04 95 1a 0e 78 03 46 a5 9c 5b 53 8b 24 +1d 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01 +01 01 01 01 01 01 e6 1e 56 e2 50 00 3c 30 30 20 +a6 00 00 90 10 00 00 1a 00 00 00 fd 00 28 3c 32 +32 08 01 0a 20 20 20 20 20 20 00 00 00 fe 00 43 +4d 4e 0a 20 20 20 20 20 20 20 20 20 00 00 00 fe +00 4e 31 31 36 42 43 4c 2d 45 41 4b 0a 20 01 80 + +70 20 79 02 00 25 01 09 fc 34 01 fc 34 01 28 3c +80 81 00 10 72 1a 00 00 03 01 28 3c 00 00 00 00 +00 00 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 90 + +Signed-off-by: Cong Yang +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260130030456.2080748-1-yangcong5@huaqin.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 108569490ed59..c9eacfffd5b29 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -2014,6 +2014,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), ++ EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x124c, &delay_200_500_e80_d50, "N122JCA-ENK"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-edp-change-boe-nv140wum-n64-timings.patch b/queue-7.0/drm-panel-edp-change-boe-nv140wum-n64-timings.patch new file mode 100644 index 0000000000..20ce7f058e --- /dev/null +++ b/queue-7.0/drm-panel-edp-change-boe-nv140wum-n64-timings.patch @@ -0,0 +1,52 @@ +From 6d9fce89ccd0fa1f5ae36cb0535f92fa585eda44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:32:35 +0800 +Subject: drm/panel-edp: Change BOE NV140WUM-N64 timings + +From: Haikun Zhou + +[ Upstream commit bbe814bcb961ed2f30706ffdc806f18150709d2d ] + +This screen timing requires a backlight off time of more than 100ms +from the end of the data stream to avoid screen flickering and red +light caused by screen material limitations. + +Signed-off-by: Haikun Zhou +Reviewed-by: Douglas Anderson +Signed-off-by: Douglas Anderson +Link: https://patch.msgid.link/20260226083235.2176689-1-zhouhaikun5@huaqin.corp-partner.google.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-edp.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index c9eacfffd5b29..260fa18b0f78a 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -1788,6 +1788,13 @@ static const struct panel_delay delay_200_500_e200 = { + .enable = 200, + }; + ++static const struct panel_delay delay_200_500_e200_d100 = { ++ .hpd_absent = 200, ++ .unprepare = 500, ++ .enable = 200, ++ .disable = 100, ++}; ++ + static const struct panel_delay delay_200_500_e200_d200 = { + .hpd_absent = 200, + .unprepare = 500, +@@ -1988,7 +1995,7 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf2, &delay_200_500_e200, "NV156FHM-N4S"), +- EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf6, &delay_200_500_e200, "NV140WUM-N64"), ++ EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf6, &delay_200_500_e200_d100, "NV140WUM-N64"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d45, &delay_200_500_e80, "NV116WHM-N4B"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"), +-- +2.53.0 + diff --git a/queue-7.0/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch b/queue-7.0/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch new file mode 100644 index 0000000000..f20d8dd27f --- /dev/null +++ b/queue-7.0/drm-prime-limit-scatter-list-size-with-dedicated-dma.patch @@ -0,0 +1,44 @@ +From 047db66c2e2d54084c00b44a98d4951d35f56ea5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:49:25 +0800 +Subject: drm/prime: Limit scatter list size with dedicated DMA device + +From: Chen-Yu Tsai + +[ Upstream commit 864279920b2b2c1dd491eba0d0c64764c0c03d9f ] + +If a dedicated DMA device is specified for the DRM device, then the +scatter list size limit should pertain to the DMA device. + +Use the dedicated DMA device, if given, to limit the scatter list size. +This only applies to drivers that have called drm_dev_set_dma_dev() and +are using drm_prime_pages_to_sg() either directly or through the SHMEM +helpers. At the time of this writing, the former case only includes the +Rockchip DRM driver, while the latter case includes the gud, udl, and +the tiny appletbdrm and gm12u320 drivers. + +Reviewed-by: Thomas Zimmermann +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260311094929.3393338-2-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_prime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 51fdb06d3e9f2..9b44c78cd77fc 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -859,7 +859,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, + return ERR_PTR(-ENOMEM); + + if (dev) +- max_segment = dma_max_mapping_size(dev->dev); ++ max_segment = dma_max_mapping_size(drm_dev_dma_dev(dev)); + if (max_segment == 0) + max_segment = UINT_MAX; + err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, +-- +2.53.0 + diff --git a/queue-7.0/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch b/queue-7.0/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch new file mode 100644 index 0000000000..458ba7215a --- /dev/null +++ b/queue-7.0/drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch @@ -0,0 +1,98 @@ +From 96500f99d0de21c6bbac5f219aec00740a094f51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:18:55 +0100 +Subject: drm/ttm: Avoid invoking the OOM killer when reading back swapped + content +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +[ Upstream commit c6135f67aa37a4a744869f726d706bda091e6dfa ] + +In situations where the system is very short on RAM, the shmem +readback from swap-space may invoke the OOM killer. + +However, since this might be a recoverable situation where the caller +is indicating this by setting +struct ttm_operation_ctx::gfp_retry_mayfail to true, adjust the gfp +value used by the allocation accordingly. + +Signed-off-by: Thomas Hellström +Reviewed-by: Maarten Lankhorst +Acked-by: Christian König +Link: https://patch.msgid.link/20260317141856.237876-3-thomas.hellstrom@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/ttm/ttm_backup.c | 6 ++++-- + drivers/gpu/drm/ttm/ttm_pool.c | 5 ++++- + include/drm/ttm/ttm_backup.h | 2 +- + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c +index 6bd4c123d94cd..81df4cb5606b4 100644 +--- a/drivers/gpu/drm/ttm/ttm_backup.c ++++ b/drivers/gpu/drm/ttm/ttm_backup.c +@@ -44,18 +44,20 @@ void ttm_backup_drop(struct file *backup, pgoff_t handle) + * @dst: The struct page to copy into. + * @handle: The handle returned when the page was backed up. + * @intr: Try to perform waits interruptible or at least killable. ++ * @additional_gfp: GFP mask to add to the default GFP mask if any. + * + * Return: 0 on success, Negative error code on failure, notably + * -EINTR if @intr was set to true and a signal is pending. + */ + int ttm_backup_copy_page(struct file *backup, struct page *dst, +- pgoff_t handle, bool intr) ++ pgoff_t handle, bool intr, gfp_t additional_gfp) + { + struct address_space *mapping = backup->f_mapping; + struct folio *from_folio; + pgoff_t idx = ttm_backup_handle_to_shmem_idx(handle); + +- from_folio = shmem_read_folio(mapping, idx); ++ from_folio = shmem_read_folio_gfp(mapping, idx, mapping_gfp_mask(mapping) ++ | additional_gfp); + if (IS_ERR(from_folio)) + return PTR_ERR(from_folio); + +diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c +index c0d95559197c6..4912ab53f6f92 100644 +--- a/drivers/gpu/drm/ttm/ttm_pool.c ++++ b/drivers/gpu/drm/ttm/ttm_pool.c +@@ -530,6 +530,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, + p = first_page[i]; + if (ttm_backup_page_ptr_is_handle(p)) { + unsigned long handle = ttm_backup_page_ptr_to_handle(p); ++ gfp_t additional_gfp = ctx->gfp_retry_mayfail ? ++ __GFP_RETRY_MAYFAIL | __GFP_NOWARN : 0; + + if (IS_ENABLED(CONFIG_FAULT_INJECTION) && ctx->interruptible && + should_fail(&backup_fault_inject, 1)) { +@@ -543,7 +545,8 @@ static int ttm_pool_restore_commit(struct ttm_pool_tt_restore *restore, + } + + ret = ttm_backup_copy_page(backup, restore->alloced_page + i, +- handle, ctx->interruptible); ++ handle, ctx->interruptible, ++ additional_gfp); + if (ret) + break; + +diff --git a/include/drm/ttm/ttm_backup.h b/include/drm/ttm/ttm_backup.h +index c33cba111171f..29b9c855af779 100644 +--- a/include/drm/ttm/ttm_backup.h ++++ b/include/drm/ttm/ttm_backup.h +@@ -56,7 +56,7 @@ ttm_backup_page_ptr_to_handle(const struct page *page) + void ttm_backup_drop(struct file *backup, pgoff_t handle); + + int ttm_backup_copy_page(struct file *backup, struct page *dst, +- pgoff_t handle, bool intr); ++ pgoff_t handle, bool intr, gfp_t additional_gfp); + + s64 + ttm_backup_backup_page(struct file *backup, struct page *page, +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch b/queue-7.0/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch new file mode 100644 index 0000000000..f9823f9231 --- /dev/null +++ b/queue-7.0/drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch @@ -0,0 +1,135 @@ +From 488f3cc36e54c709b6967042ad379df1f6e56560 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:23:15 +0530 +Subject: drm/xe/guc: Add Wa_14025883347 for GuC DMA failure on reset + +From: Sk Anirban + +[ Upstream commit c57db41b8d2cd410e7219729f446aa17965485ad ] + +Prevent GuC firmware DMA failures during GuC-only reset by disabling +idle flow and verifying SRAM handling completion. Without this, reset +can be issued while SRAM handler is copying WOPCM to SRAM, +causing GuC HW to get stuck. + +v2: Modify error message (Badal) + Rename reg bit name (Daniele) + Update WA skip condition (Daniele) + Update SRAM handling logic (Daniele) +v3: Reorder WA call (Badal) + Wait for GuC ready status (Daniele) +v4: Update reg name (Badal) + Add comment (Daniele) + Add extended graphics version (Daniele) + Modify rules + +Signed-off-by: Sk Anirban +Reviewed-by: Badal Nilawar +Acked-by: Matt Roper +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260202105313.3338094-4-sk.anirban@intel.com +Signed-off-by: Matt Roper +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/regs/xe_guc_regs.h | 8 ++++++ + drivers/gpu/drm/xe/xe_guc.c | 38 +++++++++++++++++++++++++++ + drivers/gpu/drm/xe/xe_wa_oob.rules | 3 +++ + 3 files changed, 49 insertions(+) + +diff --git a/drivers/gpu/drm/xe/regs/xe_guc_regs.h b/drivers/gpu/drm/xe/regs/xe_guc_regs.h +index 87984713dd126..5faac8316b66c 100644 +--- a/drivers/gpu/drm/xe/regs/xe_guc_regs.h ++++ b/drivers/gpu/drm/xe/regs/xe_guc_regs.h +@@ -40,6 +40,9 @@ + #define GS_BOOTROM_JUMP_PASSED REG_FIELD_PREP(GS_BOOTROM_MASK, 0x76) + #define GS_MIA_IN_RESET REG_BIT(0) + ++#define BOOT_HASH_CHK XE_REG(0xc010) ++#define GUC_BOOT_UKERNEL_VALID REG_BIT(31) ++ + #define GUC_HEADER_INFO XE_REG(0xc014) + + #define GUC_WOPCM_SIZE XE_REG(0xc050) +@@ -83,7 +86,12 @@ + #define GUC_WOPCM_OFFSET_MASK REG_GENMASK(31, GUC_WOPCM_OFFSET_SHIFT) + #define HUC_LOADING_AGENT_GUC REG_BIT(1) + #define GUC_WOPCM_OFFSET_VALID REG_BIT(0) ++ ++#define GUC_SRAM_STATUS XE_REG(0xc398) ++#define GUC_SRAM_HANDLING_MASK REG_GENMASK(8, 7) ++ + #define GUC_MAX_IDLE_COUNT XE_REG(0xc3e4) ++#define GUC_IDLE_FLOW_DISABLE REG_BIT(31) + #define GUC_PMTIMESTAMP_LO XE_REG(0xc3e8) + #define GUC_PMTIMESTAMP_HI XE_REG(0xc3ec) + +diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c +index 4ab65cae87433..96c28014f3887 100644 +--- a/drivers/gpu/drm/xe/xe_guc.c ++++ b/drivers/gpu/drm/xe/xe_guc.c +@@ -900,6 +900,41 @@ int xe_guc_post_load_init(struct xe_guc *guc) + return xe_guc_submit_enable(guc); + } + ++/* ++ * Wa_14025883347: Prevent GuC firmware DMA failures during GuC-only reset by ensuring ++ * SRAM save/restore operations are complete before reset. ++ */ ++static void guc_prevent_fw_dma_failure_on_reset(struct xe_guc *guc) ++{ ++ struct xe_gt *gt = guc_to_gt(guc); ++ u32 boot_hash_chk, guc_status, sram_status; ++ int ret; ++ ++ guc_status = xe_mmio_read32(>->mmio, GUC_STATUS); ++ if (guc_status & GS_MIA_IN_RESET) ++ return; ++ ++ boot_hash_chk = xe_mmio_read32(>->mmio, BOOT_HASH_CHK); ++ if (!(boot_hash_chk & GUC_BOOT_UKERNEL_VALID)) ++ return; ++ ++ /* Disable idle flow during reset (GuC reset re-enables it automatically) */ ++ xe_mmio_rmw32(>->mmio, GUC_MAX_IDLE_COUNT, 0, GUC_IDLE_FLOW_DISABLE); ++ ++ ret = xe_mmio_wait32(>->mmio, GUC_STATUS, GS_UKERNEL_MASK, ++ FIELD_PREP(GS_UKERNEL_MASK, XE_GUC_LOAD_STATUS_READY), ++ 100000, &guc_status, false); ++ if (ret) ++ xe_gt_warn(gt, "GuC not ready after disabling idle flow (GUC_STATUS: 0x%x)\n", ++ guc_status); ++ ++ ret = xe_mmio_wait32(>->mmio, GUC_SRAM_STATUS, GUC_SRAM_HANDLING_MASK, ++ 0, 5000, &sram_status, false); ++ if (ret) ++ xe_gt_warn(gt, "SRAM handling not complete (GUC_SRAM_STATUS: 0x%x)\n", ++ sram_status); ++} ++ + int xe_guc_reset(struct xe_guc *guc) + { + struct xe_gt *gt = guc_to_gt(guc); +@@ -912,6 +947,9 @@ int xe_guc_reset(struct xe_guc *guc) + if (IS_SRIOV_VF(gt_to_xe(gt))) + return xe_gt_sriov_vf_bootstrap(gt); + ++ if (XE_GT_WA(gt, 14025883347)) ++ guc_prevent_fw_dma_failure_on_reset(guc); ++ + xe_mmio_write32(mmio, GDRST, GRDOM_GUC); + + ret = xe_mmio_wait32(mmio, GDRST, GRDOM_GUC, 0, 5000, &gdrst, false); +diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules +index 5cd7fa6d2a5c0..ac08f94f90a14 100644 +--- a/drivers/gpu/drm/xe/xe_wa_oob.rules ++++ b/drivers/gpu/drm/xe/xe_wa_oob.rules +@@ -73,3 +73,6 @@ + 15015404425_disable PLATFORM(PANTHERLAKE), MEDIA_STEP(B0, FOREVER) + 16026007364 MEDIA_VERSION(3000) + 14020316580 MEDIA_VERSION(1301) ++ ++14025883347 MEDIA_VERSION_RANGE(1301, 3503) ++ GRAPHICS_VERSION_RANGE(2004, 3005) +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-skip-adding-prl-entry-to-null-vma.patch b/queue-7.0/drm-xe-skip-adding-prl-entry-to-null-vma.patch new file mode 100644 index 0000000000..03ca9c5ab2 --- /dev/null +++ b/queue-7.0/drm-xe-skip-adding-prl-entry-to-null-vma.patch @@ -0,0 +1,47 @@ +From 1c25c9536b0edb84ddff3d3330e6a296b2ffdf4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 17:15:50 +0000 +Subject: drm/xe: Skip adding PRL entry to NULL VMA + +From: Brian Nguyen + +[ Upstream commit 1b12096b4bc5177d685ae098fdb90260ffd5db6b ] + +NULL VMAs have no corresponding PTE, so skip adding a PRL entry to avoid +an unnecessary PRL abort during unbind. + +Signed-off-by: Brian Nguyen +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260305171546.67691-8-brian3.nguyen@intel.com +Signed-off-by: Matt Roper +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_page_reclaim.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/xe/xe_page_reclaim.c b/drivers/gpu/drm/xe/xe_page_reclaim.c +index e13c71a89da2c..390bcb82e4c5c 100644 +--- a/drivers/gpu/drm/xe/xe_page_reclaim.c ++++ b/drivers/gpu/drm/xe/xe_page_reclaim.c +@@ -26,12 +26,18 @@ + * flushes. + * - pat_index is transient display (1) + * ++ * For cases of NULL VMA, there should be no corresponding PRL entry ++ * so skip over. ++ * + * Return: true when page reclamation is unnecessary, false otherwise. + */ + bool xe_page_reclaim_skip(struct xe_tile *tile, struct xe_vma *vma) + { + u8 l3_policy; + ++ if (xe_vma_is_null(vma)) ++ return true; ++ + l3_policy = xe_pat_index_get_l3_policy(tile->xe, vma->attr.pat_index); + + /* +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-vf-wait-for-all-fixups-before-using-default-l.patch b/queue-7.0/drm-xe-vf-wait-for-all-fixups-before-using-default-l.patch new file mode 100644 index 0000000000..f53c2026c6 --- /dev/null +++ b/queue-7.0/drm-xe-vf-wait-for-all-fixups-before-using-default-l.patch @@ -0,0 +1,96 @@ +From c30adcb07a9242c1991a006d1449158bc70527bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 22:27:00 +0100 +Subject: drm/xe/vf: Wait for all fixups before using default LRCs + +From: Tomasz Lis + +[ Upstream commit f3fb5f1ebbf39e685dd2885c9dbc8bb0a80be7c6 ] + +When a context is being created during save/restore, the LRC creation +needs to wait for GGTT address space to be shifted. But it also needs +to have fixed default LRCs. This is mandatory to avoid the situation +where LRC will be created based on data from before the fixups, but +reference within exec queue will be set too late for fixups. + +This fixes an issue where contexts created during save/restore have +a large chance of having one unfixed LRC, due to the xe_lrc_create() +being synced for equal start to race with default LRC fixups. + +v2: Move the fixups confirmation further, behind all fixups. + Revert some renames. + +Signed-off-by: Tomasz Lis +Reviewed-by: Matthew Brost +Signed-off-by: Michal Wajdeczko +Link: https://patch.msgid.link/20260226212701.2937065-4-tomasz.lis@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 16 +++++++++------- + drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h | 2 +- + 2 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +index 30e8c2cf5f09a..b50f7181ce7a9 100644 +--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c ++++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +@@ -529,12 +529,6 @@ static int vf_get_ggtt_info(struct xe_gt *gt) + xe_tile_sriov_vf_fixup_ggtt_nodes_locked(gt_to_tile(gt), shift); + } + +- if (xe_sriov_vf_migration_supported(gt_to_xe(gt))) { +- WRITE_ONCE(gt->sriov.vf.migration.ggtt_need_fixes, false); +- smp_wmb(); /* Ensure above write visible before wake */ +- wake_up_all(>->sriov.vf.migration.wq); +- } +- + return 0; + } + +@@ -839,6 +833,13 @@ static void xe_gt_sriov_vf_default_lrcs_hwsp_rebase(struct xe_gt *gt) + xe_default_lrc_update_memirq_regs_with_address(hwe); + } + ++static void vf_post_migration_mark_fixups_done(struct xe_gt *gt) ++{ ++ WRITE_ONCE(gt->sriov.vf.migration.ggtt_need_fixes, false); ++ smp_wmb(); /* Ensure above write visible before wake */ ++ wake_up_all(>->sriov.vf.migration.wq); ++} ++ + static void vf_start_migration_recovery(struct xe_gt *gt) + { + bool started; +@@ -1373,6 +1374,7 @@ static void vf_post_migration_recovery(struct xe_gt *gt) + if (err) + goto fail; + ++ vf_post_migration_mark_fixups_done(gt); + vf_post_migration_rearm(gt); + + err = vf_post_migration_resfix_done(gt, marker); +@@ -1507,7 +1509,7 @@ static bool vf_valid_ggtt(struct xe_gt *gt) + } + + /** +- * xe_gt_sriov_vf_wait_valid_ggtt() - VF wait for valid GGTT addresses ++ * xe_gt_sriov_vf_wait_valid_ggtt() - wait for valid GGTT nodes and address refs + * @gt: the &xe_gt + */ + void xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt) +diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h +index 4ef881b9b6623..fca18be589db9 100644 +--- a/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h ++++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h +@@ -73,7 +73,7 @@ struct xe_gt_sriov_vf_migration { + bool recovery_queued; + /** @recovery_inprogress: VF post migration recovery in progress */ + bool recovery_inprogress; +- /** @ggtt_need_fixes: VF GGTT needs fixes */ ++ /** @ggtt_need_fixes: VF GGTT and references to it need fixes */ + bool ggtt_need_fixes; + }; + +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-arm64-add-marvell-7k-come-boards.patch b/queue-7.0/dt-bindings-arm64-add-marvell-7k-come-boards.patch new file mode 100644 index 0000000000..e80e34b9ea --- /dev/null +++ b/queue-7.0/dt-bindings-arm64-add-marvell-7k-come-boards.patch @@ -0,0 +1,48 @@ +From 76ed73f3af561dc36dcc60b03d2b4751442e016d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 18:59:21 +0200 +Subject: dt-bindings: arm64: add Marvell 7k COMe boards + +From: Elad Nachman + +[ Upstream commit 283822a64d6bd9aca55b5e2718bc63e9815b443d ] + +Add dt bindings for: +Armada 7020 COM Express CPU module +Falcon DB-98CX85x0 COM Express type 7 Carrier board +Falcon DB-98CX85x0 COM Express type 7 Carrier board +with an Armada 7020 COM Express CPU module + +Signed-off-by: Elad Nachman +Acked-by: Rob Herring (Arm) +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/arm/marvell/armada-7k-8k.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +index 4bc7454a5d3ac..7e77310da626f 100644 +--- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml ++++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +@@ -21,6 +21,17 @@ properties: + - const: marvell,armada-ap806-dual + - const: marvell,armada-ap806 + ++ - description: ++ Falcon (DB-98CX85x0) Development board COM Express Carrier plus ++ Armada 7020 SoC COM Express CPU module ++ items: ++ - const: marvell,armada7020-falcon-carrier ++ - const: marvell,db-falcon-carrier ++ - const: marvell,armada7020-cpu-module ++ - const: marvell,armada7020 ++ - const: marvell,armada-ap806-dual ++ - const: marvell,armada-ap806 ++ + - description: Armada 7040 SoC + items: + - enum: +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch b/queue-7.0/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch new file mode 100644 index 0000000000..b010a79197 --- /dev/null +++ b/queue-7.0/dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch @@ -0,0 +1,37 @@ +From e9a448e1fe9a3573e894862fab6ea9cbe8665193 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:42 +0100 +Subject: dt-bindings: rtc: microcrystal,rv3028: Allow to specify vdd-supply + +From: Frieder Schrempf + +[ Upstream commit 10663044bee592ba049a2aa37f4431fbdf93b739 ] + +In case the VDD supply voltage regulator of the RTC needs to be +specified explicitly, allow to set vdd-supply. + +Signed-off-by: Frieder Schrempf +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20260309085749.25747-2-frieder@fris.de +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +index cda8ad7c12037..2ea3b40419530 100644 +--- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml ++++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3028.yaml +@@ -32,6 +32,8 @@ properties: + - 9000 + - 15000 + ++ vdd-supply: true ++ + required: + - compatible + - reg +-- +2.53.0 + diff --git a/queue-7.0/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch b/queue-7.0/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch new file mode 100644 index 0000000000..11ebad896c --- /dev/null +++ b/queue-7.0/ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch @@ -0,0 +1,46 @@ +From a878e8db023e8a6828d1feb386c0144cb56b54d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 10:09:55 +0000 +Subject: ecryptfs: Set s_time_gran to get correct time granularity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Hsiao 蕭法宣 + +[ Upstream commit 7d9ebf33d85317f3f258c627de51701e2bf7642d ] + +Set the eCryptfs superblock time granularity, using the lower +filesystem's s_time_gran value, to prevent unnecessary inode timestamp +truncation to the granularity of a full second. + +The use of utimensat(2) to set a timestamp with nanosecond precision +would trigger this bug. That occurred when using the following utilities +to update timestamps of a file: + * cp -p: copy a file and preserve its atime and mtime + * touch -r: touch a file and use a reference file's timestamps + +Closes: https://bugs.launchpad.net/ecryptfs/+bug/1890486 +Signed-off-by: Frank Hsiao 蕭法宣 +[tyhicks: Partially rewrite the commit message] +Signed-off-by: Tyler Hicks +Signed-off-by: Sasha Levin +--- + fs/ecryptfs/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index f4ab387eb4ed2..5f37cddb956fb 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -531,6 +531,7 @@ static int ecryptfs_get_tree(struct fs_context *fc) + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ s->s_time_gran = path.dentry->d_sb->s_time_gran; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { +-- +2.53.0 + diff --git a/queue-7.0/edac-amd64-add-support-for-family-19h-models-40h-4fh.patch b/queue-7.0/edac-amd64-add-support-for-family-19h-models-40h-4fh.patch new file mode 100644 index 0000000000..51029d18cc --- /dev/null +++ b/queue-7.0/edac-amd64-add-support-for-family-19h-models-40h-4fh.patch @@ -0,0 +1,40 @@ +From 833604f0fe0319d83183697b79d4b920215d71c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 00:04:53 +0530 +Subject: EDAC/amd64: Add support for family 19h, models 40h-4fh + +From: Devang Vyas + +[ Upstream commit fbe230a9a79b62be3c6ac55b24d53ce5dd9202d5 ] + +Add support for Ryzen 6000 Zen3-based CPUs in the V3000 AMD Embedded SoC +platform which uses ECC memory and would need RAS handling of hardware errors. + +Co-developed-by: Ramesh Garidapuri +Signed-off-by: Ramesh Garidapuri +Signed-off-by: Devang Vyas +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260317183453.3556588-1-devangnayanbhai.vyas@amd.com +Signed-off-by: Sasha Levin +--- + drivers/edac/amd64_edac.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c +index 8908ab881c855..c6aa69dbd9fb1 100644 +--- a/drivers/edac/amd64_edac.c ++++ b/drivers/edac/amd64_edac.c +@@ -3863,6 +3863,9 @@ static int per_family_init(struct amd64_pvt *pvt) + pvt->max_mcs = 8; + } + break; ++ case 0x40 ... 0x4f: ++ pvt->max_mcs = 4; ++ break; + case 0x60 ... 0x6f: + pvt->flags.zn_regs_v2 = 1; + break; +-- +2.53.0 + diff --git a/queue-7.0/enic-add-v2-sr-iov-vf-device-id.patch b/queue-7.0/enic-add-v2-sr-iov-vf-device-id.patch new file mode 100644 index 0000000000..987a4b309a --- /dev/null +++ b/queue-7.0/enic-add-v2-sr-iov-vf-device-id.patch @@ -0,0 +1,53 @@ +From 38efad470ee9e4f6e22c100ec95a704373e92ed3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:31:12 -0700 +Subject: enic: add V2 SR-IOV VF device ID + +From: Satish Kharat + +[ Upstream commit 803a1b02027918450b58803190aa7cacb8056265 ] + +Register the V2 VF PCI device ID (0x02b7) so the driver binds to V2 +virtual functions created via sriov_configure. Update enic_is_sriov_vf() +to recognize V2 VFs alongside the existing V1 type. + +Signed-off-by: Satish Kharat +Link: https://patch.msgid.link/20260401-enic-sriov-v2-prep-v4-2-d5834b2ef1b9@cisco.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cisco/enic/enic_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index e839081f9ee44..e16dfbcd2c229 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -66,12 +66,14 @@ + #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ + #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ ++#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2 0x02b7 /* enet SRIOV V2 VF */ + + /* Supported devices */ + static const struct pci_device_id enic_id_table[] = { + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, ++ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2) }, + { 0, } /* end of table */ + }; + +@@ -307,7 +309,8 @@ int enic_sriov_enabled(struct enic *enic) + + static int enic_is_sriov_vf(struct enic *enic) + { +- return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; ++ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF || ++ enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2; + } + + int enic_is_valid_vf(struct enic *enic, int vf) +-- +2.53.0 + diff --git a/queue-7.0/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch b/queue-7.0/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch new file mode 100644 index 0000000000..c4657b3491 --- /dev/null +++ b/queue-7.0/erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch @@ -0,0 +1,53 @@ +From 00fcfb23921a84feab8895936eae62a809c2297c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:02:49 +0800 +Subject: erofs: ensure all folios are managed in + erofs_try_to_free_all_cached_folios() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhan Xusheng + +[ Upstream commit 5de6951fedb29700ace53b283ccb951c8f712d12 ] + +folio_trylock() in erofs_try_to_free_all_cached_folios() may +successfully acquire the folio lock, but the subsequent check +for erofs_folio_is_managed() can skip unlocking when the folio +is not managed by EROFS. + +As Gao Xiang pointed out, this condition should not happen in +practice because compressed_bvecs[] only holds valid cached folios +at this point — any non-managed folio would have already been +detached by z_erofs_cache_release_folio() under folio lock. + +Fix this by adding DBG_BUGON() to catch unexpected folios +and ensure folio_unlock() is always called. + +Suggested-by: Gao Xiang +Signed-off-by: Zhan Xusheng +Reviewed-by: Gao Xiang +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zdata.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index fe8121df9ef2f..b566996a0d1a5 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -605,8 +605,7 @@ static int erofs_try_to_free_all_cached_folios(struct erofs_sb_info *sbi, + if (!folio_trylock(folio)) + return -EBUSY; + +- if (!erofs_folio_is_managed(sbi, folio)) +- continue; ++ DBG_BUGON(!erofs_folio_is_managed(sbi, folio)); + pcl->compressed_bvecs[i].page = NULL; + folio_detach_private(folio); + folio_unlock(folio); +-- +2.53.0 + diff --git a/queue-7.0/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch b/queue-7.0/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch new file mode 100644 index 0000000000..68f327d9ff --- /dev/null +++ b/queue-7.0/ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch @@ -0,0 +1,58 @@ +From db1a0631103e0db5047c9d4113cf80418566408d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 09:43:43 +0800 +Subject: ethtool: fix ethnl_bitmap32_not_zero() bit interval semantics + +From: Chenguang Zhao + +[ Upstream commit 3d042592ebd4c7e44974d556de0b727cb7db4dab ] + +ethnl_bitmap32_not_zero() should return true if some bit in [start, end) +is set: + +- Fix inverted memchr_inv() sense: return true when the scan finds a + non-zero byte, not when the middle words are all zero. +- Return false for an empty interval (end <= start). +- When end is 32-bit aligned, indices in [start, end) do not include any + bits from map[end_word]; return false after earlier checks found no + non-zero data. + +Fixes: 10b518d4e6dd ("ethtool: netlink bitset handling") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index f0883357d12e5..4691d6d0f2b75 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -91,7 +91,7 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + u32 mask; + + if (end <= start) +- return true; ++ return false; + + if (start % 32) { + mask = ethnl_upper_bits(start); +@@ -104,11 +104,11 @@ static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start, + start_word++; + } + +- if (!memchr_inv(map + start_word, '\0', +- (end_word - start_word) * sizeof(u32))) ++ if (memchr_inv(map + start_word, '\0', ++ (end_word - start_word) * sizeof(u32))) + return true; + if (end % 32 == 0) +- return true; ++ return false; + return map[end_word] & ethnl_lower_bits(end); + } + +-- +2.53.0 + diff --git a/queue-7.0/exfat-fix-bitwise-operation-having-different-size.patch b/queue-7.0/exfat-fix-bitwise-operation-having-different-size.patch new file mode 100644 index 0000000000..17b35b749d --- /dev/null +++ b/queue-7.0/exfat-fix-bitwise-operation-having-different-size.patch @@ -0,0 +1,40 @@ +From fa6bca19383c19d7e262e390c997d6d441235051 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:59:14 +0100 +Subject: exfat: Fix bitwise operation having different size + +From: Philipp Hahn + +[ Upstream commit 3dce5bb82c97fc2ac28d80d496120a6525ce3fb7 ] + +cpos has type loff_t (long long), while s_blocksize has type u32. The +inversion wil happen on u32, the coercion to s64 happens afterwards and +will do 0-left-paddding, resulting in the upper bits getting masked out. + +Cast s_blocksize to loff_t before negating it. + +Found by static code analysis using Klocwork. + +Signed-off-by: Philipp Hahn +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index 3a4853693d8bf..e710dd196e2f0 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -249,7 +249,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx) + */ + if (err == -EIO) { + cpos += 1 << (sb->s_blocksize_bits); +- cpos &= ~(sb->s_blocksize - 1); ++ cpos &= ~(loff_t)(sb->s_blocksize - 1); + } + + err = -EIO; +-- +2.53.0 + diff --git a/queue-7.0/exfat-fix-incorrect-directory-checksum-after-rename-.patch b/queue-7.0/exfat-fix-incorrect-directory-checksum-after-rename-.patch new file mode 100644 index 0000000000..f78ca7d0c0 --- /dev/null +++ b/queue-7.0/exfat-fix-incorrect-directory-checksum-after-rename-.patch @@ -0,0 +1,44 @@ +From d17de324a49f1b84062a1d8726aa631183c3cfb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:33 +0800 +Subject: exfat: fix incorrect directory checksum after rename to shorter name + +From: Chi Zhiling + +[ Upstream commit ff37797badd831797b8a27830fe5046d7e23fdc3 ] + +When renaming a file in-place to a shorter name, exfat_remove_entries +marks excess entries as DELETED, but es->num_entries is not updated +accordingly. As a result, exfat_update_dir_chksum iterates over the +deleted entries and computes an incorrect checksum. + +This does not lead to persistent corruption because mark_inode_dirty() +is called afterward, and __exfat_write_inode later recomputes the +checksum using the correct num_entries value. + +Fix by setting es->num_entries = num_entries in exfat_init_ext_entry. + +Signed-off-by: Chi Zhiling +Reviewed-by: Sungjong Seo +Reviewed-by: Yuezhang Mo +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/dir.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c +index e710dd196e2f0..2a4f6a131fbe7 100644 +--- a/fs/exfat/dir.c ++++ b/fs/exfat/dir.c +@@ -490,6 +490,7 @@ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries, + unsigned short *uniname = p_uniname->name; + struct exfat_dentry *ep; + ++ es->num_entries = num_entries; + ep = exfat_get_dentry_cached(es, ES_IDX_FILE); + ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); + +-- +2.53.0 + diff --git a/queue-7.0/exfat-fix-s_maxbytes.patch b/queue-7.0/exfat-fix-s_maxbytes.patch new file mode 100644 index 0000000000..c29ce31189 --- /dev/null +++ b/queue-7.0/exfat-fix-s_maxbytes.patch @@ -0,0 +1,80 @@ +From 39da81f3de487a75c3c31b3709fcb5ccb53a8984 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 06:41:37 +0900 +Subject: exfat: fix s_maxbytes + +From: David Timber + +[ Upstream commit 4129a3a2751cba8511cee5d13145223662a8e019 ] + +With fallocate support, xfstest unit generic/213 fails with + + QA output created by 213 + We should get: fallocate: No space left on device + Strangely, xfs_io sometimes says "Success" when something went wrong + -fallocate: No space left on device + +fallocate: File too large + +because sb->s_maxbytes is set to the volume size. + +To be in line with other non-extent-based filesystems, set to max volume +size possible with the cluster size of the volume. + +Signed-off-by: David Timber +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/exfat_raw.h | 1 + + fs/exfat/file.c | 1 + + fs/exfat/super.c | 11 ++++++++--- + 3 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h +index 4082fa7b8c142..ec70cd35bba0c 100644 +--- a/fs/exfat/exfat_raw.h ++++ b/fs/exfat/exfat_raw.h +@@ -25,6 +25,7 @@ + #define EXFAT_FIRST_CLUSTER 2 + #define EXFAT_DATA_CLUSTER_COUNT(sbi) \ + ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) ++#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) + + /* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ + #define ALLOC_POSSIBLE 0x01 +diff --git a/fs/exfat/file.c b/fs/exfat/file.c +index 90cd540afeaa7..310083537a91d 100644 +--- a/fs/exfat/file.c ++++ b/fs/exfat/file.c +@@ -33,6 +33,7 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) + return ret; + + num_clusters = EXFAT_B_TO_CLU(exfat_ondisk_size(inode), sbi); ++ /* integer overflow is already checked in inode_newsize_ok(). */ + new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi); + + if (new_num_clusters == num_clusters) +diff --git a/fs/exfat/super.c b/fs/exfat/super.c +index 83396fd265cda..95d87e2d7717f 100644 +--- a/fs/exfat/super.c ++++ b/fs/exfat/super.c +@@ -531,9 +531,14 @@ static int exfat_read_boot_sector(struct super_block *sb) + if (sbi->vol_flags & MEDIA_FAILURE) + exfat_warn(sb, "Medium has reported failures. Some data may be lost."); + +- /* exFAT file size is limited by a disk volume size */ +- sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << +- sbi->cluster_size_bits; ++ /* ++ * Set to the max possible volume size for this volume's cluster size so ++ * that any integer overflow from bytes to cluster size conversion is ++ * checked in inode_newsize_ok(). Clamped to MAX_LFS_FILESIZE for 32-bit ++ * machines. ++ */ ++ sb->s_maxbytes = min(MAX_LFS_FILESIZE, ++ EXFAT_CLU_TO_B((loff_t)EXFAT_MAX_NUM_CLUSTER, sbi)); + + /* check logical sector size */ + if (exfat_calibrate_blocksize(sb, 1 << p_boot->sect_size_bits)) +-- +2.53.0 + diff --git a/queue-7.0/exfat-use-truncate_inode_pages_final-at-evict_inode.patch b/queue-7.0/exfat-use-truncate_inode_pages_final-at-evict_inode.patch new file mode 100644 index 0000000000..ddf73f99c4 --- /dev/null +++ b/queue-7.0/exfat-use-truncate_inode_pages_final-at-evict_inode.patch @@ -0,0 +1,49 @@ +From c08960f1925db40d6ffef4b7181a7c7cd5e02606 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 22:59:42 +0800 +Subject: exfat: use truncate_inode_pages_final() at evict_inode() + +From: Yang Wen + +[ Upstream commit 4637b4cdd7aebfa2e38fa39f4db91fa089b809c5 ] + +Currently, exfat uses truncate_inode_pages() in exfat_evict_inode(). +However, truncate_inode_pages() does not mark the mapping as exiting, +so reclaim may still install shadow entries for the mapping until +the inode teardown completes. + +In older kernels like Linux 5.10, if shadow entries are present +at that point,clear_inode() can hit + + BUG_ON(inode->i_data.nrexceptional); + +To align with VFS eviction semantics and prevent this situation, +switch to truncate_inode_pages_final() in ->evict_inode(). + +Other filesystems were updated to use truncate_inode_pages_final() +in ->evict_inode() by commit 91b0abe36a7b ("mm + fs: store shadow +entries in page cache")'. + +Signed-off-by: Yang Wen +Signed-off-by: Namjae Jeon +Signed-off-by: Sasha Levin +--- + fs/exfat/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c +index 2fb2d2d5d503a..567308aff726a 100644 +--- a/fs/exfat/inode.c ++++ b/fs/exfat/inode.c +@@ -686,7 +686,7 @@ struct inode *exfat_build_inode(struct super_block *sb, + + void exfat_evict_inode(struct inode *inode) + { +- truncate_inode_pages(&inode->i_data, 0); ++ truncate_inode_pages_final(&inode->i_data); + + if (!inode->i_nlink) { + i_size_write(inode, 0); +-- +2.53.0 + diff --git a/queue-7.0/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch b/queue-7.0/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch new file mode 100644 index 0000000000..aac5561fa4 --- /dev/null +++ b/queue-7.0/ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch @@ -0,0 +1,45 @@ +From 2e0f542dedf1906eeb1c3d518d1001b7dd07e381 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 02:20:52 +0000 +Subject: ext2: avoid drop_nlink() during unlink of zero-nlink inode in + ext2_unlink() + +From: Ziyi Guo + +[ Upstream commit 19134a133184fcc49c41cf42797cb2e7fef76065 ] + +ext2_unlink() calls inode_dec_link_count() unconditionally, which +invokes drop_nlink(). If the inode was loaded from a corrupted disk +image with i_links_count == 0, drop_nlink() +triggers WARN_ON(inode->i_nlink == 0) + +Follow the ext4 pattern from __ext4_unlink(): check i_nlink before +decrementing. If already zero, skip the decrement. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260211022052.973114-1-n7l8m4@u.northwestern.edu +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/namei.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c +index bde617a66cecd..728c487308baf 100644 +--- a/fs/ext2/namei.c ++++ b/fs/ext2/namei.c +@@ -293,7 +293,10 @@ static int ext2_unlink(struct inode *dir, struct dentry *dentry) + goto out; + + inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); +- inode_dec_link_count(inode); ++ ++ if (inode->i_nlink) ++ inode_dec_link_count(inode); ++ + err = 0; + out: + return err; +-- +2.53.0 + diff --git a/queue-7.0/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch b/queue-7.0/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch new file mode 100644 index 0000000000..c7604140ea --- /dev/null +++ b/queue-7.0/ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch @@ -0,0 +1,43 @@ +From e584f9932b04d630ee9171e0fe124aaccaa183c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:06:17 -0800 +Subject: ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks + +From: Milos Nikic + +[ Upstream commit 0cf9c58bf654d0f27abe18005281dbf9890de401 ] + +If ext2_get_blocks() is called with maxblocks == 0, it currently triggers +a BUG_ON(), causing a kernel panic. + +While this condition implies a logic error in the caller, a filesystem +should not crash the system due to invalid arguments. + +Replace the BUG_ON() with a WARN_ON_ONCE() to provide a stack trace for +debugging, and return -EINVAL to handle the error gracefully. + +Signed-off-by: Milos Nikic +Link: https://patch.msgid.link/20260207010617.216675-1-nikic.milos@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/ext2/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c +index 39d972722f5f8..73efd3030743d 100644 +--- a/fs/ext2/inode.c ++++ b/fs/ext2/inode.c +@@ -638,7 +638,8 @@ static int ext2_get_blocks(struct inode *inode, + int count = 0; + ext2_fsblk_t first_block = 0; + +- BUG_ON(maxblocks == 0); ++ if (WARN_ON_ONCE(maxblocks == 0)) ++ return -EINVAL; + + depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + +-- +2.53.0 + diff --git a/queue-7.0/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch b/queue-7.0/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch new file mode 100644 index 0000000000..8a958f407c --- /dev/null +++ b/queue-7.0/ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch @@ -0,0 +1,98 @@ +From a919ef544f0485837da06eccf80123dda9fd7123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:29:14 +0530 +Subject: ext4: unmap invalidated folios from page tables in + mpage_release_unused_pages() + +From: Deepanshu Kartikey + +[ Upstream commit 9b25f381de6b8942645f43735cb0a4fb0ab3a6d1 ] + +When delayed block allocation fails (e.g., due to filesystem corruption +detected in ext4_map_blocks()), the writeback error handler calls +mpage_release_unused_pages(invalidate=true) which invalidates affected +folios by clearing their uptodate flag via folio_clear_uptodate(). + +However, these folios may still be mapped in process page tables. If a +subsequent operation (such as ftruncate calling ext4_block_truncate_page) +triggers a write fault, the existing page table entry allows access to +the now-invalidated folio. This leads to ext4_page_mkwrite() being called +with a non-uptodate folio, which then gets marked dirty, triggering: + + WARNING: CPU: 0 PID: 5 at mm/page-writeback.c:2960 + __folio_mark_dirty+0x578/0x880 + + Call Trace: + fault_dirty_shared_page+0x16e/0x2d0 + do_wp_page+0x38b/0xd20 + handle_pte_fault+0x1da/0x450 + +The sequence leading to this warning is: + +1. Process writes to mmap'd file, folio becomes uptodate and dirty +2. Writeback begins, but delayed allocation fails due to corruption +3. mpage_release_unused_pages(invalidate=true) is called: + - block_invalidate_folio() clears dirty flag + - folio_clear_uptodate() clears uptodate flag + - But folio remains mapped in page tables +4. Later, ftruncate triggers ext4_block_truncate_page() +5. This causes a write fault on the still-mapped folio +6. ext4_page_mkwrite() is called with folio that is !uptodate +7. block_page_mkwrite() marks buffers dirty +8. fault_dirty_shared_page() tries to mark folio dirty +9. block_dirty_folio() calls __folio_mark_dirty(warn=1) +10. WARNING triggers: WARN_ON_ONCE(warn && !uptodate && !dirty) + +Fix this by unmapping folios from page tables before invalidating them +using unmap_mapping_pages(). This ensures that subsequent accesses +trigger new page faults rather than reusing invalidated folios through +stale page table entries. + +Note that this results in data loss for any writes to the mmap'd region +that couldn't be written back, but this is expected behavior when +writeback fails due to filesystem corruption. The existing error message +already states "This should not happen!! Data will be lost". + +Reported-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Tested-by: syzbot+b0a0670332b6b3230a0a@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b0a0670332b6b3230a0a +Suggested-by: Matthew Wilcox +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20251205055914.1393799-1-kartikey406@gmail.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 1123d995494b5..025ea8f0c41bd 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1757,8 +1757,22 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd, + BUG_ON(!folio_test_locked(folio)); + BUG_ON(folio_test_writeback(folio)); + if (invalidate) { +- if (folio_mapped(folio)) ++ if (folio_mapped(folio)) { + folio_clear_dirty_for_io(folio); ++ /* ++ * Unmap folio from page ++ * tables to prevent ++ * subsequent accesses through ++ * stale PTEs. This ensures ++ * future accesses trigger new ++ * page faults rather than ++ * reusing the invalidated ++ * folio. ++ */ ++ unmap_mapping_pages(folio->mapping, ++ folio->index, ++ folio_nr_pages(folio), false); ++ } + block_invalidate_folio(folio, 0, + folio_size(folio)); + folio_clear_uptodate(folio); +-- +2.53.0 + diff --git a/queue-7.0/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch b/queue-7.0/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch new file mode 100644 index 0000000000..fb01419de7 --- /dev/null +++ b/queue-7.0/f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch @@ -0,0 +1,115 @@ +From 15193e09f0e89a8eb106ce77981aa315af4b4cfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:54 -0700 +Subject: f2fs: fix to freeze GC and discard threads quickly + +From: Daeho Jeong + +[ Upstream commit 02d91398a602c394d72cd61a67c84e2730c5f79b ] + +Suspend can fail if kernel threads do not freeze for a while. +f2fs_gc and f2fs_discard threads can perform long-running operations +that prevent them from reaching a freeze point in a timely manner. + +This patch adds explicit freezing checks in the following locations: +1. f2fs_gc: Added a check at the 'retry' label to exit the loop quickly + if freezing is requested, especially during heavy GC rounds. +2. __issue_discard_cmd: Added a 'suspended' flag to break both inner and + outer loops during discard command issuance if freezing is detected + after at least one command has been issued. +3. __issue_discard_cmd_orderly: Added a similar check for orderly discard + to ensure responsiveness. + +These checks ensure that the threads release locks safely and enter the +frozen state. + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 10 ++++++++++ + fs/f2fs/segment.c | 12 +++++++++++- + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 34f9f13adfb12..0dc8cebd63e44 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1894,12 +1894,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + sbi->next_victim_seg[gc_type] = + (cur_segno + 1 < sec_end_segno) ? + cur_segno + 1 : NULL_SEGNO; ++ ++ if (unlikely(freezing(current))) { ++ folio_put_refs(sum_folio, 2); ++ goto stop; ++ } + } + next_block: + folio_put_refs(sum_folio, 2); + segno = block_end_segno; + } + ++stop: + if (submitted) + f2fs_submit_merged_write(sbi, data_type); + +@@ -1973,6 +1979,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control) + goto stop; + } + retry: ++ if (unlikely(freezing(current))) { ++ ret = 0; ++ goto stop; ++ } + ret = __get_victim(sbi, &segno, gc_type, gc_control->one_time); + if (ret) { + /* allow to search victim from sections has pinned data */ +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 8390994a8826c..54294f1543bb6 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -1606,6 +1606,9 @@ static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, + if (dc->state != D_PREP) + goto next; + ++ if (*issued > 0 && unlikely(freezing(current))) ++ break; ++ + if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { + io_interrupted = true; + break; +@@ -1645,6 +1648,7 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + struct blk_plug plug; + int i, issued; + bool io_interrupted = false; ++ bool suspended = false; + + if (dpolicy->timeout) + f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT); +@@ -1675,6 +1679,11 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + list_for_each_entry_safe(dc, tmp, pend_list, list) { + f2fs_bug_on(sbi, dc->state != D_PREP); + ++ if (issued > 0 && unlikely(freezing(current))) { ++ suspended = true; ++ break; ++ } ++ + if (dpolicy->timeout && + f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) + break; +@@ -1694,7 +1703,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, + next: + mutex_unlock(&dcc->cmd_lock); + +- if (issued >= dpolicy->max_requests || io_interrupted) ++ if (issued >= dpolicy->max_requests || io_interrupted || ++ suspended) + break; + } + +-- +2.53.0 + diff --git a/queue-7.0/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch b/queue-7.0/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch new file mode 100644 index 0000000000..1c59f5b31e --- /dev/null +++ b/queue-7.0/f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch @@ -0,0 +1,48 @@ +From 22a0cf7a77713bb14b2694438bdaa7dd9b22de08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:59:21 -0700 +Subject: f2fs: fix to skip empty sections in f2fs_get_victim + +From: Daeho Jeong + +[ Upstream commit dccd324fa9bd1a2907a63fa4cc2651f687b2b5d0 ] + +In age-based victim selection (ATGC, AT_SSR, or GC_CB), f2fs_get_victim +can encounter sections with zero valid blocks. This situation often +arises when checkpoint is disabled or due to race conditions between +SIT updates and dirty list management. + +In such cases, f2fs_get_section_mtime() returns INVALID_MTIME, which +subsequently triggers a fatal f2fs_bug_on(sbi, mtime == INVALID_MTIME) +in add_victim_entry() or get_cb_cost(). + +This patch adds a check in f2fs_get_victim's selection loop to skip +sections with no valid blocks. This prevents unnecessary age +calculations for empty sections and avoids the associated kernel panic. +This change also allows removing redundant checks in add_victim_entry(). + +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index ec0680187c0db..34f9f13adfb12 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -909,6 +909,9 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, + if (!f2fs_segment_has_free_slot(sbi, segno)) + goto next; + } ++ ++ if (!get_valid_blocks(sbi, segno, true)) ++ goto next; + } + + if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) +-- +2.53.0 + diff --git a/queue-7.0/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch b/queue-7.0/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch new file mode 100644 index 0000000000..8bc2ccdd6c --- /dev/null +++ b/queue-7.0/fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch @@ -0,0 +1,41 @@ +From 96950444d461a6bbf723cbd8f1abab29973e32cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:34:03 +0800 +Subject: fbdev: omap2: fix inconsistent lock returns in omapfb_mmap + +From: Hongling Zeng + +[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ] + +Fix the warning about inconsistent returns for '&rg->lock' in +omapfb_mmap() function. The warning arises because the error path +uses 'ofbi->region' while the normal path uses 'rg'. + +smatch warnings: +drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap() +warn: inconsistent returns '&rg->lock'. + +Reported-by: kernel test robot +Signed-off-by: Hongling Zeng +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +index a8b2930290e1f..d70deb6a91508 100644 +--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) + return 0; + + error: +- omapfb_put_mem_region(ofbi->region); ++ omapfb_put_mem_region(rg); + + return r; + } +-- +2.53.0 + diff --git a/queue-7.0/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch b/queue-7.0/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch new file mode 100644 index 0000000000..f1c5beb0e4 --- /dev/null +++ b/queue-7.0/fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch @@ -0,0 +1,47 @@ +From 259e69e1a4c3fd3b4a7aa45c48b764066393f91d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 01:19:26 -0400 +Subject: fbdev: savage: fix probe-path EDID cleanup leaks + +From: Yuho Choi + +[ Upstream commit 9b8a9a3a6f57edd02b7c8db14a316e6fab7fa772 ] + +When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an +EDID-derived monspecs.modedb and a modelist from it before later failing. + +The normal success path frees monspecs.modedb after the initial mode selection, +but the probe error path only deletes the I2C busses and misses the +EDID-derived allocations. + +Free both the modelist and monspecs.modedb on the failed: unwind path. + +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/savage/savagefb_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c +index ac41f8f37589f..c2f79357c8da0 100644 +--- a/drivers/video/fbdev/savage/savagefb_driver.c ++++ b/drivers/video/fbdev/savage/savagefb_driver.c +@@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) + failed: + #ifdef CONFIG_FB_SAVAGE_I2C + savagefb_delete_i2c_busses(info); ++ fb_destroy_modelist(&info->modelist); ++ fb_destroy_modedb(info->monspecs.modedb); + #endif + fb_alloc_cmap(&info->cmap, 0, 0); + savage_unmap_video(info); +-- +2.53.0 + diff --git a/queue-7.0/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch b/queue-7.0/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch new file mode 100644 index 0000000000..9330317661 --- /dev/null +++ b/queue-7.0/fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch @@ -0,0 +1,38 @@ +From ed72a892690902808009f75503f516eb1cfcef4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:14:20 +0800 +Subject: fbdev: viafb: check ioremap return value in + viafb_lcd_get_mobile_state + +From: Wang Jun <1742789905@qq.com> + +[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ] + +The function viafb_lcd_get_mobile_state() calls ioremap() without +checking the return value. If ioremap() fails (returns NULL), the +subsequent readw() will cause a NULL pointer dereference. + +Signed-off-by: Wang Jun <1742789905@qq.com> +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/via/lcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c +index 8673fced87492..3fa2304fbda7e 100644 +--- a/drivers/video/fbdev/via/lcd.c ++++ b/drivers/video/fbdev/via/lcd.c +@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile) + u16 start_pattern; + + biosptr = ioremap(romaddr, 0x10000); ++ if (!biosptr) ++ return false; ++ + start_pattern = readw(biosptr); + + /* Compare pattern */ +-- +2.53.0 + diff --git a/queue-7.0/fddi-defxx-rate-limit-memory-allocation-errors.patch b/queue-7.0/fddi-defxx-rate-limit-memory-allocation-errors.patch new file mode 100644 index 0000000000..9761d7052d --- /dev/null +++ b/queue-7.0/fddi-defxx-rate-limit-memory-allocation-errors.patch @@ -0,0 +1,69 @@ +From cee85d9425bac836597c8dab5593d341357a2eb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:32:25 +0100 +Subject: FDDI: defxx: Rate-limit memory allocation errors + +From: Maciej W. Rozycki + +[ Upstream commit 7fae6616704a17c64438ad4b73a6effa6c03ffda ] + +Prevent the system from becoming unstable or unusable due to a flood of +memory allocation error messages under memory pressure, e.g.: + +[...] +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +fddi0: Could not allocate receive buffer. Dropping packet. +rcu: INFO: rcu_sched self-detected stall on CPU +rcu: 0-...!: (332 ticks this GP) idle=255c/1/0x40000000 softirq=16420123/16420123 fqs=0 +rcu: (t=2103 jiffies g=35680089 q=4 ncpus=1) +rcu: rcu_sched kthread timer wakeup didn't happen for 2102 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 +rcu: Possible timer handling issue on cpu=0 timer-softirq=12779658 +rcu: rcu_sched kthread starved for 2103 jiffies! g35680089 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0 +rcu: Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected behavior. +rcu: RCU grace-period kthread stack dump: +task:rcu_sched state:I stack:0 pid:14 tgid:14 ppid:2 flags:0x00004000 +Call Trace: + __schedule+0x258/0x580 + schedule+0x19/0xa0 + schedule_timeout+0x4a/0xb0 + ? hrtimers_cpu_dying+0x1b0/0x1b0 + rcu_gp_fqs_loop+0xb1/0x450 + rcu_gp_kthread+0x9d/0x130 + kthread+0xb2/0xe0 + ? rcu_gp_init+0x4a0/0x4a0 + ? kthread_park+0x90/0x90 + ret_from_fork+0x2d/0x50 + ? kthread_park+0x90/0x90 + ret_from_fork_asm+0x12/0x20 + entry_INT80_32+0x10d/0x10d +CPU: 0 UID: 500 PID: 21895 Comm: 31370.exe Not tainted 6.13.0-dirty #2 + +(here running the libstdc++-v3 testsuite). + +Signed-off-by: Maciej W. Rozycki +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/alpine.DEB.2.21.2603291236590.60268@angie.orcam.me.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/fddi/defxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c +index 0fbbb7286008d..6b8cfbee3b9d6 100644 +--- a/drivers/net/fddi/defxx.c ++++ b/drivers/net/fddi/defxx.c +@@ -3182,7 +3182,7 @@ static void dfx_rcv_queue_process( + pkt_len + 3); + if (skb == NULL) + { +- printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); ++ printk_ratelimited("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } +-- +2.53.0 + diff --git a/queue-7.0/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch new file mode 100644 index 0000000000..fafbedf09b --- /dev/null +++ b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch @@ -0,0 +1,36 @@ +From c86aae9d54632c7e224f52c9002a3c1c2c4da7b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Feb 2026 09:32:54 +0100 +Subject: firmware: qcom: scm: allow QSEECOM on ASUS Vivobook X1P42100 variant + +From: Jens Glathe + +[ Upstream commit 26b86610650eaac17bf6574f34d9119151b95483 ] + +Enables access to EFI variables on this machine. + +Reviewed-by: Dmitry Baryshkov +Tested-by: Colin K. Williams +Signed-off-by: Jens Glathe +Link: https://lore.kernel.org/r/20260214-b4-vivobook-v3-2-3c88065bbf77@oldschoolsolutions.biz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index d439a9f5b62b8..dda6b0bc1cbd0 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -2289,6 +2289,7 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); + */ + static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "asus,vivobook-s15" }, ++ { .compatible = "asus,vivobook-s15-x1p4" }, + { .compatible = "asus,zenbook-a14-ux3407qa" }, + { .compatible = "asus,zenbook-a14-ux3407ra" }, + { .compatible = "dell,inspiron-14-plus-7441" }, +-- +2.53.0 + diff --git a/queue-7.0/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch new file mode 100644 index 0000000000..f835b720cf --- /dev/null +++ b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch @@ -0,0 +1,35 @@ +From 0f1818b874f8ff78b9546e1bd7603361be7766fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 20:30:13 -0300 +Subject: firmware: qcom: scm: Allow QSEECOM on ECS LIVA QC710 + +From: Val Packett + +[ Upstream commit 34a49e8508b5d00816d25fe3758b474471e7e051 ] + +Allow this machine to access efivars through qseecom/uefisecapp. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260120234029.419825-11-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index dda6b0bc1cbd0..0df8ad8b303d5 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -2295,6 +2295,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "dell,inspiron-14-plus-7441" }, + { .compatible = "dell,latitude-7455" }, + { .compatible = "dell,xps13-9345" }, ++ { .compatible = "ecs,liva-qc710" }, + { .compatible = "hp,elitebook-ultra-g1q" }, + { .compatible = "hp,omnibook-x14" }, + { .compatible = "huawei,gaokun3" }, +-- +2.53.0 + diff --git a/queue-7.0/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch new file mode 100644 index 0000000000..1fb3449cf3 --- /dev/null +++ b/queue-7.0/firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch @@ -0,0 +1,37 @@ +From cad286b0235110c780b18dd7df40228bd4844f92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 21:31:27 -0500 +Subject: firmware: qcom: scm: Allow QSEECOM on Lenovo IdeaCentre Mini X + +From: Bjorn Andersson + +[ Upstream commit a31ad9339eff4ce401dec816b01a94b4e3c47898 ] + +The Hamoa-based Lenovo IdeaCentre Mini X provides the same UEFI variable +access through uefisecapp as other Hamoa devices, add it to the +allowlist. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20260401-ideacentre-v2-3-5745fe2c764e@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index 0df8ad8b303d5..773ca842577c9 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -2300,6 +2300,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "hp,omnibook-x14" }, + { .compatible = "huawei,gaokun3" }, + { .compatible = "lenovo,flex-5g" }, ++ { .compatible = "lenovo,ideacentre-mini-01q8x10" }, + { .compatible = "lenovo,thinkbook-16" }, + { .compatible = "lenovo,thinkpad-t14s" }, + { .compatible = "lenovo,thinkpad-x13s", }, +-- +2.53.0 + diff --git a/queue-7.0/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch b/queue-7.0/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch new file mode 100644 index 0000000000..965d605a7b --- /dev/null +++ b/queue-7.0/fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch @@ -0,0 +1,124 @@ +From e6d32bc0e4c2d0a235cc45c4012e9ff00654bbcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 16:46:29 +0900 +Subject: fprobe: Fix unregister_fprobe() to wait for RCU grace period + +From: Masami Hiramatsu (Google) + +[ Upstream commit 657b594b2084b39a4bc6d8493aa2140cb00cea49 ] + +Commit 4346ba1604093 ("fprobe: Rewrite fprobe on function-graph tracer") +changed fprobe to register struct fprobe to an rcu-hlist, but it forgot +to wait for RCU GP. Thus there can be use-after-free if the fprobe is +released right after unregistering. This can be happened on fprobe +event and sample module code. + +To fix this issue, add synchronize_rcu() in unregister_fprobe(). + +Note that BPF is OK because fprobe is used as a part of +bpf_kprobe_multi_link. This unregisters its fprobe in +bpf_kprobe_multi_link_release() and it is deallocated via +bpf_kprobe_multi_link_dealloc(), which is invoked from +bpf_link_defer_dealloc_rcu_gp() RCU callback. + +For BPF, this also introduced unregister_fprobe_async() which does +NOT wait for RCU grace priod. + +Link: https://lore.kernel.org/all/177813998919.256460.2809243930741138224.stgit@mhiramat.tok.corp.google.com/ + +Fixes: 4346ba1604093 ("fprobe: Rewrite fprobe on function-graph tracer") +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/linux/fprobe.h | 5 +++++ + kernel/trace/bpf_trace.c | 3 ++- + kernel/trace/fprobe.c | 23 +++++++++++++++++++++-- + 3 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h +index 0a3bcd1718f37..be1b38c981d4d 100644 +--- a/include/linux/fprobe.h ++++ b/include/linux/fprobe.h +@@ -94,6 +94,7 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter + int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num); + int register_fprobe_syms(struct fprobe *fp, const char **syms, int num); + int unregister_fprobe(struct fprobe *fp); ++int unregister_fprobe_async(struct fprobe *fp); + bool fprobe_is_registered(struct fprobe *fp); + int fprobe_count_ips_from_filter(const char *filter, const char *notfilter); + #else +@@ -113,6 +114,10 @@ static inline int unregister_fprobe(struct fprobe *fp) + { + return -EOPNOTSUPP; + } ++static inline int unregister_fprobe_async(struct fprobe *fp) ++{ ++ return -EOPNOTSUPP; ++} + static inline bool fprobe_is_registered(struct fprobe *fp) + { + return false; +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index af7079aa0f36d..a02bd258677ee 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2384,7 +2384,8 @@ static void bpf_kprobe_multi_link_release(struct bpf_link *link) + struct bpf_kprobe_multi_link *kmulti_link; + + kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); +- unregister_fprobe(&kmulti_link->fp); ++ /* Don't wait for RCU GP here. */ ++ unregister_fprobe_async(&kmulti_link->fp); + kprobe_multi_put_modules(kmulti_link->mods, kmulti_link->mods_cnt); + } + +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 0afaae4e1a59c..fe4d630aa4460 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -1001,14 +1001,15 @@ static int unregister_fprobe_nolock(struct fprobe *fp) + } + + /** +- * unregister_fprobe() - Unregister fprobe. ++ * unregister_fprobe_async() - Unregister fprobe without RCU GP wait + * @fp: A fprobe data structure to be unregistered. + * + * Unregister fprobe (and remove ftrace hooks from the function entries). ++ * This function will NOT wait until the fprobe is no longer used. + * + * Return 0 if @fp is unregistered successfully, -errno if not. + */ +-int unregister_fprobe(struct fprobe *fp) ++int unregister_fprobe_async(struct fprobe *fp) + { + guard(mutex)(&fprobe_mutex); + if (!fp || !fprobe_registered(fp)) +@@ -1016,6 +1017,24 @@ int unregister_fprobe(struct fprobe *fp) + + return unregister_fprobe_nolock(fp); + } ++ ++/** ++ * unregister_fprobe() - Unregister fprobe with RCU GP wait ++ * @fp: A fprobe data structure to be unregistered. ++ * ++ * Unregister fprobe (and remove ftrace hooks from the function entries). ++ * This function will block until the fprobe is no longer used. ++ * ++ * Return 0 if @fp is unregistered successfully, -errno if not. ++ */ ++int unregister_fprobe(struct fprobe *fp) ++{ ++ int ret = unregister_fprobe_async(fp); ++ ++ if (!ret) ++ synchronize_rcu(); ++ return ret; ++} + EXPORT_SYMBOL_GPL(unregister_fprobe); + + static int __init fprobe_initcall(void) +-- +2.53.0 + diff --git a/queue-7.0/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch b/queue-7.0/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch new file mode 100644 index 0000000000..d98e431dae --- /dev/null +++ b/queue-7.0/fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch @@ -0,0 +1,99 @@ +From 150665e6e41a15e071a5cf3d9d8c972814b8d0d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 14:06:34 +0800 +Subject: fs: aio: reject partial mremap to avoid Null-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit 3adf7ae18bf42601246031002287c103a27df307 ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +... +Crash analysis showed the file involved was an AIO ring file. The +phenomenon triggered is the same as the issue described in [1]. + +[CAUSE] +Consider the following scenario: userspace sets up an AIO context via +io_setup(), which creates a VMA covering the entire ring buffer. Then +userspace calls mremap() with the AIO ring address as the source, a smaller +old_len (less than the full ring size), MREMAP_MAYMOVE set, and without +MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new +destination address. + +During this move, __split_vma() splits the original AIO ring VMA. The +requested portion is unmapped from the source and re-established at the +destination, while the remainder stays at the original source address as +an orphan VMA. The aio_ring_mremap() callback fires on the new destination +VMA, updating ctx->mmap_base to the destination address. But the callback +is unaware that only a partial region was moved and that an orphan VMA +still exists at the source: + + source(AIO): + +-------------------+---------------------+ + | moved to dest | orphan VMA (AIO) | + +-------------------+---------------------+ + A A+partial_len A+ctx->mmap_size + + dest: + +-------------------+ + | moved VMA (AIO) | + +-------------------+ + B B+partial_len + +Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which +unmaps the destination. This not only fails to unmap the orphan VMA at the +source, but also overshoots the destination VMA and may unmap unrelated +mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize() +to remove all pages from the pagecache, any subsequent access to the orphan +VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio +does not implement read_folio, this results in a NULL pointer dereference. + +[FIX] +Note that expanding mremap (new_len > old_len) is already rejected because +AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is +a partial move where "old_len == new_len" but both are smaller than the +full ring size. + +Fix this by checking in aio_ring_mremap() that the new VMA covers the +entire ring. This ensures the AIO ring is always moved as a whole, +preventing orphan VMAs and the subsequent crash. + +[1]: https://lore.kernel.org/all/20260413010814.548568-1-wozizhi@huawei.com/ + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260418060634.3713620-1-wozizhi@huaweicloud.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 6d436f8b3f349..b8a163d90bfaf 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + + ctx = rcu_dereference(table->table[i]); + if (ctx && ctx->aio_ring_file == file) { +- if (!atomic_read(&ctx->dead)) { ++ if (!atomic_read(&ctx->dead) && ++ (ctx->mmap_size == (vma->vm_end - vma->vm_start))) { + ctx->user_id = ctx->mmap_base = vma->vm_start; + res = 0; + } +-- +2.53.0 + diff --git a/queue-7.0/fs-aio-set-vma_dontcopy_bit-in-mmap-to-fix-null-poin.patch b/queue-7.0/fs-aio-set-vma_dontcopy_bit-in-mmap-to-fix-null-poin.patch new file mode 100644 index 0000000000..feed4a8a69 --- /dev/null +++ b/queue-7.0/fs-aio-set-vma_dontcopy_bit-in-mmap-to-fix-null-poin.patch @@ -0,0 +1,93 @@ +From 59b78ee0de610d76ee73c8d46d8bcec6c82435b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:08:14 +0800 +Subject: fs: aio: set VMA_DONTCOPY_BIT in mmap to fix NULL-pointer-dereference + error + +From: Zizhi Wo + +[ Upstream commit c03ce4173c7bffe1e7477f905a09b015d4000d3c ] + +[BUG] +Recently, our internal syzkaller testing uncovered a null pointer +dereference issue: +BUG: kernel NULL pointer dereference, address: 0000000000000000 +... +[ 51.111664] filemap_read_folio+0x25/0xe0 +[ 51.112410] filemap_fault+0xad7/0x1250 +[ 51.113112] __do_fault+0x4b/0x460 +[ 51.113699] do_pte_missing+0x5bc/0x1db0 +[ 51.114250] ? __pte_offset_map+0x23/0x170 +[ 51.114822] __handle_mm_fault+0x9f8/0x1680 +[ 51.115408] handle_mm_fault+0x24c/0x570 +[ 51.115958] do_user_addr_fault+0x226/0xa50 +... +Crash analysis showed the file involved was an AIO ring file. + +[CAUSE] + PARENT process CHILD process +t=0 io_setup(1, &ctx) + [access ctx addr] + fork() + io_destroy + vm_munmap // not affect child vma + percpu_ref_put + ... + put_aio_ring_file +t=1 [access ctx addr] // pagefault + ... + __do_fault + filemap_fault + max_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE) +t=2 truncate_setsize + truncate_pagecache +t=3 filemap_get_folio // no folio, create folio + __filemap_get_folio(..., FGP_CREAT, ...) // page_not_uptodate + filemap_read_folio(file, mapping->a_ops->read_folio, folio) // oops! + +At t=0, the parent process calls io_setup and then fork. The child process +gets its own VMA but without any PTEs. The parent then calls io_destroy. +Before i_size is truncated to 0, at t=1 the child process accesses this AIO +ctx address and triggers a pagefault. After the max_idx check passes, at +t=2 the parent calls truncate_setsize and truncate_pagecache. At t=3 the +child fails to obtain the folio, falls into the "page_not_uptodate" path, +and hits this problem because AIO does not implement "read_folio". + +[Fix] +Fix this by marking the AIO ring buffer VMA with VM_DONTCOPY so +that fork()'s dup_mmap() skips it entirely. This is the correct +semantic because: + +1) The child's ioctx_table is already reset to NULL by mm_init_aio() during +fork(), so the child has no AIO context and no way to perform any AIO +operations on this mapping. +2) The AIO ring VMA is only meaningful in conjunction with its associated +kioctx, which is never inherited across fork(). So child process with no +AIO context has no legitimate reason to access the ring buffer. Delivering +SIGSEGV on such an erroneous access is preferable to a kernel crash. + +Signed-off-by: Zizhi Wo +Link: https://patch.msgid.link/20260413010814.548568-1-wozizhi@huawei.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/aio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/aio.c b/fs/aio.c +index a07bdd1aaaa60..6d436f8b3f349 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -394,7 +394,7 @@ static const struct vm_operations_struct aio_ring_vm_ops = { + + static int aio_ring_mmap_prepare(struct vm_area_desc *desc) + { +- vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT); ++ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT, VMA_DONTCOPY_BIT); + desc->vm_ops = &aio_ring_vm_ops; + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/fs-fix-forced-iversion-increment-on-lazytime-timesta.patch b/queue-7.0/fs-fix-forced-iversion-increment-on-lazytime-timesta.patch new file mode 100644 index 0000000000..9ba88f1caa --- /dev/null +++ b/queue-7.0/fs-fix-forced-iversion-increment-on-lazytime-timesta.patch @@ -0,0 +1,62 @@ +From b4edd363cb3986d5e3262351289bdfbb74d44ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 13:19:18 +0200 +Subject: fs: fix forced iversion increment on lazytime timestamp updates + +From: Pankaj Raghav + +[ Upstream commit 834e98acb748025c04fed3cac9c8954454f4b520 ] + +When updating timestamps with lazytime enabled, if only I_DIRTY_TIME is +set (pure lazytime update), inode_maybe_inc_iversion() should not be +forced to increment i_version. The force parameter should only be true +when actual data or metadata changes require an iversion bump. + +The current code uses "!!dirty" which evaluates to true whenever dirty +has any bits set, including the I_DIRTY_TIME bit alone. This forces an +iversion increment on every lazytime timestamp update, which then sets +I_DIRTY_SYNC, triggering expensive log flushes on subsequent fdatasync +calls. Andres reported this issue when he noticed a perf regression[1]. + +Fix this by using "dirty != I_DIRTY_TIME" as the force parameter. This +passes false for pure lazytime updates (allowing the I_VERSION_QUERIED +optimization to work), while still forcing the increment when dirty +contains other flags indicating real changes that require iversion +updates. + +[1] https://lore.kernel.org/linux-xfs/7ys6erh3nnyeerv2nybyfvp7dmaknuxrlxv74wx56ocdothkc6@ekfiadtkfn2r/ + +Fixes: 85c871a02b03 ("fs: add support for non-blocking timestamp updates") +Signed-off-by: Pankaj Raghav +Link: https://patch.msgid.link/20260511111918.1793689-1-p.raghav@samsung.com +Reviewed-by: Jeff Layton +Reviewed-by: Christoph Hellwig +Reviewed-by: Carlos Maiolino +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/inode.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/inode.c b/fs/inode.c +index cc12b68e021b2..e10439d8d7d98 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -2130,7 +2130,13 @@ static int inode_update_cmtime(struct inode *inode, unsigned int flags) + inode_iversion_need_inc(inode)) + return -EAGAIN; + } else { +- if (inode_maybe_inc_iversion(inode, !!dirty)) ++ /* ++ * Don't force iversion increment for pure lazytime ++ * updates (I_DIRTY_TIME only), let I_VERSION_QUERIED ++ * dictate whether the increment is needed. ++ */ ++ if (inode_maybe_inc_iversion(inode, ++ dirty != I_DIRTY_TIME)) + dirty |= I_DIRTY_SYNC; + } + } +-- +2.53.0 + diff --git a/queue-7.0/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch b/queue-7.0/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch new file mode 100644 index 0000000000..a887e56c73 --- /dev/null +++ b/queue-7.0/fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch @@ -0,0 +1,55 @@ +From 9cc5b86dc38ae7a626da76479647ffe59781302c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 May 2026 15:10:58 +0800 +Subject: fs: Fix return in jfs_mkdir and orangefs_mkdir + +From: Hongling Zeng + +[ Upstream commit a7cf1da7ac016490d6a1106f2aa6b602d34e9a12 ] + +Return NULL instead of passing to ERR_PTR while err is zero +Fixes these smatch warnings: + - fs/jfs/namei.c:311 jfs_mkdir() warn: passing zero to 'ERR_PTR' + - fs/orangefs/namei.c:369 orangefs_mkdir() warn: passing zero + to 'ERR_PTR' + +Fixes: 88d5baf69082 ("Change inode_operations.mkdir to return struct dentry *") +Signed-off-by: Hongling Zeng +Link: https://patch.msgid.link/20260501071058.1243245-1-zenghongling@kylinos.cn +Reviewed-by: Jori Koolstra +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/jfs/namei.c | 2 +- + fs/orangefs/namei.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c +index 60c4a0e0fca5e..442d626792622 100644 +--- a/fs/jfs/namei.c ++++ b/fs/jfs/namei.c +@@ -309,7 +309,7 @@ static struct dentry *jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip, + out1: + + jfs_info("jfs_mkdir: rc:%d", rc); +- return ERR_PTR(rc); ++ return rc ? ERR_PTR(rc) : NULL; + } + + /* +diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c +index bec5475de094d..75e65e72c2d64 100644 +--- a/fs/orangefs/namei.c ++++ b/fs/orangefs/namei.c +@@ -362,7 +362,7 @@ static struct dentry *orangefs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + __orangefs_setattr(dir, &iattr); + out: + op_release(new_op); +- return ERR_PTR(ret); ++ return ret ? ERR_PTR(ret) : NULL; + } + + static int orangefs_rename(struct mnt_idmap *idmap, +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-fix-lxdev-xattr-lookup.patch b/queue-7.0/fs-ntfs3-fix-lxdev-xattr-lookup.patch new file mode 100644 index 0000000000..54a35ba846 --- /dev/null +++ b/queue-7.0/fs-ntfs3-fix-lxdev-xattr-lookup.patch @@ -0,0 +1,35 @@ +From 8acffd1bb1cac385a8dd910f7a82b05f7b551564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:24:54 +0800 +Subject: fs/ntfs3: fix $LXDEV xattr lookup + +From: Zhan Xusheng + +[ Upstream commit bb82fe0872de867f87fd4f64c9cb157903ac78db ] + +Use correct xattr name ("$LXDEV") and buffer size when calling +ntfs_get_ea(), otherwise the attribute may not be read. + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/xattr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c +index 3fffda7848922..9eeac0ab2b714 100644 +--- a/fs/ntfs3/xattr.c ++++ b/fs/ntfs3/xattr.c +@@ -1031,7 +1031,7 @@ void ntfs_get_wsl_perm(struct inode *inode) + i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); + inode->i_mode = le32_to_cpu(value[2]); + +- if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, ++ if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, + &value[0], sizeof(value), + &sz) == sizeof(value[0])) { + inode->i_rdev = le32_to_cpu(value[0]); +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch b/queue-7.0/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch new file mode 100644 index 0000000000..a8e379796f --- /dev/null +++ b/queue-7.0/fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch @@ -0,0 +1,48 @@ +From ec24c2f4351725618551a3c7eb735735abc44a7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:12:32 +0800 +Subject: fs/ntfs3: fix potential double iput on d_make_root() failure + +From: Zhan Xusheng + +[ Upstream commit d1062683bf6b560b31f287eb0ebde4841bc72376 ] + +d_make_root() consumes the reference to the passed inode: it either +attaches it to the newly created dentry on success, or drops it via +iput() on failure. + +In the error path, the code currently does: + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto put_inode_out; + +which leads to a second iput(inode) in put_inode_out. This results in +a double iput and may trigger a use-after-free if the inode gets freed +after the first iput(). + +Fix this by jumping directly to the common cleanup path, avoiding the +extra iput(inode). + +Signed-off-by: Zhan Xusheng +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 9ed485f9efbae..00a5a33fc46b7 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1678,7 +1678,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; +- goto put_inode_out; ++ goto out; + } + + if (boot2) { +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-increase-client_rec-name-field-size.patch b/queue-7.0/fs-ntfs3-increase-client_rec-name-field-size.patch new file mode 100644 index 0000000000..1a52ce53f2 --- /dev/null +++ b/queue-7.0/fs-ntfs3-increase-client_rec-name-field-size.patch @@ -0,0 +1,40 @@ +From 222dde6078eb20b84d537a2f283755da6664b4eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 14:29:26 +0100 +Subject: fs/ntfs3: increase CLIENT_REC name field size + +From: Konstantin Komarov + +[ Upstream commit 81ad9e67eccc0b094a6eef55a19ee56c761416dc ] + +This patch increases the size of the CLIENT_REC name field from 32 utf-16 +chars to 64 utf-16 chars. It fixes the buffer overflow problem in +log_replay() reported by Robbert Morris. + +Reported-by: +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/fslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c +index 037df47fa9f3a..acfa18b84401e 100644 +--- a/fs/ntfs3/fslog.c ++++ b/fs/ntfs3/fslog.c +@@ -45,10 +45,10 @@ struct CLIENT_REC { + __le16 seq_num; // 0x14: + u8 align[6]; // 0x16: + __le32 name_bytes; // 0x1C: In bytes. +- __le16 name[32]; // 0x20: Name of client. ++ __le16 name[64]; // 0x20: Name of client. + }; + +-static_assert(sizeof(struct CLIENT_REC) == 0x60); ++static_assert(sizeof(struct CLIENT_REC) == 0xa0); + + /* Two copies of these will exist at the beginning of the log file */ + struct RESTART_AREA { +-- +2.53.0 + diff --git a/queue-7.0/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch b/queue-7.0/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch new file mode 100644 index 0000000000..7ed036d58a --- /dev/null +++ b/queue-7.0/fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch @@ -0,0 +1,49 @@ +From 318fdbc831694812f90e874f7eb1ca3c425c5560 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 May 2026 20:26:49 +0900 +Subject: fs/statmount: fix slab out-of-bounds write in statmount_mnt_idmap + +From: Junyoung Jang + +[ Upstream commit a3bf0f28d4ba16e1f35f8c983bb04426b87e2a78 ] + +statmount_mnt_idmap() writes one mapping with seq_printf() and then +manually advances seq->count to include the NUL separator. + +If seq_printf() overflows, seq_set_overflow() sets seq->count to +seq->size. The manual seq->count++ changes this to seq->size + 1. +seq_has_overflowed() then no longer detects the overflow. The corrupted +count returns to statmount_string(), which later executes: + + seq->buf[seq->count++] = '\0'; + +This causes a 1-byte NULL out-of-bounds write on the dynamically +allocated seq buffer. + +Fix this by checking for overflow immediately after seq_printf(). + +Fixes: 37c4a9590e1e ("statmount: allow to retrieve idmappings") +Signed-off-by: Junyoung Jang +Link: https://patch.msgid.link/20260504112649.1862936-1-graypanda.inzag@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/mnt_idmapping.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/mnt_idmapping.c b/fs/mnt_idmapping.c +index 6472c4ea3d1e6..cb61fbdb52e90 100644 +--- a/fs/mnt_idmapping.c ++++ b/fs/mnt_idmapping.c +@@ -375,6 +375,8 @@ int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_ + continue; + + seq_printf(seq, "%u %u %u", extent->first, lower, extent->count); ++ if (seq_has_overflowed(seq)) ++ return -EAGAIN; + + seq->count++; /* mappings are separated by \0 */ + if (seq_has_overflowed(seq)) +-- +2.53.0 + diff --git a/queue-7.0/fuse-fix-inode-initialization-race.patch b/queue-7.0/fuse-fix-inode-initialization-race.patch new file mode 100644 index 0000000000..e72773e0fa --- /dev/null +++ b/queue-7.0/fuse-fix-inode-initialization-race.patch @@ -0,0 +1,63 @@ +From 573713b1261525a862e44429db6cb6fd58780efc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 18:28:54 +0100 +Subject: fuse: fix inode initialization race + +From: Horst Birthelmer + +[ Upstream commit aff12041b4b2f4f2c164a0cf1b9688408515d036 ] + +Fix a race between fuse_iget() and fuse_reverse_inval_inode() where +invalidation can arrive while an inode is being initialized, causing +the invalidation to be lost. +By keeping the inode state I_NEW as long as the attributes are not valid +the invalidation can wait until the inode is fully initialized. + +Suggested-by: Joanne Koong +Signed-off-by: Horst Birthelmer +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/inode.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c +index bc05c9479f571..6481f754822b4 100644 +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -470,6 +470,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, + struct inode *inode; + struct fuse_inode *fi; + struct fuse_conn *fc = get_fuse_conn_super(sb); ++ bool is_new_inode = false; + + /* + * Auto mount points get their node id from the submount root, which is +@@ -505,13 +506,13 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, + if (!inode) + return NULL; + +- if ((inode_state_read_once(inode) & I_NEW)) { ++ is_new_inode = inode_state_read_once(inode) & I_NEW; ++ if (is_new_inode) { + inode->i_flags |= S_NOATIME; + if (!fc->writeback_cache || !S_ISREG(attr->mode)) + inode->i_flags |= S_NOCMTIME; + inode->i_generation = generation; + fuse_init_inode(inode, attr, fc); +- unlock_new_inode(inode); + } else if (fuse_stale_inode(inode, generation, attr)) { + /* nodeid was reused, any I/O on the old inode should fail */ + fuse_make_bad(inode); +@@ -528,6 +529,8 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, + done: + fuse_change_attributes_i(inode, attr, NULL, attr_valid, attr_version, + evict_ctr); ++ if (is_new_inode) ++ unlock_new_inode(inode); + return inode; + } + +-- +2.53.0 + diff --git a/queue-7.0/fuse-mark-dax-inode-releases-as-blocking.patch b/queue-7.0/fuse-mark-dax-inode-releases-as-blocking.patch new file mode 100644 index 0000000000..8bf965b3eb --- /dev/null +++ b/queue-7.0/fuse-mark-dax-inode-releases-as-blocking.patch @@ -0,0 +1,77 @@ +From c55f73080244ea6842288da47808863d42897bb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 00:24:11 +0100 +Subject: fuse: mark DAX inode releases as blocking + +From: Sergio Lopez + +[ Upstream commit 42fbb31310b2c145308d3cdcb32d8f05998cfd6c ] + +Commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from +fuseblk workers") made fputs on closing files always asynchronous. + +As cleaning up DAX inodes may require issuing a number of synchronous +request for releasing the mappings, completing the release request from +the worker thread may lead to it hanging like this: + +[ 21.386751] Workqueue: events virtio_fs_requests_done_work +[ 21.386769] Call trace: +[ 21.386770] __switch_to+0xe4/0x140 +[ 21.386780] __schedule+0x294/0x72c +[ 21.386787] schedule+0x24/0x90 +[ 21.386794] request_wait_answer+0x184/0x298 +[ 21.386799] __fuse_simple_request+0x1f4/0x320 +[ 21.386805] fuse_send_removemapping+0x80/0xa0 +[ 21.386810] dmap_removemapping_list+0xac/0xfc +[ 21.386814] inode_reclaim_dmap_range.constprop.0+0xd0/0x204 +[ 21.386820] fuse_dax_inode_cleanup+0x28/0x5c +[ 21.386825] fuse_evict_inode+0x120/0x190 +[ 21.386834] evict+0x188/0x320 +[ 21.386847] iput_final+0xb0/0x20c +[ 21.386854] iput+0xa0/0xbc +[ 21.386862] fuse_release_end+0x18/0x2c +[ 21.386868] fuse_request_end+0x9c/0x2c0 +[ 21.386872] virtio_fs_request_complete+0x150/0x384 +[ 21.386879] virtio_fs_requests_done_work+0x18c/0x37c +[ 21.386885] process_one_work+0x15c/0x2e8 +[ 21.386891] worker_thread+0x278/0x480 +[ 21.386898] kthread+0xd0/0xdc +[ 21.386902] ret_from_fork+0x10/0x20 + +Here, the virtio-fs worker_thread is waiting on request_wait_answer() +for a reply from the virtio-fs server that is already in the virtqueue +but will never be processed since it's that same worker thread the one +in charge of consuming the elements from the virtqueue. + +To address this issue, when relesing a DAX inode mark the operation as +potentially blocking. Doing this will ensure these release requests are +processed on a different worker thread. + +Signed-off-by: Sergio Lopez +Reviewed-by: Darrick J. Wong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 676fd9856bfbf..14740134faff7 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -117,6 +117,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { ++ /* ++ * DAX inodes may need to issue a number of synchronous ++ * request for clearing the mappings. ++ */ ++ if (ra && ra->inode && FUSE_IS_DAX(ra->inode)) ++ args->may_block = true; + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) +-- +2.53.0 + diff --git a/queue-7.0/fuse-validate-outarg-offset-and-size-in-notify-store.patch b/queue-7.0/fuse-validate-outarg-offset-and-size-in-notify-store.patch new file mode 100644 index 0000000000..ed8f1194f2 --- /dev/null +++ b/queue-7.0/fuse-validate-outarg-offset-and-size-in-notify-store.patch @@ -0,0 +1,81 @@ +From 38e0a9ca8be15780d904baa60fb8c98706c5b4e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 14:44:46 -0800 +Subject: fuse: validate outarg offset and size in notify store/retrieve + +From: Joanne Koong + +[ Upstream commit 65161470f95bb579a72673bf303ecf0800b9054b ] + +Add validation checking for outarg offset and outarg size values passed +in by the server. MAX_LFS_FILESIZE is the maximum file size supported. +The fuse_notify_store_out and fuse_notify_retrieve_out structs take in +a uint64_t offset. + +Add logic to ensure: +* outarg.offset is less than MAX_LFS_FILESIZE +* outarg.offset + outarg.size cannot exceed MAX_LFS_FILESIZE +* potential uint64_t overflow is fixed when adding outarg.offset and + outarg.size. + +Signed-off-by: Joanne Koong +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index 24ee9e8702637..1d191e1d2ad65 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1789,7 +1789,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + if (size - sizeof(outarg) != outarg.size) + return -EINVAL; + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + nodeid = outarg.nodeid; ++ num = min(outarg.size, MAX_LFS_FILESIZE - outarg.offset); + + down_read(&fc->killsb); + +@@ -1802,13 +1806,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, + index = outarg.offset >> PAGE_SHIFT; + offset = outarg.offset & ~PAGE_MASK; + file_size = i_size_read(inode); +- end = outarg.offset + outarg.size; ++ end = outarg.offset + num; + if (end > file_size) { + file_size = end; +- fuse_write_update_attr(inode, file_size, outarg.size); ++ fuse_write_update_attr(inode, file_size, num); + } + +- num = outarg.size; + while (num) { + struct folio *folio; + unsigned int folio_offset; +@@ -1888,7 +1891,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode, + num = min(outarg->size, fc->max_write); + if (outarg->offset > file_size) + num = 0; +- else if (outarg->offset + num > file_size) ++ else if (num > file_size - outarg->offset) + num = file_size - outarg->offset; + + num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -1970,6 +1973,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, + + fuse_copy_finish(cs); + ++ if (outarg.offset >= MAX_LFS_FILESIZE) ++ return -EINVAL; ++ + down_read(&fc->killsb); + err = -ENOENT; + nodeid = outarg.nodeid; +-- +2.53.0 + diff --git a/queue-7.0/gcc-plugins-always-define-const_cast_gimple-and-cons.patch b/queue-7.0/gcc-plugins-always-define-const_cast_gimple-and-cons.patch new file mode 100644 index 0000000000..e4ed34658e --- /dev/null +++ b/queue-7.0/gcc-plugins-always-define-const_cast_gimple-and-cons.patch @@ -0,0 +1,45 @@ +From 6f7504cc80bc5aa59a69d765e6bfbda56fb2b6f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 14:24:56 +0100 +Subject: gcc-plugins: Always define CONST_CAST_GIMPLE and CONST_CAST_TREE + +From: Kees Cook + +[ Upstream commit 905c559e51497b8bfdbb68df8be56d2f70f0de8e ] + +For gcc-16, the CONST_CAST macro family was removed. Add back what +we were using in gcc-common.h, as they are simple wrappers. + +See GCC commits: + c3d96ff9e916c02584aa081f03ab999292efbb50 + 458c7926d48959abcb2c1adaa22458e27459a551 + +Suggested-by: Ingo Saitz +Link: https://lore.kernel.org/lkml/ab6OKoay0OWkywjK@spatz.zoo +Fixes: 6b90bd4ba40b ("GCC plugin infrastructure") +Tested-by: Ivan Bulatovic +Tested-by: Christopher Cradock +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + scripts/gcc-plugins/gcc-common.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h +index 8f1b3500f8e2d..abb1964c44d4e 100644 +--- a/scripts/gcc-plugins/gcc-common.h ++++ b/scripts/gcc-plugins/gcc-common.h +@@ -309,7 +309,9 @@ typedef const gimple *const_gimple_ptr; + #define gimple gimple_ptr + #define const_gimple const_gimple_ptr + #undef CONST_CAST_GIMPLE +-#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X)) ++#define CONST_CAST_GIMPLE(X) const_cast((X)) ++#undef CONST_CAST_TREE ++#define CONST_CAST_TREE(X) const_cast((X)) + + /* gimple related */ + static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL) +-- +2.53.0 + diff --git a/queue-7.0/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..7b111447c1 --- /dev/null +++ b/queue-7.0/gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From af6ca237311e3e7467ff38ac12086422ec2a441c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:50 -0800 +Subject: gpio: bd9571mwv: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c43778680546dd379b3d8219c177b1a34ba87002 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by bd9571mwv_gpio_get() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-1-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-bd9571mwv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c +index 7c95bb36511e1..cc5b1746f2fe8 100644 +--- a/drivers/gpio/gpio-bd9571mwv.c ++++ b/drivers/gpio/gpio-bd9571mwv.c +@@ -69,7 +69,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset); ++ return !!(val & BIT(offset)); + } + + static int bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-7.0/gpio-cgbc-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-cgbc-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..eb3c63dcec --- /dev/null +++ b/queue-7.0/gpio-cgbc-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,39 @@ +From b9cd654e7f177b1618417e4f7441b8320ef5f641 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:51 -0800 +Subject: gpio: cgbc: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 49621f1c97788216f2f10f1a9e903f216e289f5d ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by cgbc_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-2-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-cgbc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-cgbc.c b/drivers/gpio/gpio-cgbc.c +index 0efa1b61001ad..84b5ed3c6e22b 100644 +--- a/drivers/gpio/gpio-cgbc.c ++++ b/drivers/gpio/gpio-cgbc.c +@@ -47,8 +47,8 @@ static int cgbc_gpio_get(struct gpio_chip *chip, unsigned int offset) + + if (ret) + return ret; +- else +- return (int)(val & (u8)BIT(offset)); ++ ++ return !!(val & BIT(offset)); + } + + static int __cgbc_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-7.0/gpio-da9055-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-da9055-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..d4878d92e2 --- /dev/null +++ b/queue-7.0/gpio-da9055-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From d9c86a7d6b91be210043fb6f89144e247364bfdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:52 -0800 +Subject: gpio: da9055: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 4d720b0d68e9a251d60804eace42aac800d7a79f ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by da9055_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-3-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-da9055.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c +index a09bd6eb93cfb..1949a6ea8ec61 100644 +--- a/drivers/gpio/gpio-da9055.c ++++ b/drivers/gpio/gpio-da9055.c +@@ -55,7 +55,7 @@ static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) + return ret; + } + +- return ret & (1 << offset); ++ return !!(ret & (1 << offset)); + + } + +-- +2.53.0 + diff --git a/queue-7.0/gpio-lp873x-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-lp873x-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..3dec20ae99 --- /dev/null +++ b/queue-7.0/gpio-lp873x-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 9f7f4ff1273eb1e9f846959338c895d6f037862d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:53 -0800 +Subject: gpio: lp873x: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5a32ebabb6819fafce99e7bc6575ca568af6d22a ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by lp873x_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-4-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-lp873x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c +index 5376708a81bfe..f4413fa5a8110 100644 +--- a/drivers/gpio/gpio-lp873x.c ++++ b/drivers/gpio/gpio-lp873x.c +@@ -55,7 +55,7 @@ static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) + if (ret < 0) + return ret; + +- return val & BIT(offset * BITS_PER_GPO); ++ return !!(val & BIT(offset * BITS_PER_GPO)); + } + + static int lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-7.0/gpio-tps65086-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-tps65086-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..71e9abd03a --- /dev/null +++ b/queue-7.0/gpio-tps65086-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 77849c0fe107d5bf9a9dbf35782aef31ca1370f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:55 -0800 +Subject: gpio: tps65086: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 9eb7ecfd20f868421e44701274896ba9e136daae ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by tps65086_gpio_get() is normalized +to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-6-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-tps65086.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c +index 84b17b83476f5..df770ecf28bc4 100644 +--- a/drivers/gpio/gpio-tps65086.c ++++ b/drivers/gpio/gpio-tps65086.c +@@ -50,7 +50,7 @@ static int tps65086_gpio_get(struct gpio_chip *chip, unsigned offset) + if (ret < 0) + return ret; + +- return val & BIT(4 + offset); ++ return !!(val & BIT(4 + offset)); + } + + static int tps65086_gpio_set(struct gpio_chip *chip, unsigned int offset, +-- +2.53.0 + diff --git a/queue-7.0/gpio-viperboard-normalize-return-value-of-gpio_get.patch b/queue-7.0/gpio-viperboard-normalize-return-value-of-gpio_get.patch new file mode 100644 index 0000000000..e9d4787f72 --- /dev/null +++ b/queue-7.0/gpio-viperboard-normalize-return-value-of-gpio_get.patch @@ -0,0 +1,37 @@ +From 22f740845137d7514f8a9026f09ede7ea7645d77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:06:56 -0800 +Subject: gpio: viperboard: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit c08381ad56a9cc111f893b2b21400ceb468cc698 ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by vprbrd_gpiob_get() in the output +case is normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260218190657.2974723-7-dmitry.torokhov@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-viperboard.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c +index 15e495c109d2a..89087fd48a819 100644 +--- a/drivers/gpio/gpio-viperboard.c ++++ b/drivers/gpio/gpio-viperboard.c +@@ -288,7 +288,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip, + + /* if io is set to output, just return the saved value */ + if (gpio->gpiob_out & (1 << offset)) +- return gpio->gpiob_val & (1 << offset); ++ return !!(gpio->gpiob_val & (1 << offset)); + + mutex_lock(&vb->lock); + +-- +2.53.0 + diff --git a/queue-7.0/gve-advertise-netif_f_gro_hw-instead-of-netif_f_lro.patch b/queue-7.0/gve-advertise-netif_f_gro_hw-instead-of-netif_f_lro.patch new file mode 100644 index 0000000000..70f264ef79 --- /dev/null +++ b/queue-7.0/gve-advertise-netif_f_gro_hw-instead-of-netif_f_lro.patch @@ -0,0 +1,89 @@ +From 29af6ec90e8d5c973a612cee4785bad441fd2f3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:46 -0800 +Subject: gve: Advertise NETIF_F_GRO_HW instead of NETIF_F_LRO + +From: Ankit Garg + +[ Upstream commit e637c244b954426b84340cbc551ca0e2a32058ce ] + +The device behind DQO format has always coalesced packets per stricter +hardware GRO spec even though it was being advertised as LRO. + +Update advertised capability to match device behavior. + +Signed-off-by: Ankit Garg +Reviewed-by: Willem de Bruijn +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-2-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_adminq.c | 6 +++--- + drivers/net/ethernet/google/gve/gve_main.c | 15 ++++++++------- + 2 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c +index b72cc0fa2ba2b..873672f680e3a 100644 +--- a/drivers/net/ethernet/google/gve/gve_adminq.c ++++ b/drivers/net/ethernet/google/gve/gve_adminq.c +@@ -791,7 +791,7 @@ static void gve_adminq_get_create_rx_queue_cmd(struct gve_priv *priv, + cmd->create_rx_queue.rx_buff_ring_size = + cpu_to_be16(priv->rx_desc_cnt); + cmd->create_rx_queue.enable_rsc = +- !!(priv->dev->features & NETIF_F_LRO); ++ !!(priv->dev->features & NETIF_F_GRO_HW); + if (priv->header_split_enabled) + cmd->create_rx_queue.header_buffer_size = + cpu_to_be16(priv->header_buf_size); +@@ -1127,9 +1127,9 @@ int gve_adminq_describe_device(struct gve_priv *priv) + + gve_set_default_rss_sizes(priv); + +- /* DQO supports LRO. */ ++ /* DQO supports HW-GRO. */ + if (!gve_is_gqi(priv)) +- priv->dev->hw_features |= NETIF_F_LRO; ++ priv->dev->hw_features |= NETIF_F_GRO_HW; + + priv->max_registered_pages = + be64_to_cpu(descriptor->max_registered_pages); +diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c +index 9eb4b3614c4f5..9cae4fc88a2ff 100644 +--- a/drivers/net/ethernet/google/gve/gve_main.c ++++ b/drivers/net/ethernet/google/gve/gve_main.c +@@ -1717,9 +1717,9 @@ static int gve_verify_xdp_configuration(struct net_device *dev, + struct gve_priv *priv = netdev_priv(dev); + u16 max_xdp_mtu; + +- if (dev->features & NETIF_F_LRO) { ++ if (dev->features & NETIF_F_GRO_HW) { + NL_SET_ERR_MSG_MOD(extack, +- "XDP is not supported when LRO is on."); ++ "XDP is not supported when HW-GRO is on."); + return -EOPNOTSUPP; + } + +@@ -2136,12 +2136,13 @@ static int gve_set_features(struct net_device *netdev, + + gve_get_curr_alloc_cfgs(priv, &tx_alloc_cfg, &rx_alloc_cfg); + +- if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) { +- netdev->features ^= NETIF_F_LRO; +- if (priv->xdp_prog && (netdev->features & NETIF_F_LRO)) { ++ if ((netdev->features & NETIF_F_GRO_HW) != ++ (features & NETIF_F_GRO_HW)) { ++ netdev->features ^= NETIF_F_GRO_HW; ++ if (priv->xdp_prog && (netdev->features & NETIF_F_GRO_HW)) { + netdev_warn(netdev, +- "XDP is not supported when LRO is on.\n"); +- err = -EOPNOTSUPP; ++ "HW-GRO is not supported when XDP is on."); ++ err = -EOPNOTSUPP; + goto revert_features; + } + if (netif_running(netdev)) { +-- +2.53.0 + diff --git a/queue-7.0/gve-fix-sw-coalescing-when-hw-gro-is-used.patch b/queue-7.0/gve-fix-sw-coalescing-when-hw-gro-is-used.patch new file mode 100644 index 0000000000..d069af4811 --- /dev/null +++ b/queue-7.0/gve-fix-sw-coalescing-when-hw-gro-is-used.patch @@ -0,0 +1,81 @@ +From 6bd33244140d9b3cdfbc5814c1f53169d80751d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:55:47 -0800 +Subject: gve: fix SW coalescing when hw-GRO is used + +From: Ankit Garg + +[ Upstream commit ea4c1176871fd70a06eadcbd7c828f6cb9a1b0cd ] + +Leaving gso_segs unpopulated on hardware GRO packet prevents further +coalescing by software stack because the kernel's GRO logic marks the +SKB for flush because the expected length of all segments doesn't match +actual payload length. + +Setting gso_segs correctly results in significantly more segments being +coalesced as measured by the result of dev_gro_receive(). + +gso_segs are derived from payload length. When header-split is enabled, +payload is in the non-linear portion of skb. And when header-split is +disabled, we have to parse the headers to determine payload length. + +Signed-off-by: Ankit Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Jordan Rhee +Reviewed-by: Harshitha Ramamurthy +Signed-off-by: Joshua Washington +Link: https://patch.msgid.link/20260303195549.2679070-3-joshwash@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 23 ++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index c706c79321594..cf69570f4d57a 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -944,11 +944,16 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + struct gve_ptype ptype) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int rsc_segments, rsc_seg_len, hdr_len; + +- /* Only TCP is supported right now. */ ++ /* HW-GRO only coalesces TCP. */ + if (ptype.l4_type != GVE_L4_TYPE_TCP) + return -EINVAL; + ++ rsc_seg_len = le16_to_cpu(desc->rsc_seg_len); ++ if (!rsc_seg_len) ++ return 0; ++ + switch (ptype.l3_type) { + case GVE_L3_TYPE_IPV4: + shinfo->gso_type = SKB_GSO_TCPV4; +@@ -960,7 +965,21 @@ static int gve_rx_complete_rsc(struct sk_buff *skb, + return -EINVAL; + } + +- shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len); ++ if (skb_headlen(skb)) { ++ /* With header-split, payload is in the non-linear part */ ++ rsc_segments = DIV_ROUND_UP(skb->data_len, rsc_seg_len); ++ } else { ++ /* HW-GRO packets are guaranteed to have complete TCP/IP ++ * headers in frag[0] when header-split is not enabled. ++ */ ++ hdr_len = eth_get_headlen(skb->dev, ++ skb_frag_address(&shinfo->frags[0]), ++ skb_frag_size(&shinfo->frags[0])); ++ rsc_segments = DIV_ROUND_UP(skb->len - hdr_len, rsc_seg_len); ++ } ++ shinfo->gso_size = rsc_seg_len; ++ shinfo->gso_segs = rsc_segments; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/hexagon-uapi-fix-structure-alignment-attribute.patch b/queue-7.0/hexagon-uapi-fix-structure-alignment-attribute.patch new file mode 100644 index 0000000000..ec42b07bf3 --- /dev/null +++ b/queue-7.0/hexagon-uapi-fix-structure-alignment-attribute.patch @@ -0,0 +1,43 @@ +From c91dbefb9a2098a918fdc360f687de2df2987fbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 07:37:59 +0100 +Subject: hexagon: uapi: Fix structure alignment attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 47bca1cbf692b89defbf4db27495813f82d5e3ff ] + +__aligned() is a kernel macro, which is not available in UAPI headers. + +Use the compiler-provided alignment attribute directly. + +Signed-off-by: Thomas Weißschuh +Acked-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Tested-by: Nicolas Schier +Link: https://patch.msgid.link/20260227-kbuild-uapi-libc-v1-1-c17de0d19776@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + arch/hexagon/include/uapi/asm/sigcontext.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/hexagon/include/uapi/asm/sigcontext.h b/arch/hexagon/include/uapi/asm/sigcontext.h +index 7171edb1b8b71..179a97041b593 100644 +--- a/arch/hexagon/include/uapi/asm/sigcontext.h ++++ b/arch/hexagon/include/uapi/asm/sigcontext.h +@@ -29,6 +29,6 @@ + */ + struct sigcontext { + struct user_regs_struct sc_regs; +-} __aligned(8); ++} __attribute__((aligned(8))); + + #endif +-- +2.53.0 + diff --git a/queue-7.0/hfsplus-fix-generic-642-failure.patch b/queue-7.0/hfsplus-fix-generic-642-failure.patch new file mode 100644 index 0000000000..4b81fe4849 --- /dev/null +++ b/queue-7.0/hfsplus-fix-generic-642-failure.patch @@ -0,0 +1,203 @@ +From efc2e05f4d74ae8c27aa4bbd25b10abbbbc5cdb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:05:56 -0700 +Subject: hfsplus: fix generic/642 failure + +From: Viacheslav Dubeyko + +[ Upstream commit c1307d18caa819ddc28459d858eb38fdd6c3f8a0 ] + +The xfstests' test-case generic/642 finishes with +corrupted HFS+ volume: + +sudo ./check generic/642 +[sudo] password for slavad: +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent +(see xfstests-dev/results//generic/642.full for details) + +Ran: generic/642 +Failures: generic/642 +Failed 1 of 1 tests + +sudo fsck.hfs -d /dev/loop51 +** /dev/loop51 +Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. +Executing fsck_hfs (version 540.1-Linux). +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +invalid free nodes - calculated 1637 header 1260 +Invalid B-tree header +Invalid map node +(8, 0) +** Checking volume bitmap. +** Checking volume information. +Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 +CBTStat = 0x0000 CatStat = 0x00000000 +** Repairing volume. +** Rechecking volume. +** Checking non-journaled HFS Plus Volume. +The volume name is untitled +** Checking extents overflow file. +** Checking catalog file. +** Checking multi-linked files. +** Checking catalog hierarchy. +** Checking extended attributes file. +** Checking volume bitmap. +** Checking volume information. +** The volume untitled was repaired successfully. + +The fsck tool detected that Extended Attributes b-tree is corrupted. +Namely, the free nodes number is incorrect and map node +bitmap has inconsistent state. Analysis has shown that during +b-tree closing there are still some lost b-tree's nodes in +the hash out of b-tree structure. But this orphaned b-tree nodes +are still accounted as used in map node bitmap: + +tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 +tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 +tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 +tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 +tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 +tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 + +This issue happens in hfs_bnode_split() logic during detection +the possibility of moving half ot the records out of the node. +The hfs_bnode_split() contains a loop that implements +a roughly 50/50 split of the B-tree node's records by scanning +the offset table to find where the data crosses the node's midpoint. +If this logic detects the incapability of spliting the node, then +it simply calls hfs_bnode_put() for newly created node. However, +node is not set as HFS_BNODE_DELETED and real deletion of node +doesn't happen. As a result, the empty node becomes orphaned but +it is still accounted as used. Finally, fsck tool detects this +inconsistency of HFS+ volume. + +This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() +for the case if new node cannot be used for spliting the existing +node. + +sudo ./check generic/642 +FSTYP -- hfsplus +PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 +MKFS_OPTIONS -- /dev/loop51 +MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch + +generic/642 40s ... 39s +Ran: generic/642 +Passed all 1 tests + +Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 +cc: John Paul Adrian Glaubitz +cc: Yangtao Li +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/hfsplus/brec.c | 32 ++++++++++++++++++++------------ + 1 file changed, 20 insertions(+), 12 deletions(-) + +diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c +index 6796c1a80e997..e3df89284079d 100644 +--- a/fs/hfsplus/brec.c ++++ b/fs/hfsplus/brec.c +@@ -239,6 +239,9 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + struct hfs_bnode_desc node_desc; + int num_recs, new_rec_off, new_off, old_rec_off; + int data_start, data_end, size; ++ size_t rec_off_tbl_size; ++ size_t node_desc_size = sizeof(struct hfs_bnode_desc); ++ size_t rec_size = sizeof(__be16); + + tree = fd->tree; + node = fd->bnode; +@@ -265,18 +268,22 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + return next_node; + } + +- size = tree->node_size / 2 - node->num_recs * 2 - 14; +- old_rec_off = tree->node_size - 4; ++ rec_off_tbl_size = node->num_recs * rec_size; ++ size = tree->node_size / 2; ++ size -= node_desc_size; ++ size -= rec_off_tbl_size; ++ old_rec_off = tree->node_size - (2 * rec_size); ++ + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, old_rec_off); + if (data_start > size) + break; +- old_rec_off -= 2; ++ old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; +- /* panic? */ + hfs_bnode_put(node); ++ hfs_bnode_unlink(new_node); + hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); +@@ -287,7 +294,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + /* new record is in the lower half, + * so leave some more space there + */ +- old_rec_off += 2; ++ old_rec_off += rec_size; + num_recs--; + data_start = hfs_bnode_read_u16(node, old_rec_off); + } else { +@@ -295,27 +302,28 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) + hfs_bnode_get(new_node); + fd->bnode = new_node; + fd->record -= num_recs; +- fd->keyoffset -= data_start - 14; +- fd->entryoffset -= data_start - 14; ++ fd->keyoffset -= data_start - node_desc_size; ++ fd->entryoffset -= data_start - node_desc_size; + } + new_node->num_recs = node->num_recs - num_recs; + node->num_recs = num_recs; + +- new_rec_off = tree->node_size - 2; +- new_off = 14; ++ new_rec_off = tree->node_size - rec_size; ++ new_off = node_desc_size; + size = data_start - new_off; + num_recs = new_node->num_recs; + data_end = data_start; + while (num_recs) { + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- old_rec_off -= 2; +- new_rec_off -= 2; ++ old_rec_off -= rec_size; ++ new_rec_off -= rec_size; + data_end = hfs_bnode_read_u16(node, old_rec_off); + new_off = data_end - size; + num_recs--; + } + hfs_bnode_write_u16(new_node, new_rec_off, new_off); +- hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); ++ hfs_bnode_copy(new_node, node_desc_size, ++ node, data_start, data_end - data_start); + + /* update new bnode header */ + node_desc.next = cpu_to_be32(new_node->next); +-- +2.53.0 + diff --git a/queue-7.0/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch b/queue-7.0/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch new file mode 100644 index 0000000000..30376127be --- /dev/null +++ b/queue-7.0/hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch @@ -0,0 +1,47 @@ +From 4c1a292b0afa38a7723084ff21868288be17c8b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 10:10:02 +0300 +Subject: HID: intel-thc-hid: Intel-quickspi: Fix some error codes + +From: Dan Carpenter + +[ Upstream commit ae4ac077332ea3341a0f4c0973556c6b7ac5b7a1 ] + +If we have a partial read that is supposed to be treated as failure but +in this code we forgot to set the error code. Return -EINVAL. + +Fixes: 9d8d51735a3a ("HID: intel-thc-hid: intel-quickspi: Add HIDSPI protocol implementation") +Signed-off-by: Dan Carpenter +Reviewed-by: Even Xu +Reviewed-by: Mark Pearson +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c +index 16f780bc879b1..cb19057f1191b 100644 +--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c ++++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c +@@ -94,7 +94,7 @@ static int quickspi_get_device_descriptor(struct quickspi_device *qsdev) + dev_err_once(qsdev->dev, "Read DEVICE_DESCRIPTOR failed, ret = %d\n", ret); + dev_err_once(qsdev->dev, "DEVICE_DESCRIPTOR expected len = %u, actual read = %u\n", + input_len, read_len); +- return ret; ++ return ret ?: -EINVAL; + } + + input_rep_type = ((struct input_report_body_header *)read_buf)->input_report_type; +@@ -318,7 +318,7 @@ int reset_tic(struct quickspi_device *qsdev) + dev_err_once(qsdev->dev, "Read RESET_RESPONSE body failed, ret = %d\n", ret); + dev_err_once(qsdev->dev, "RESET_RESPONSE body expected len = %u, actual = %u\n", + read_len, actual_read_len); +- return ret; ++ return ret ?: -EINVAL; + } + + input_rep_type = FIELD_GET(HIDSPI_IN_REP_BDY_HDR_REP_TYPE, reset_response); +-- +2.53.0 + diff --git a/queue-7.0/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch b/queue-7.0/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch new file mode 100644 index 0000000000..9a0b0e32c7 --- /dev/null +++ b/queue-7.0/hid-logitech-hidpp-check-bounds-when-deleting-force-.patch @@ -0,0 +1,56 @@ +From 7b3ef41c9ca0f5813e933216859258e7f2b26776 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:40:51 +0200 +Subject: HID: logitech-hidpp: Check bounds when deleting force-feedback + effects +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Günther Noack + +[ Upstream commit e606d8329be1e19b7eb3e0c6c72a73cbbb25ae3d ] + +Without this bounds check, this might otherwise overwrite index -1. + +Triggering this condition requires action both from the USB device and from +userspace, which reduces the scenarios in which it can be exploited. + +Cc: Lee Jones +Signed-off-by: Günther Noack +Reviewed-by: Lee Jones +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index e9aa99ade5aac..62f07aa7eee10 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -2502,12 +2502,15 @@ static void hidpp_ff_work_handler(struct work_struct *w) + } + break; + case HIDPP_FF_DESTROY_EFFECT: +- if (wd->effect_id >= 0) +- /* regular effect destroyed */ +- data->effect_ids[wd->params[0]-1] = -1; +- else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) +- /* autocenter spring destroyed */ +- data->slot_autocenter = 0; ++ slot = wd->params[0]; ++ if (slot > 0 && slot <= data->num_effects) { ++ if (wd->effect_id >= 0) ++ /* regular effect destroyed */ ++ data->effect_ids[slot-1] = -1; ++ else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) ++ /* autocenter spring destroyed */ ++ data->slot_autocenter = 0; ++ } + break; + case HIDPP_FF_SET_GLOBAL_GAINS: + data->gain = (wd->params[0] << 8) + wd->params[1]; +-- +2.53.0 + diff --git a/queue-7.0/hid-logitech-hidpp-fix-race-condition-when-accessing.patch b/queue-7.0/hid-logitech-hidpp-fix-race-condition-when-accessing.patch new file mode 100644 index 0000000000..3e0888d1f3 --- /dev/null +++ b/queue-7.0/hid-logitech-hidpp-fix-race-condition-when-accessing.patch @@ -0,0 +1,112 @@ +From 5db7a0054bef268be79ec426e39ea518ab644856 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:48:11 +0000 +Subject: HID: logitech-hidpp: fix race condition when accessing stale stack + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit e2aaf2d3ad92ac4a8afa6b69ad4c38e7747d3d6e ] + +The driver uses hidpp->send_receive_buf to point to a stack-allocated +buffer in the synchronous command path (__do_hidpp_send_message_sync). +However, this pointer is not cleared when the function returns. + +If an event is processed (e.g. by a different thread) while the +send_mutex is held by a new command, but before that command has +updated send_receive_buf, the handler (hidpp_raw_hidpp_event) will +observe that the mutex is locked and dereference the stale pointer. + +This results in an out-of-bounds access on a different thread's kernel +stack (or a NULL pointer dereference on the very first command). + +Fix this by: +1. Clearing hidpp->send_receive_buf to NULL before releasing the mutex + in the synchronous command path. +2. Moving the assignment of the local 'question' and 'answer' pointers + inside the mutex_is_locked() block in the handler, and adding + a NULL check before dereferencing. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-logitech-hidpp.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index 62f07aa7eee10..b3ff9265377b9 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -306,21 +306,22 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + if (ret) { + dbg_hid("__hidpp_send_report returned err: %d\n", ret); + memset(response, 0, sizeof(struct hidpp_report)); +- return ret; ++ goto out; + } + + if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, + 5*HZ)) { + dbg_hid("%s:timeout waiting for response\n", __func__); + memset(response, 0, sizeof(struct hidpp_report)); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + + if (response->report_id == REPORT_ID_HIDPP_SHORT && + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + + if ((response->report_id == REPORT_ID_HIDPP_LONG || +@@ -328,10 +329,14 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, + response->fap.feature_index == HIDPP20_ERROR) { + ret = response->fap.params[1]; + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); +- return ret; ++ goto out; + } + +- return 0; ++ ret = 0; ++ ++out: ++ hidpp->send_receive_buf = NULL; ++ return ret; + } + + /* +@@ -3843,8 +3848,7 @@ static int hidpp_input_configured(struct hid_device *hdev, + static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + int size) + { +- struct hidpp_report *question = hidpp->send_receive_buf; +- struct hidpp_report *answer = hidpp->send_receive_buf; ++ struct hidpp_report *question, *answer; + struct hidpp_report *report = (struct hidpp_report *)data; + int ret; + int last_online; +@@ -3854,6 +3858,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, + * previously sent command. + */ + if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { ++ question = hidpp->send_receive_buf; ++ answer = hidpp->send_receive_buf; ++ ++ if (!question) ++ return 0; ++ + /* + * Check for a correct hidpp20 answer or the corresponding + * error +-- +2.53.0 + diff --git a/queue-7.0/hid-playstation-validate-num_touch_reports-in-dualsh.patch b/queue-7.0/hid-playstation-validate-num_touch_reports-in-dualsh.patch new file mode 100644 index 0000000000..2fa6bdbae4 --- /dev/null +++ b/queue-7.0/hid-playstation-validate-num_touch_reports-in-dualsh.patch @@ -0,0 +1,64 @@ +From 3957a16d6a2f6d918df39197475b35a23e06aeab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:47:37 +0000 +Subject: HID: playstation: validate num_touch_reports in DualShock 4 reports +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benoît Sevens + +[ Upstream commit 82a4fc46330910b4c1d9b189561439d468e3ff11 ] + +The DualShock 4 HID driver fails to validate the num_touch_reports field +received from the device in both USB and Bluetooth input reports. +A malicious device could set this field to a value larger than the +allocated size of the touch_reports array (3 for USB, 4 for Bluetooth), +leading to an out-of-bounds read in dualshock4_parse_report(). + +This can result in kernel memory disclosure when processing malicious +HID reports. + +Validate num_touch_reports against the array size for the respective +connection types before processing the touch data. + +Signed-off-by: Benoît Sevens +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-playstation.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c +index 8d06ddff356a9..e485373316756 100644 +--- a/drivers/hid/hid-playstation.c ++++ b/drivers/hid/hid-playstation.c +@@ -2377,6 +2377,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + struct dualshock4_input_report_usb *usb = + (struct dualshock4_input_report_usb *)data; + ++ if (usb->num_touch_reports > ARRAY_SIZE(usb->touch_reports)) { ++ hid_err(hdev, "DualShock4 USB input report has invalid num_touch_reports=%d\n", ++ usb->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &usb->common; + num_touch_reports = min_t(u8, usb->num_touch_reports, + ARRAY_SIZE(usb->touch_reports)); +@@ -2392,6 +2398,12 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * + return -EILSEQ; + } + ++ if (bt->num_touch_reports > ARRAY_SIZE(bt->touch_reports)) { ++ hid_err(hdev, "DualShock4 BT input report has invalid num_touch_reports=%d\n", ++ bt->num_touch_reports); ++ return -EINVAL; ++ } ++ + ds4_report = &bt->common; + num_touch_reports = min_t(u8, bt->num_touch_reports, + ARRAY_SIZE(bt->touch_reports)); +-- +2.53.0 + diff --git a/queue-7.0/hid-quirks-really-enable-the-intended-work-around-fo.patch b/queue-7.0/hid-quirks-really-enable-the-intended-work-around-fo.patch new file mode 100644 index 0000000000..da467ccdc2 --- /dev/null +++ b/queue-7.0/hid-quirks-really-enable-the-intended-work-around-fo.patch @@ -0,0 +1,42 @@ +From 53d8b7bb4b95f10700c96d2caedd4ca76964d055 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 09:11:31 +0100 +Subject: HID: quirks: really enable the intended work around for appledisplay + +From: Lukas Bulwahn + +[ Upstream commit 5f90dcfa8dc32a488581b78e575cdd7808ba5c78 ] + +Commit c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for +appledisplay") intends to add a quirk for kernels built with Apple Cinema +Display support, but it refers to the non-existing config option +CONFIG_APPLEDISPLAY, whereas the config option for Apple Cinema Display +support is named CONFIG_USB_APPLEDISPLAY. + +Refer to the intended config option CONFIG_USB_APPLEDISPLAY in the ifdef +directive. + +Fixes: c7fabe4ad921 ("HID: quirks: work around VID/PID conflict for appledisplay") +Signed-off-by: Lukas Bulwahn +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 02f7db5c10564..5e754b0a50325 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -234,7 +234,7 @@ static const struct hid_device_id hid_quirks[] = { + * used as a driver. See hid_scan_report(). + */ + static const struct hid_device_id hid_have_special_driver[] = { +-#if IS_ENABLED(CONFIG_APPLEDISPLAY) ++#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, +-- +2.53.0 + diff --git a/queue-7.0/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch b/queue-7.0/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch new file mode 100644 index 0000000000..c3b6f1ab95 --- /dev/null +++ b/queue-7.0/hid-quirks-set-always_poll-for-logitech_bolt_receive.patch @@ -0,0 +1,48 @@ +From ce855d1bcd68b98e3126539a3828d924e0c174c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:59:28 -0400 +Subject: HID: quirks: Set ALWAYS_POLL for LOGITECH_BOLT_RECEIVER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit d4229fc0cb50c52b385538d072c5fc8827b287a9 ] + +The Logitech Bolt receiver once connected to a wireless device will +generate data on interface 2. If this data isn't polled, when the USB +port it is connected to gets suspended (and if that happens within 5 +minutes of the last input from the wireless device), it will trigger a +remote wakeup 3 seconds later, which will result in a spurious system +wakeup if the port was suspended as part of system sleep. + +Set the ALWAYS_POLL quirk for this device to ensure interface 2 is +always polled and this spurious wakeup never happens. + +With this change in place the system can be suspended with the receiver +plugged in and the system can be woken up when an input is sent from the +wireless device. + +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 5e754b0a50325..987495f10e6e5 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -134,6 +134,7 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, +-- +2.53.0 + diff --git a/queue-7.0/hid-uclogic-fix-regression-of-input-name-assignment.patch b/queue-7.0/hid-uclogic-fix-regression-of-input-name-assignment.patch new file mode 100644 index 0000000000..175d421da9 --- /dev/null +++ b/queue-7.0/hid-uclogic-fix-regression-of-input-name-assignment.patch @@ -0,0 +1,44 @@ +From 16884f30ab6da6ada0ea6768c4629450e69f654d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 10:33:16 +0200 +Subject: HID: uclogic: Fix regression of input name assignment + +From: Takashi Iwai + +[ Upstream commit 487359284509a6745e14b8c0518768bc277809b0 ] + +The previous fix for adding the devm_kasprintf() return check in the +commit bd07f751208b ("HID: uclogic: Add NULL check in +uclogic_input_configured()") changed the condition of hi->input->name +assignment, and it resulted in missing the proper input device name +when no custom suffix is defined. + +Restore the conditional to the original content to address the +regression. + +Fixes: bd07f751208b ("HID: uclogic: Add NULL check in uclogic_input_configured()") +Signed-off-by: Takashi Iwai +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-uclogic-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c +index bd7f93e96e4e4..b73f09d26688a 100644 +--- a/drivers/hid/hid-uclogic-core.c ++++ b/drivers/hid/hid-uclogic-core.c +@@ -184,7 +184,9 @@ static int uclogic_input_configured(struct hid_device *hdev, + suffix = "System Control"; + break; + } +- } else { ++ } ++ ++ if (suffix) { + hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s %s", hdev->name, suffix); + if (!hi->input->name) +-- +2.53.0 + diff --git a/queue-7.0/hinic3-add-msg_send_lock-for-message-sending-concurr.patch b/queue-7.0/hinic3-add-msg_send_lock-for-message-sending-concurr.patch new file mode 100644 index 0000000000..d666f4aba6 --- /dev/null +++ b/queue-7.0/hinic3-add-msg_send_lock-for-message-sending-concurr.patch @@ -0,0 +1,91 @@ +From 23ccfeafe7de088a72e16818a12bdf725ae7dde8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:04:53 +0800 +Subject: hinic3: Add msg_send_lock for message sending concurrecy + +From: Fan Gong + +[ Upstream commit 2a76f900d17dcb9e8322770ac9bcae34517805b3 ] + +As send_mbox_msg is invoked by 3 functions: hinic3_send_mbox_to_mgmt, +hinic3_response_mbox_to_mgmt and hinic3_send_mbox_to_mgmt_no_ack, only +hinic3_response_mbox_to_mgmt does not has mutex and the other two has +mbox->mbox_send_lock because their send actions are mutually exclusive. + As hinic3_response_mbox_to_mgmt does not conflict with them in send +actions but in mailbox resources, add the new mutex(msg_send_lock) in +send_mbox_msg to ensure message concurrency. + + Besdies, in mbox_send_seg change FIELD_PREP to FIELD_GET in +MBOX_STATUS_FINISHED and MBOX_STATUS_SUCCESS to be more reasonable. + +Co-developed-by: Zhu Yikai +Signed-off-by: Zhu Yikai +Signed-off-by: Fan Gong +Link: https://patch.msgid.link/d83f7f6eb4b5e94642a558fab75d61292c347e48.1773062356.git.zhuyikai1@h-partners.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c | 9 +++++++-- + drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h | 4 ++++ + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +index 826fa8879a113..65528b2a7b7c8 100644 +--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c ++++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +@@ -50,9 +50,9 @@ + #define MBOX_WB_STATUS_NOT_FINISHED 0x00 + + #define MBOX_STATUS_FINISHED(wb) \ +- ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED) ++ ((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED) + #define MBOX_STATUS_SUCCESS(wb) \ +- ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) == \ ++ ((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) == \ + MBOX_WB_STATUS_FINISHED_SUCCESS) + #define MBOX_STATUS_ERRCODE(wb) \ + ((wb) & MBOX_WB_ERROR_CODE_MASK) +@@ -395,6 +395,7 @@ static int hinic3_mbox_pre_init(struct hinic3_hwdev *hwdev, + { + mbox->hwdev = hwdev; + mutex_init(&mbox->mbox_send_lock); ++ mutex_init(&mbox->mbox_seg_send_lock); + spin_lock_init(&mbox->mbox_lock); + + mbox->workq = create_singlethread_workqueue(HINIC3_MBOX_WQ_NAME); +@@ -706,6 +707,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd, + else + rsp_aeq_id = 0; + ++ mutex_lock(&mbox->mbox_seg_send_lock); ++ + if (dst_func == MBOX_MGMT_FUNC_ID && + !(hwdev->features[0] & MBOX_COMM_F_MBOX_SEGMENT)) { + err = mbox_prepare_dma_msg(mbox, ack_type, &dma_msg, +@@ -759,6 +762,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd, + } + + err_send: ++ mutex_unlock(&mbox->mbox_seg_send_lock); ++ + return err; + } + +diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +index e26f22d1d5641..30de0c1295038 100644 +--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h ++++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +@@ -114,6 +114,10 @@ struct hinic3_mbox { + struct hinic3_hwdev *hwdev; + /* lock for send mbox message and ack message */ + struct mutex mbox_send_lock; ++ /* lock for send message transmission. ++ * The lock hierarchy is mbox_send_lock -> mbox_seg_send_lock. ++ */ ++ struct mutex mbox_seg_send_lock; + struct hinic3_send_mbox send_mbox; + struct mbox_dma_queue sync_msg_queue; + struct mbox_dma_queue async_msg_queue; +-- +2.53.0 + diff --git a/queue-7.0/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch b/queue-7.0/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch new file mode 100644 index 0000000000..f7d5cfbd03 --- /dev/null +++ b/queue-7.0/hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch @@ -0,0 +1,65 @@ +From b7b1437c95e72481e56f181bc5a7da16a625e74b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 16:16:18 +0100 +Subject: hwmon: (asus-ec-sensors )add ROG CROSSHAIR X670E EXTREME + +From: Timothy C. Sweeney-Fanelli + +[ Upstream commit ab4b7071ae0a831e4c2fd45c626c3b1d66cc1201 ] + +Add support for ROG CROSSHAIR X670E EXTREME + +Signed-off-by: Timothy C. Sweeney-Fanelli +Signed-off-by: Eugene Shalygin +Link: https://lore.kernel.org/r/20260215151743.20138-3-eugene.shalygin@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + Documentation/hwmon/asus_ec_sensors.rst | 1 + + drivers/hwmon/asus-ec-sensors.c | 11 +++++++++++ + 2 files changed, 12 insertions(+) + +diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst +index 58986546c7233..8a080a786abd2 100644 +--- a/Documentation/hwmon/asus_ec_sensors.rst ++++ b/Documentation/hwmon/asus_ec_sensors.rst +@@ -22,6 +22,7 @@ Supported boards: + * ROG CROSSHAIR VIII FORMULA + * ROG CROSSHAIR VIII HERO + * ROG CROSSHAIR VIII IMPACT ++ * ROG CROSSHAIR X670E EXTREME + * ROG CROSSHAIR X670E HERO + * ROG CROSSHAIR X670E GENE + * ROG MAXIMUS X HERO +diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c +index adedaf0db10e6..934e37738a516 100644 +--- a/drivers/hwmon/asus-ec-sensors.c ++++ b/drivers/hwmon/asus-ec-sensors.c +@@ -456,6 +456,15 @@ static const struct ec_board_info board_info_crosshair_viii_impact = { + .family = family_amd_500_series, + }; + ++static const struct ec_board_info board_info_crosshair_x670e_extreme = { ++ .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | ++ SENSOR_TEMP_MB | SENSOR_TEMP_VRM | ++ SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_WATER_IN | ++ SENSOR_TEMP_WATER_OUT, ++ .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, ++ .family = family_amd_600_series, ++}; ++ + static const struct ec_board_info board_info_crosshair_x670e_gene = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_T_SENSOR | +@@ -825,6 +834,8 @@ static const struct dmi_system_id dmi_table[] = { + &board_info_crosshair_viii_hero), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT", + &board_info_crosshair_viii_impact), ++ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E EXTREME", ++ &board_info_crosshair_x670e_extreme), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE", + &board_info_crosshair_x670e_gene), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", +-- +2.53.0 + diff --git a/queue-7.0/hwmon-gpd-fan-add-gpd-win-5.patch b/queue-7.0/hwmon-gpd-fan-add-gpd-win-5.patch new file mode 100644 index 0000000000..b93a6135af --- /dev/null +++ b/queue-7.0/hwmon-gpd-fan-add-gpd-win-5.patch @@ -0,0 +1,43 @@ +From 206e9ce491dbbad7a6de5854b77270d195dda247 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 17:16:01 +0100 +Subject: hwmon: (gpd-fan) Add GPD Win 5 + +From: Antheas Kapenekakis + +[ Upstream commit 4853b53264869e51378cad7bf1556d4e8049d445 ] + +The GPD Win 5 is a new device by GPD with an AMD AI MAX 385/395 chip. +It uses the same fan control registers as the GPD Win Duo. This +information was provided by GPD. + +Signed-off-by: Antheas Kapenekakis +Link: https://lore.kernel.org/r/20260220161601.2344291-1-lkml@antheas.dev +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/gpd-fan.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c +index 1729729b135f8..80de5f20781eb 100644 +--- a/drivers/hwmon/gpd-fan.c ++++ b/drivers/hwmon/gpd-fan.c +@@ -209,6 +209,14 @@ static const struct dmi_system_id dmi_table[] = { + }, + .driver_data = &gpd_duo_drvdata, + }, ++ { ++ // GPD Win 5 with AMD AI MAX 395 ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "GPD"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "G1618-05"), ++ }, ++ .driver_data = &gpd_duo_drvdata, ++ }, + { + // GPD Pocket 4 + .matches = { +-- +2.53.0 + diff --git a/queue-7.0/hwmon-lm90-add-lock-protection-to-lm90_alert.patch b/queue-7.0/hwmon-lm90-add-lock-protection-to-lm90_alert.patch new file mode 100644 index 0000000000..d1636fb3e0 --- /dev/null +++ b/queue-7.0/hwmon-lm90-add-lock-protection-to-lm90_alert.patch @@ -0,0 +1,58 @@ +From 9e933fa79e0126740dd423589844d4e9e92dbcfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 14:41:00 -0700 +Subject: hwmon: (lm90) Add lock protection to lm90_alert + +From: Guenter Roeck + +[ Upstream commit 873e919e3101063a7a75989510ccfc125a4391cf ] + +Sashiko reports: + +lm90_alert() executes in the smbus alert context and calls +lm90_update_confreg() to disable the hardware alert line, without +acquiring hwmon_lock. + +Concurrently, sysfs write operations (such as lm90_write_convrate) hold +the hwmon_lock, temporarily modify data->config, and then restore it. + +If an alert interrupt occurs concurrently with a sysfs write, the sysfs +path will overwrite the alert handler's modifications to data->config +and the hardware register. + +This unintentionally re-enables the hardware alert line while the alarm is +still active, causing an interrupt storm. + +Add the missing lock to lm90_alert() to solve the problem. + +Fixes: 7a1d220ccb0cc ("hwmon: (lm90) Introduce function to update configuration register") +Reported-by: Sashiko +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/lm90.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c +index c4a9dafff81d6..1eeb608e59039 100644 +--- a/drivers/hwmon/lm90.c ++++ b/drivers/hwmon/lm90.c +@@ -2946,6 +2946,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + */ + struct lm90_data *data = i2c_get_clientdata(client); + ++ hwmon_lock(data->hwmon_dev); + if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) && + (data->current_alarms & data->alert_alarms)) { + if (!(data->config & 0x80)) { +@@ -2955,6 +2956,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + schedule_delayed_work(&data->alert_work, + max_t(int, HZ, msecs_to_jiffies(data->update_interval))); + } ++ hwmon_unlock(data->hwmon_dev); + } else { + dev_dbg(&client->dev, "Everything OK\n"); + } +-- +2.53.0 + diff --git a/queue-7.0/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch b/queue-7.0/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch new file mode 100644 index 0000000000..2306abe6cd --- /dev/null +++ b/queue-7.0/hwmon-lm90-stop-work-before-releasing-hwmon-device.patch @@ -0,0 +1,108 @@ +From 19bc1cce18e32e82ba6f621e171ada86586bfb08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 14:31:49 -0700 +Subject: hwmon: (lm90) Stop work before releasing hwmon device + +From: Guenter Roeck + +[ Upstream commit b09a45601094c7f4ec4db8090b825fa61e169d93 ] + +Sashiko reports: + +In lm90_probe(), the devm action to cancel the alert_work and report_work +(lm90_restore_conf) is registered in lm90_init_client() before +devm_hwmon_device_register_with_info() is called. + +Because devm executes cleanup actions in reverse order during module +unbind or probe failure, the hwmon device is unregistered and freed first. + +If lm90_alert_work() or lm90_report_alarms() runs in the window between +the hwmon device being freed and the delayed works being cancelled, +lm90_update_alarms() will dereference the freed data->hwmon_dev here. + +Fix the problem by canceling the workers separately after registering +the hwmon device and before registering the interrupt handler. This ensures +that the workers are canceled after interrupts are disabled and before +the hwmon device is released. Add "shutdown" flag to indicate that device +shutdown is in progress to prevent workers from being re-armed. + +Fixes: f6d0775119fb9 ("hwmon: (lm90) Rework alarm/status handling") +Reported-by: Sashiko +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/lm90.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c +index 3c10a5066b53d..c4a9dafff81d6 100644 +--- a/drivers/hwmon/lm90.c ++++ b/drivers/hwmon/lm90.c +@@ -736,6 +736,7 @@ struct lm90_data { + struct hwmon_chip_info chip; + struct delayed_work alert_work; + struct work_struct report_work; ++ bool shutdown; /* true if shutting down */ + bool valid; /* true if register values are valid */ + bool alarms_valid; /* true if status register values are valid */ + unsigned long last_updated; /* in jiffies */ +@@ -1154,6 +1155,9 @@ static void lm90_report_alarms(struct work_struct *work) + + static int lm90_update_alarms_locked(struct lm90_data *data, bool force) + { ++ if (data->shutdown) ++ return 0; ++ + if (force || !data->alarms_valid || + time_after(jiffies, data->alarms_updated + msecs_to_jiffies(data->update_interval))) { + struct i2c_client *client = data->client; +@@ -2584,15 +2588,23 @@ static void lm90_restore_conf(void *_data) + struct lm90_data *data = _data; + struct i2c_client *client = data->client; + +- cancel_delayed_work_sync(&data->alert_work); +- cancel_work_sync(&data->report_work); +- + /* Restore initial configuration */ + if (data->flags & LM90_HAVE_CONVRATE) + lm90_write_convrate(data, data->convrate_orig); + lm90_write_reg(client, LM90_REG_CONFIG1, data->config_orig); + } + ++static void lm90_stop_work(void *_data) ++{ ++ struct lm90_data *data = _data; ++ ++ hwmon_lock(data->hwmon_dev); ++ data->shutdown = true; ++ hwmon_unlock(data->hwmon_dev); ++ cancel_delayed_work_sync(&data->alert_work); ++ cancel_work_sync(&data->report_work); ++} ++ + static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) + { + struct device_node *np = client->dev.of_node; +@@ -2902,6 +2914,10 @@ static int lm90_probe(struct i2c_client *client) + + data->hwmon_dev = hwmon_dev; + ++ err = devm_add_action_or_reset(&client->dev, lm90_stop_work, data); ++ if (err) ++ return err; ++ + if (client->irq) { + dev_dbg(dev, "IRQ: %d\n", client->irq); + err = devm_request_threaded_irq(dev, client->irq, +@@ -2930,7 +2946,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + */ + struct lm90_data *data = i2c_get_clientdata(client); + +- if ((data->flags & LM90_HAVE_BROKEN_ALERT) && ++ if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) && + (data->current_alarms & data->alert_alarms)) { + if (!(data->config & 0x80)) { + dev_dbg(&client->dev, "Disabling ALERT#\n"); +-- +2.53.0 + diff --git a/queue-7.0/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch b/queue-7.0/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch new file mode 100644 index 0000000000..e0fbda0e67 --- /dev/null +++ b/queue-7.0/hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch @@ -0,0 +1,49 @@ +From c3841765313a8dbb6521dc6501b77fe2d93bf1ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 00:17:27 +0000 +Subject: hwmon: (nct6683) Add customer ID for ASRock B650I Lightning WiFi + +From: Petr Klotz + +[ Upstream commit ff708b549c4dbecb308fa97e360a8fe0b2f89309 ] + +The ASRock B650I Lightning WiFi motherboard uses an NCT6686D chip with a +customer ID of 0x1633. Without this ID, the nct6683 driver fails to +recognize the hardware on this board, preventing hardware monitoring +from working. + +Add NCT6683_CUSTOMER_ID_ASROCK6 (0x1633) to the list of supported customer +IDs and update the probe function to handle it + +Signed-off-by: Petr Klotz +Link: https://lore.kernel.org/r/20260412000911.9063-2-pklotz0@protonmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/nct6683.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c +index 4a83804140386..0581770380cc5 100644 +--- a/drivers/hwmon/nct6683.c ++++ b/drivers/hwmon/nct6683.c +@@ -182,6 +182,7 @@ superio_exit(int ioreg) + #define NCT6683_CUSTOMER_ID_ASROCK3 0x1631 + #define NCT6683_CUSTOMER_ID_ASROCK4 0x163e + #define NCT6683_CUSTOMER_ID_ASROCK5 0x1621 ++#define NCT6683_CUSTOMER_ID_ASROCK6 0x1633 + + #define NCT6683_REG_BUILD_YEAR 0x604 + #define NCT6683_REG_BUILD_MONTH 0x605 +@@ -1245,6 +1246,8 @@ static int nct6683_probe(struct platform_device *pdev) + break; + case NCT6683_CUSTOMER_ID_ASROCK5: + break; ++ case NCT6683_CUSTOMER_ID_ASROCK6: ++ break; + default: + if (!force) + return -ENODEV; +-- +2.53.0 + diff --git a/queue-7.0/hwmon-nct6775-add-asus-x870-w480-to-wmi-monitoring-l.patch b/queue-7.0/hwmon-nct6775-add-asus-x870-w480-to-wmi-monitoring-l.patch new file mode 100644 index 0000000000..51894ac74e --- /dev/null +++ b/queue-7.0/hwmon-nct6775-add-asus-x870-w480-to-wmi-monitoring-l.patch @@ -0,0 +1,143 @@ +From 9395fe5a36eee883b387629e876c4a98a7c021c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Mar 2026 15:18:45 +0200 +Subject: hwmon: (nct6775) Add ASUS X870/W480 to WMI monitoring list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Pauk + +[ Upstream commit 21518579cbdeb4e86a6fffbc3d52f52bd74ab87e ] + +Boards such as +* G15CE, +* PRIME X870-P WIFI, +* PRIME X870-P, +* Pro WS W480-ACE, +* ProArt X870E-CREATOR WIFI, +* ROG CROSSHAIR X870E APEX, +* ROG CROSSHAIR X870E DARK HERO, +* ROG CROSSHAIR X870E EXTREME, +* ROG CROSSHAIR X870E GLACIAL, +* ROG CROSSHAIR X870E HERO BTF, +* ROG CROSSHAIR X870E HERO, +* ROG STRIX X870-A GAMING WIFI, +* ROG STRIX X870-F GAMING WIFI, +* ROG STRIX X870-I GAMING WIFI, +* ROG STRIX X870E-E GAMING WIFI, +* ROG STRIX X870E-E GAMING WIFI7 R2, +* TUF GAMING X870-PLUS WIFI, +* TUF GAMING X870-PRO WIFI7 W NEO, +* TUF GAMING X870E-PLUS WIFI7, +* W480/SYS, +* X870 AYW GAMING WIFI W, +* X870 MAX GAMING WIFI7 W, +* X870 MAX GAMING WIFI7 +have got a nct6775 chip, but by default there's no use of it because of +resource conflict with WMI method. + +Add the boards to the WMI monitoring list. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=204807 +Signed-off-by: Denis Pauk +Tested-by: Tomáš Bžatek +Tested-by: Theunis Scheepers +Link: https://lore.kernel.org/r/20260322131848.6261-1-pauk.denis@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/nct6775-platform.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c +index 555029dfe713f..1975399ac440d 100644 +--- a/drivers/hwmon/nct6775-platform.c ++++ b/drivers/hwmon/nct6775-platform.c +@@ -1159,6 +1159,7 @@ static const char * const asus_wmi_boards[] = { + "Pro A520M-C", + "Pro A520M-C II", + "Pro B550M-C", ++ "Pro WS W480-ACE", + "Pro WS X570-ACE", + "ProArt B550-CREATOR", + "ProArt X570-CREATOR WIFI", +@@ -1258,6 +1259,7 @@ static const char * const asus_wmi_boards[] = { + "TUF Z390-PRO GAMING", + "TUF Z390M-PRO GAMING", + "TUF Z390M-PRO GAMING (WI-FI)", ++ "W480/SYS", + "WS Z390 PRO", + "Z490-GUNDAM (WI-FI)", + }; +@@ -1270,6 +1272,7 @@ static const char * const asus_msi_boards[] = { + "EX-B760M-V5 D4", + "EX-H510M-V3", + "EX-H610M-V3 D4", ++ "G15CE", + "G15CF", + "PRIME A620M-A", + "PRIME B560-PLUS", +@@ -1320,6 +1323,8 @@ static const char * const asus_msi_boards[] = { + "PRIME X670-P", + "PRIME X670-P WIFI", + "PRIME X670E-PRO WIFI", ++ "PRIME X870-P", ++ "PRIME X870-P WIFI", + "PRIME Z590-A", + "PRIME Z590-P", + "PRIME Z590-P WIFI", +@@ -1362,11 +1367,18 @@ static const char * const asus_msi_boards[] = { + "ProArt B660-CREATOR D4", + "ProArt B760-CREATOR D4", + "ProArt X670E-CREATOR WIFI", ++ "ProArt X870E-CREATOR WIFI", + "ProArt Z690-CREATOR WIFI", + "ProArt Z790-CREATOR WIFI", + "ROG CROSSHAIR X670E EXTREME", + "ROG CROSSHAIR X670E GENE", + "ROG CROSSHAIR X670E HERO", ++ "ROG CROSSHAIR X870E APEX", ++ "ROG CROSSHAIR X870E DARK HERO", ++ "ROG CROSSHAIR X870E EXTREME", ++ "ROG CROSSHAIR X870E GLACIAL", ++ "ROG CROSSHAIR X870E HERO", ++ "ROG CROSSHAIR X870E HERO BTF", + "ROG MAXIMUS XIII APEX", + "ROG MAXIMUS XIII EXTREME", + "ROG MAXIMUS XIII EXTREME GLACIAL", +@@ -1404,6 +1416,11 @@ static const char * const asus_msi_boards[] = { + "ROG STRIX X670E-E GAMING WIFI", + "ROG STRIX X670E-F GAMING WIFI", + "ROG STRIX X670E-I GAMING WIFI", ++ "ROG STRIX X870-A GAMING WIFI", ++ "ROG STRIX X870-F GAMING WIFI", ++ "ROG STRIX X870-I GAMING WIFI", ++ "ROG STRIX X870E-E GAMING WIFI", ++ "ROG STRIX X870E-E GAMING WIFI7 R2", + "ROG STRIX X870E-H GAMING WIFI7", + "ROG STRIX Z590-A GAMING WIFI", + "ROG STRIX Z590-A GAMING WIFI II", +@@ -1451,6 +1468,9 @@ static const char * const asus_msi_boards[] = { + "TUF GAMING H770-PRO WIFI", + "TUF GAMING X670E-PLUS", + "TUF GAMING X670E-PLUS WIFI", ++ "TUF GAMING X870-PLUS WIFI", ++ "TUF GAMING X870-PRO WIFI7 W NEO", ++ "TUF GAMING X870E-PLUS WIFI7", + "TUF GAMING Z590-PLUS", + "TUF GAMING Z590-PLUS WIFI", + "TUF GAMING Z690-PLUS", +@@ -1460,6 +1480,9 @@ static const char * const asus_msi_boards[] = { + "TUF GAMING Z790-PLUS D4", + "TUF GAMING Z790-PLUS WIFI", + "TUF GAMING Z790-PLUS WIFI D4", ++ "X870 AYW GAMING WIFI W", ++ "X870 MAX GAMING WIFI7", ++ "X870 MAX GAMING WIFI7 W", + "Z590 WIFI GUNDAM EDITION", + }; + +-- +2.53.0 + diff --git a/queue-7.0/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch b/queue-7.0/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch new file mode 100644 index 0000000000..39c4e88e49 --- /dev/null +++ b/queue-7.0/hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch @@ -0,0 +1,73 @@ +From 788d18e4474f60ef49a62cb1e3c2feecd2fe35dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:02:08 +0800 +Subject: hwmon: (pmbus/isl68137) Add support for Renesas RAA228942 and + RAA228943 + +From: Dawei Liu + +[ Upstream commit 7c760db74c9f30da7281c7f450d0676ec78ec3e6 ] + +Add I2C device IDs for Renesas RAA228942 and RAA228943. + +At the Linux PMBus hwmon interface level currently supported by this +driver, these devices are compatible with the existing 2-rail non-TC +controllers, so devicetree will use fallback compatibles and no +dedicated OF match entries are needed. + +Signed-off-by: Dawei Liu +Link: https://lore.kernel.org/r/20260325090208.857-3-dawei.liu.jy@renesas.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + Documentation/hwmon/isl68137.rst | 20 ++++++++++++++++++++ + drivers/hwmon/pmbus/isl68137.c | 2 ++ + 2 files changed, 22 insertions(+) + +diff --git a/Documentation/hwmon/isl68137.rst b/Documentation/hwmon/isl68137.rst +index e77f582c28505..0ce20d09164fc 100644 +--- a/Documentation/hwmon/isl68137.rst ++++ b/Documentation/hwmon/isl68137.rst +@@ -394,6 +394,26 @@ Supported chips: + + Provided by Renesas upon request and NDA + ++ * Renesas RAA228942 ++ ++ Prefix: 'raa228942' ++ ++ Addresses scanned: - ++ ++ Datasheet: ++ ++ Provided by Renesas upon request and NDA ++ ++ * Renesas RAA228943 ++ ++ Prefix: 'raa228943' ++ ++ Addresses scanned: - ++ ++ Datasheet: ++ ++ Provided by Renesas upon request and NDA ++ + * Renesas RAA229001 + + Prefix: 'raa229001' +diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c +index 3e3a887aad050..c8930f2d54237 100644 +--- a/drivers/hwmon/pmbus/isl68137.c ++++ b/drivers/hwmon/pmbus/isl68137.c +@@ -498,6 +498,8 @@ static const struct i2c_device_id raa_dmpvr_id[] = { + {"raa228228", raa_dmpvr2_2rail_nontc}, + {"raa228244", raa_dmpvr2_2rail_nontc}, + {"raa228246", raa_dmpvr2_2rail_nontc}, ++ {"raa228942", raa_dmpvr2_2rail_nontc}, ++ {"raa228943", raa_dmpvr2_2rail_nontc}, + {"raa229001", raa_dmpvr2_2rail}, + {"raa229004", raa_dmpvr2_2rail}, + {"raa229141", raa_dmpvr2_2rail_pmbus}, +-- +2.53.0 + diff --git a/queue-7.0/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch b/queue-7.0/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch new file mode 100644 index 0000000000..6f28c58493 --- /dev/null +++ b/queue-7.0/i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch @@ -0,0 +1,36 @@ +From 44615a246d622672ddb4b5f5379f1281715a5b55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 13:34:08 +0530 +Subject: i2c: usbio: Add ACPI device-id for NVL platforms + +From: Arun T + +[ Upstream commit e43f2df330a1b87c97235e4faade860d15787735 ] + +Add device IDs of Nova Lake into i2c-usbio support list + +Signed-off-by: Arun T +Reviewed-by: Vadillo Miguel +Reviewed-by: Sakari Ailus +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260410080408.562311-1-arun.t@intel.com +Signed-off-by: Sasha Levin +--- + drivers/i2c/busses/i2c-usbio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/i2c/busses/i2c-usbio.c b/drivers/i2c/busses/i2c-usbio.c +index e7799abf67877..259754e5fd05b 100644 +--- a/drivers/i2c/busses/i2c-usbio.c ++++ b/drivers/i2c/busses/i2c-usbio.c +@@ -29,6 +29,7 @@ static const struct acpi_device_id usbio_i2c_acpi_hids[] = { + { "INTC10B6" }, /* LNL */ + { "INTC10D2" }, /* MTL-CVF */ + { "INTC10E3" }, /* PTL */ ++ { "INTC1118" }, /* NVL */ + { } + }; + +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-move-bus_init-error-suppression.patch b/queue-7.0/i3c-master-move-bus_init-error-suppression.patch new file mode 100644 index 0000000000..cf2ca0b40c --- /dev/null +++ b/queue-7.0/i3c-master-move-bus_init-error-suppression.patch @@ -0,0 +1,98 @@ +From 0b9750de1f36ab496ccb953fd23284a78c13f5f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:31 +0100 +Subject: i3c: master: Move bus_init error suppression + +From: Jorge Marques + +[ Upstream commit 49775afa983e3e5ce8e7d00ee241791073be214d ] + +Prepare to fix improper Mx positive error propagation in later commits +by handling Mx error codes where the i3c_ccc_cmd command is allocated. +The CCC DISEC to broadcast address is invoked with +i3c_master_enec_disec_locked() and yields error I3C_ERROR_M2 if there +are no devices active on the bus. This is expected at the bus +initialization stage, where it is not known yet that there are no active +devices on the bus. Add bool suppress_m2 argument to +i3c_master_enec_disec_locked() and update the call site at +i3c_master_bus_init() with the exact corner case to not require +propagating positive Mx error codes. Other call site should not suppress +the error code, for example, if a driver requests to peripheral to +disable events and the transfer is not acknowledged, this is an error +and should not proceed. + +Reviewed-by: Frank Li +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-3-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 9e6be49bebb2c..b91dc1e734ed8 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -1051,7 +1051,8 @@ int i3c_master_entdaa_locked(struct i3c_master_controller *master) + EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); + + static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, +- u8 addr, bool enable, u8 evts) ++ u8 addr, bool enable, u8 evts, ++ bool suppress_m2) + { + struct i3c_ccc_events *events; + struct i3c_ccc_cmd_dest dest; +@@ -1071,6 +1072,9 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + i3c_ccc_cmd_dest_cleanup(&dest); + ++ if (suppress_m2 && ret && cmd.err == I3C_ERROR_M2) ++ ret = 0; ++ + return ret; + } + +@@ -1091,7 +1095,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, false, evts); ++ return i3c_master_enec_disec_locked(master, addr, false, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + +@@ -1112,7 +1116,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) + { +- return i3c_master_enec_disec_locked(master, addr, true, evts); ++ return i3c_master_enec_disec_locked(master, addr, true, evts, false); + } + EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + +@@ -2102,11 +2106,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + +- /* Disable all slave events before starting DAA. */ +- ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, +- I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +- I3C_CCC_EVENT_HJ); +- if (ret && ret != I3C_ERROR_M2) ++ /* ++ * Disable all slave events before starting DAA. When no active device ++ * is on the bus, returns Mx error code M2, this error is ignored. ++ */ ++ ret = i3c_master_enec_disec_locked(master, I3C_BROADCAST_ADDR, false, ++ I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | ++ I3C_CCC_EVENT_HJ, true); ++ if (ret) + goto err_bus_cleanup; + + /* +-- +2.53.0 + diff --git a/queue-7.0/i3c-mipi-i3c-hci-pci-add-support-for-intel-nova-lake.patch b/queue-7.0/i3c-mipi-i3c-hci-pci-add-support-for-intel-nova-lake.patch new file mode 100644 index 0000000000..747485c46c --- /dev/null +++ b/queue-7.0/i3c-mipi-i3c-hci-pci-add-support-for-intel-nova-lake.patch @@ -0,0 +1,37 @@ +From ed817e71e97ae1b43b165e24a9121560ec3113d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:50:45 +0200 +Subject: i3c: mipi-i3c-hci-pci: Add support for Intel Nova Lake-H I3C + +From: Adrian Hunter + +[ Upstream commit eaa1d092a4f304415b867b7b74ed74b8f8722b0b ] + +Add I3C controller PCI IDs for Intel Nova Lake-H. + +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260309075045.52344-1-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +index 30302e4d08e2a..22a5ba4ad7460 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c ++++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +@@ -337,6 +337,9 @@ static const struct pci_device_id mipi_i3c_hci_pci_devices[] = { + /* Nova Lake-S */ + { PCI_VDEVICE(INTEL, 0x6e2c), (kernel_ulong_t)&intel_mi_1_info}, + { PCI_VDEVICE(INTEL, 0x6e2d), (kernel_ulong_t)&intel_mi_2_info}, ++ /* Nova Lake-H */ ++ { PCI_VDEVICE(INTEL, 0xd37c), (kernel_ulong_t)&intel_mi_1_info}, ++ { PCI_VDEVICE(INTEL, 0xd36f), (kernel_ulong_t)&intel_mi_2_info}, + { }, + }; + MODULE_DEVICE_TABLE(pci, mipi_i3c_hci_pci_devices); +-- +2.53.0 + diff --git a/queue-7.0/ice-dpll-fix-misplaced-header-macros.patch b/queue-7.0/ice-dpll-fix-misplaced-header-macros.patch new file mode 100644 index 0000000000..a6925e4a0c --- /dev/null +++ b/queue-7.0/ice-dpll-fix-misplaced-header-macros.patch @@ -0,0 +1,74 @@ +From 1eb46394fcc254f1c7992a0cdac8e059f4539066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:17 -0700 +Subject: ice: dpll: fix misplaced header macros + +From: Ivan Vecera + +[ Upstream commit 30f1658fc5387384c7a60b9d15c79cb959512c1a ] + +The CGU register definitions (ICE_CGU_R10, ICE_CGU_R11 and related field +masks) were placed after the #endif of the _ICE_DPLL_H_ include guard, +leaving them unprotected. Move them inside the guard. + +Fixes: ad1df4f2d591 ("ice: dpll: Support E825-C SyncE and dynamic pin discovery") +Signed-off-by: Ivan Vecera +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-8-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.h | 32 +++++++++++------------ + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h +index ae42cdea0ee14..8678575359b92 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.h ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.h +@@ -8,6 +8,22 @@ + + #define ICE_DPLL_RCLK_NUM_MAX 4 + ++#define ICE_CGU_R10 0x28 ++#define ICE_CGU_R10_SYNCE_CLKO_SEL GENMASK(8, 5) ++#define ICE_CGU_R10_SYNCE_CLKODIV_M1 GENMASK(13, 9) ++#define ICE_CGU_R10_SYNCE_CLKODIV_LOAD BIT(14) ++#define ICE_CGU_R10_SYNCE_DCK_RST BIT(15) ++#define ICE_CGU_R10_SYNCE_ETHCLKO_SEL GENMASK(18, 16) ++#define ICE_CGU_R10_SYNCE_ETHDIV_M1 GENMASK(23, 19) ++#define ICE_CGU_R10_SYNCE_ETHDIV_LOAD BIT(24) ++#define ICE_CGU_R10_SYNCE_DCK2_RST BIT(25) ++#define ICE_CGU_R10_SYNCE_S_REF_CLK GENMASK(31, 27) ++ ++#define ICE_CGU_R11 0x2C ++#define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1) ++ ++#define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3 ++ + /** + * enum ice_dpll_pin_sw - enumerate ice software pin indices: + * @ICE_DPLL_PIN_SW_1_IDX: index of first SW pin +@@ -157,19 +173,3 @@ static inline void ice_dpll_deinit(struct ice_pf *pf) { } + #endif + + #endif +- +-#define ICE_CGU_R10 0x28 +-#define ICE_CGU_R10_SYNCE_CLKO_SEL GENMASK(8, 5) +-#define ICE_CGU_R10_SYNCE_CLKODIV_M1 GENMASK(13, 9) +-#define ICE_CGU_R10_SYNCE_CLKODIV_LOAD BIT(14) +-#define ICE_CGU_R10_SYNCE_DCK_RST BIT(15) +-#define ICE_CGU_R10_SYNCE_ETHCLKO_SEL GENMASK(18, 16) +-#define ICE_CGU_R10_SYNCE_ETHDIV_M1 GENMASK(23, 19) +-#define ICE_CGU_R10_SYNCE_ETHDIV_LOAD BIT(24) +-#define ICE_CGU_R10_SYNCE_DCK2_RST BIT(25) +-#define ICE_CGU_R10_SYNCE_S_REF_CLK GENMASK(31, 27) +- +-#define ICE_CGU_R11 0x2C +-#define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1) +- +-#define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3 +-- +2.53.0 + diff --git a/queue-7.0/ice-dpll-fix-rclk-pin-state-get-for-e810.patch b/queue-7.0/ice-dpll-fix-rclk-pin-state-get-for-e810.patch new file mode 100644 index 0000000000..b053c683af --- /dev/null +++ b/queue-7.0/ice-dpll-fix-rclk-pin-state-get-for-e810.patch @@ -0,0 +1,58 @@ +From 85fe627f7f0f117136bbfd924213f6a837899c7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:16 -0700 +Subject: ice: dpll: fix rclk pin state get for E810 + +From: Ivan Vecera + +[ Upstream commit cce709d8df6ba6d2a0a0dbf34acc2cdd9e23bd46 ] + +The refactoring of ice_dpll_rclk_state_on_pin_get() to use +ice_dpll_pin_get_parent_idx() omitted the base_rclk_idx adjustment that was +correctly added in the ice_dpll_rclk_state_on_pin_set() path. This breaks +E810 devices where base_rclk_idx is non-zero, causing the wrong hardware +index to be used for pin state lookup and incorrect recovered clock state +to be reported via the DPLL subsystem. E825C is unaffected as its +base_rclk_idx is 0. + +While at it, add bounds check against ICE_DPLL_RCLK_NUM_MAX on hw_idx after +the base_rclk_idx subtraction in both ice_dpll_rclk_state_on_pin_{get,set}() +to prevent out-of-bounds access on the pin state array. + +Fixes: ad1df4f2d591 ("ice: dpll: Support E825-C SyncE and dynamic pin discovery") +Signed-off-by: Ivan Vecera +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-7-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 27b460926bace..892bc7c2e28b4 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -2523,6 +2523,8 @@ ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, + if (hw_idx < 0) + goto unlock; + hw_idx -= pf->dplls.base_rclk_idx; ++ if (hw_idx >= ICE_DPLL_RCLK_NUM_MAX) ++ goto unlock; + + if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) || + (!enable && p->state[hw_idx] == DPLL_PIN_STATE_DISCONNECTED)) { +@@ -2586,6 +2588,9 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv, + hw_idx = ice_dpll_pin_get_parent_idx(p, parent_pin); + if (hw_idx < 0) + goto unlock; ++ hw_idx -= pf->dplls.base_rclk_idx; ++ if (hw_idx >= ICE_DPLL_RCLK_NUM_MAX) ++ goto unlock; + + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_INPUT, + extack); +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-locking-in-ice_dcb_rebuild.patch b/queue-7.0/ice-fix-locking-in-ice_dcb_rebuild.patch new file mode 100644 index 0000000000..02525e5deb --- /dev/null +++ b/queue-7.0/ice-fix-locking-in-ice_dcb_rebuild.patch @@ -0,0 +1,57 @@ +From 845aa089b4094e678e31ad5aeb5a2582dfb7e37d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:15 -0700 +Subject: ice: fix locking in ice_dcb_rebuild() + +From: Bart Van Assche + +[ Upstream commit 0ded1f36ba4021cba50513e80be6b6e173710168 ] + +Move the mutex_lock() call up to prevent that DCB settings change after +the first ice_query_port_ets() call. The second ice_query_port_ets() +call in ice_dcb_rebuild() is already protected by pf->tc_mutex. + +This also fixes a bug in an error path, as before taking the first +"goto dcb_error" in the function jumped over mutex_lock() to +mutex_unlock(). + +This bug has been detected by the clang thread-safety analyzer. + +Cc: intel-wired-lan@lists.osuosl.org +Fixes: 242b5e068b25 ("ice: Fix DCB rebuild after reset") +Signed-off-by: Bart Van Assche +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Arpana Arland +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-6-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index 16aa255351523..0bc6dd3756879 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -537,14 +537,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) + struct ice_dcbx_cfg *err_cfg; + int ret; + ++ mutex_lock(&pf->tc_mutex); ++ + ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); + if (ret) { + dev_err(dev, "Query Port ETS failed\n"); + goto dcb_error; + } + +- mutex_lock(&pf->tc_mutex); +- + if (!pf->hw.port_info->qos_cfg.is_sw_lldp) + ice_cfg_etsrec_defaults(pf->hw.port_info); + +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-setting-rss-vsi-hash-for-e830.patch b/queue-7.0/ice-fix-setting-rss-vsi-hash-for-e830.patch new file mode 100644 index 0000000000..f3b808793b --- /dev/null +++ b/queue-7.0/ice-fix-setting-rss-vsi-hash-for-e830.patch @@ -0,0 +1,56 @@ +From c954e5098eec46fbbec44f9b046382e2b9336506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:14 -0700 +Subject: ice: fix setting RSS VSI hash for E830 + +From: Marcin Szycik + +[ Upstream commit b3cda96feb60d91fe88d52b974ff110dcfa91239 ] + +ice_set_rss_hfunc() performs a VSI update, in which it sets hashing +function, leaving other VSI options unchanged. However, ::q_opt_flags is +mistakenly set to the value of another field, instead of its original +value, probably due to a typo. What happens next is hardware-dependent: + +On E810, only the first bit is meaningful (see +ICE_AQ_VSI_Q_OPT_PE_FLTR_EN) and can potentially end up in a different +state than before VSI update. + +On E830, some of the remaining bits are not reserved. Setting them +to some unrelated values can cause the firmware to reject the update +because of invalid settings, or worse - succeed. + +Reproducer: + sudo ethtool -X $PF1 equal 8 + +Output in dmesg: + Failed to configure RSS hash for VSI 6, error -5 + +Fixes: 352e9bf23813 ("ice: enable symmetric-xor RSS for Toeplitz hash function") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Signed-off-by: Marcin Szycik +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-5-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 055968485af6c..e290d224fe415 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -8046,7 +8046,7 @@ int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc) + ctx->info.q_opt_rss |= + FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hfunc); + ctx->info.q_opt_tc = vsi->info.q_opt_tc; +- ctx->info.q_opt_flags = vsi->info.q_opt_rss; ++ ctx->info.q_opt_flags = vsi->info.q_opt_flags; + + err = ice_update_vsi(hw, vsi->idx, ctx, NULL); + if (err) { +-- +2.53.0 + diff --git a/queue-7.0/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch b/queue-7.0/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch new file mode 100644 index 0000000000..7502049758 --- /dev/null +++ b/queue-7.0/idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch @@ -0,0 +1,91 @@ +From f7291d5b8d27e56caa4547908fb0600bc7237c36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 14:48:12 -0700 +Subject: idpf: fix read_dev_clk_lock spinlock init in idpf_ptp_init() + +From: Emil Tantilov + +[ Upstream commit da4f76b6a84ede14a71282ef841768299ead0221 ] + +In idpf_ptp_init(), read_dev_clk_lock is initialized after +ptp_schedule_worker() had already been called (and after +idpf_ptp_settime64() could reach the lock). The PTP aux worker +fires immediately upon scheduling and can call into +idpf_ptp_read_src_clk_reg_direct(), which takes +spin_lock(&ptp->read_dev_clk_lock) on an uninitialized lock, triggering +the lockdep "non-static key" warning: + +[12973.796587] idpf 0000:83:00.0: Device HW Reset initiated +[12974.094507] INFO: trying to register non-static key. +... +[12974.097208] Call Trace: +[12974.097213] +[12974.097218] dump_stack_lvl+0x93/0xe0 +[12974.097234] register_lock_class+0x4c4/0x4e0 +[12974.097249] ? __lock_acquire+0x427/0x2290 +[12974.097259] __lock_acquire+0x98/0x2290 +[12974.097272] lock_acquire+0xc6/0x310 +[12974.097281] ? idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097311] ? lockdep_hardirqs_on_prepare+0xde/0x190 +[12974.097318] ? finish_task_switch.isra.0+0xd2/0x350 +[12974.097330] ? __pfx_ptp_aux_kworker+0x10/0x10 [ptp] +[12974.097343] _raw_spin_lock+0x30/0x40 +[12974.097353] ? idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097373] idpf_ptp_read_src_clk_reg+0xb7/0x150 [idpf] +[12974.097391] ? kthread_worker_fn+0x88/0x3d0 +[12974.097404] ? kthread_worker_fn+0x4e/0x3d0 +[12974.097411] idpf_ptp_update_cached_phctime+0x26/0x120 [idpf] +[12974.097428] ? _raw_spin_unlock_irq+0x28/0x50 +[12974.097436] idpf_ptp_do_aux_work+0x15/0x20 [idpf] +[12974.097454] ptp_aux_kworker+0x20/0x40 [ptp] +[12974.097464] kthread_worker_fn+0xd5/0x3d0 +[12974.097474] ? __pfx_kthread_worker_fn+0x10/0x10 +[12974.097482] kthread+0xf4/0x130 +[12974.097489] ? __pfx_kthread+0x10/0x10 +[12974.097498] ret_from_fork+0x32c/0x410 +[12974.097512] ? __pfx_kthread+0x10/0x10 +[12974.097519] ret_from_fork_asm+0x1a/0x30 +[12974.097540] + +Move the call to spin_lock_init() up a bit to make sure read_dev_clk_lock +is not touched before it's been initialized. + +Fixes: 5cb8805d2366 ("idpf: negotiate PTP capabilities and get PTP clock") +Signed-off-by: Emil Tantilov +Reviewed-by: Madhu Chittim +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Samuel Salin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260506-jk-iwl-net-2026-05-04-v2-3-a5ea4dc837a9@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/idpf/idpf_ptp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +index eec91c4f0a75a..4a51d2727547d 100644 +--- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c ++++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +@@ -952,6 +952,8 @@ int idpf_ptp_init(struct idpf_adapter *adapter) + goto free_ptp; + } + ++ spin_lock_init(&adapter->ptp->read_dev_clk_lock); ++ + err = idpf_ptp_create_clock(adapter); + if (err) + goto free_ptp; +@@ -977,8 +979,6 @@ int idpf_ptp_init(struct idpf_adapter *adapter) + goto remove_clock; + } + +- spin_lock_init(&adapter->ptp->read_dev_clk_lock); +- + pci_dbg(adapter->pdev, "PTP init successful\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/iio-abi-fix-current_trigger-description.patch b/queue-7.0/iio-abi-fix-current_trigger-description.patch new file mode 100644 index 0000000000..afd5eac09f --- /dev/null +++ b/queue-7.0/iio-abi-fix-current_trigger-description.patch @@ -0,0 +1,35 @@ +From 6e03820e4b4337c72edc96bf87987b76c6a9358d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 20:02:02 +0200 +Subject: iio: ABI: fix current_trigger description + +From: Cosmin Tanislav + +[ Upstream commit 04bb8d0e5d1c8d5a9079b35b4e6f0868f734698b ] + +Triggers exist under /sys/bus/iio/devices/, not under /sys/class/iio. +/sys/class/iio does not even exist. Use the current path. + +Signed-off-by: Cosmin Tanislav +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + Documentation/ABI/testing/sysfs-bus-iio | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio +index 5f87dcee78f76..4fc9f6bd42812 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio ++++ b/Documentation/ABI/testing/sysfs-bus-iio +@@ -1428,7 +1428,7 @@ KernelVersion: 2.6.35 + Contact: linux-iio@vger.kernel.org + Description: + The name of the trigger source being used, as per string given +- in /sys/class/iio/triggerY/name. ++ in /sys/bus/iio/devices/triggerY/name. + + What: /sys/bus/iio/devices/iio:deviceX/bufferY/length + KernelVersion: 5.11 +-- +2.53.0 + diff --git a/queue-7.0/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch b/queue-7.0/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch new file mode 100644 index 0000000000..0996f2dd57 --- /dev/null +++ b/queue-7.0/iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch @@ -0,0 +1,39 @@ +From 3e09b0db076c177e4d57b822b6bae521fc912edc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:36:26 +0100 +Subject: iio: imu: st_lsm6dsx: Add ACPI ID for SHIFT13mi gyroscope + +From: Milan Misic + +[ Upstream commit 7913c1de9c3cbe3018fc29ce25a4d462ac2eaa82 ] + +The SHIFT13mi or SHIFTbook tablet device by the German manufacturer +SHIFT contains an STM LSM6DSO IMU declared in the DSDT with the +hardware ID SMOCF00. Add this ID to the ACPI match table so that the +driver binds correctly to this device. + +WHO_AM_I register returns 0x6c, confirming LSM6DSO. + +Signed-off-by: Milan Misic +Reviewed-by: Andy Shevchenko +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +index 7c933218036b8..b2a7c2eaf50dc 100644 +--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c ++++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +@@ -144,6 +144,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); + + static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { + { "SMO8B30", ST_LSM6DS3TRC_ID, }, ++ { "SMOCF00", ST_LSM6DSO_ID, }, + { } + }; + MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); +-- +2.53.0 + diff --git a/queue-7.0/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch b/queue-7.0/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch new file mode 100644 index 0000000000..dd7561d12f --- /dev/null +++ b/queue-7.0/ima-define-and-use-a-digest_size-field-in-the-ima_al.patch @@ -0,0 +1,149 @@ +From b84ecee1cfc4206da312b2d8517df43465811fc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 13:06:45 +0100 +Subject: ima: Define and use a digest_size field in the ima_algo_desc + structure + +From: Roberto Sassu + +[ Upstream commit a74d7197ebe5b1b8028911d47e78c119d9aaf193 ] + +Add the digest_size field to the ima_algo_desc structure to determine the +digest size from the correct source. + +If the hash algorithm is among allocated PCR banks, take the value from the +TPM bank info (equal to the value from the crypto subsystem if the TPM +algorithm is supported by it; otherwise, not exceding the size of the +digest buffer in the tpm_digest structure, used by IMA). + +If the hash algorithm is SHA1, use the predefined value. Lastly, if the +hash algorithm is the default one but not among the PCR banks, take the +digest size from the crypto subsystem (the default hash algorithm is +checked when parsing the ima_hash= command line option). + +Finally, use the new information to correctly show the template digest in +ima_measurements_show() and ima_ascii_measurements_show(). + +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima.h | 1 + + security/integrity/ima/ima_crypto.c | 6 ++++++ + security/integrity/ima/ima_fs.c | 18 ++++++------------ + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h +index 89ebe98ffc5e5..c38a9eb945b68 100644 +--- a/security/integrity/ima/ima.h ++++ b/security/integrity/ima/ima.h +@@ -53,6 +53,7 @@ extern atomic_t ima_setxattr_allowed_hash_algorithms; + struct ima_algo_desc { + struct crypto_shash *tfm; + enum hash_algo algo; ++ unsigned int digest_size; + }; + + /* set during initialization */ +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 85c433e39c008..8f680ef18d8c3 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -109,6 +109,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) + + int __init ima_init_crypto(void) + { ++ unsigned int digest_size; + enum hash_algo algo; + long rc; + int i; +@@ -147,7 +148,9 @@ int __init ima_init_crypto(void) + + for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) { + algo = ima_tpm_chip->allocated_banks[i].crypto_id; ++ digest_size = ima_tpm_chip->allocated_banks[i].digest_size; + ima_algo_array[i].algo = algo; ++ ima_algo_array[i].digest_size = digest_size; + + /* unknown TPM algorithm */ + if (algo == HASH_ALGO__LAST) +@@ -183,12 +186,15 @@ int __init ima_init_crypto(void) + } + + ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1; ++ ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE; + } + + if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) && + ima_hash_algo_idx != ima_sha1_idx) { ++ digest_size = hash_digest_size[ima_hash_algo]; + ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm; + ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo; ++ ima_algo_array[ima_hash_algo_idx].digest_size = digest_size; + } + + return 0; +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index f3c461ad7062b..ca4931a95098d 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v) + char *template_name; + u32 pcr, namelen, template_data_len; /* temporary fields */ + bool is_ima_template = false; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v) + ima_putc(m, &pcr, sizeof(e->pcr)); + + /* 2nd: template digest */ +- ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_putc(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3rd: template name size */ + namelen = !ima_canonical_fmt ? strlen(template_name) : +@@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + struct ima_queue_entry *qe = v; + struct ima_template_entry *e; + char *template_name; +- enum hash_algo algo; + int i, algo_idx; + + algo_idx = ima_sha1_idx; +- algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) { ++ if (m->file != NULL) + algo_idx = (unsigned long)file_inode(m->file)->i_private; +- algo = ima_algo_array[algo_idx].algo; +- } + + /* get entry */ + e = qe->entry; +@@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + seq_printf(m, "%2d ", e->pcr); + + /* 2nd: template hash */ +- ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]); ++ ima_print_digest(m, e->digests[algo_idx].digest, ++ ima_algo_array[algo_idx].digest_size); + + /* 3th: template name */ + seq_printf(m, " %s", template_name); +-- +2.53.0 + diff --git a/queue-7.0/io_uring-cancel-validate-opcode-for-ioring_async_can.patch b/queue-7.0/io_uring-cancel-validate-opcode-for-ioring_async_can.patch new file mode 100644 index 0000000000..02c72f1376 --- /dev/null +++ b/queue-7.0/io_uring-cancel-validate-opcode-for-ioring_async_can.patch @@ -0,0 +1,53 @@ +From ad47f6f43a596e6338cf547fa4d423d2cd30bc50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:51:13 +0330 +Subject: io_uring/cancel: validate opcode for IORING_ASYNC_CANCEL_OP + +From: Amir Mohammad Jahangirzad + +[ Upstream commit 85a58309c0d5b5f5a4b65658312ceaf2c34c9bbf ] + +io_async_cancel_prep() reads the opcode selector from sqe->len and +stores it in cancel->opcode, which is an 8-bit field. Since sqe->len +is a 32-bit value, values larger than U8_MAX are implicitly truncated. + +This can cause unintended opcode matches when the truncated value +corresponds to a valid io_uring opcode. For example, submitting a value +such as 0x10b will be truncated to 0x0b (IORING_OP_TIMEOUT), allowing a +cancel request to match operations it did not intend to target. +Validate the opcode value before assigning it to the 8-bit field and +reject values outside the valid io_uring opcode range. + +Signed-off-by: Amir Mohammad Jahangirzad +Link: https://patch.msgid.link/20260331232113.615972-1-a.jahangirzad@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/cancel.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/io_uring/cancel.c b/io_uring/cancel.c +index 65e04063e343b..5e5eb9cfc7cd6 100644 +--- a/io_uring/cancel.c ++++ b/io_uring/cancel.c +@@ -156,9 +156,16 @@ int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) + cancel->fd = READ_ONCE(sqe->fd); + } + if (cancel->flags & IORING_ASYNC_CANCEL_OP) { ++ u32 op; ++ + if (cancel->flags & IORING_ASYNC_CANCEL_ANY) + return -EINVAL; +- cancel->opcode = READ_ONCE(sqe->len); ++ ++ op = READ_ONCE(sqe->len); ++ if (op >= IORING_OP_LAST) ++ return -EINVAL; ++ ++ cancel->opcode = op; + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch b/queue-7.0/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch new file mode 100644 index 0000000000..c2d15e9ea5 --- /dev/null +++ b/queue-7.0/io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch @@ -0,0 +1,60 @@ +From 2bf97045a1fffd5347c9ec6a9dec5c8035c290c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 13:14:54 -0600 +Subject: io_uring/rsrc: unify nospec indexing for direct descriptors + +From: Jens Axboe + +[ Upstream commit 53262c91f7b81f96495ff24e9d1fa8b1632e69c8 ] + +For file updates, the node reset isn't capping the value via +array_index_nospec() like the other paths do. Ensure it's all sane and +have the update path do the proper capping as well. + +Reviewed-by: Gabriel Krisman Bertazi +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/rsrc.c | 3 +++ + io_uring/rsrc.h | 9 +++++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c +index 1b96ab5e98c99..7953f38af1eb0 100644 +--- a/io_uring/rsrc.c ++++ b/io_uring/rsrc.c +@@ -238,6 +238,9 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx, + continue; + + i = up->offset + done; ++ if (i >= ctx->file_table.data.nr) ++ break; ++ i = array_index_nospec(i, ctx->file_table.data.nr); + if (io_reset_rsrc_node(ctx, &ctx->file_table.data, i)) + io_file_bitmap_clear(&ctx->file_table, i); + +diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h +index cff0f8834c353..44e3386f7c1ca 100644 +--- a/io_uring/rsrc.h ++++ b/io_uring/rsrc.h +@@ -109,10 +109,15 @@ static inline void io_put_rsrc_node(struct io_ring_ctx *ctx, struct io_rsrc_node + } + + static inline bool io_reset_rsrc_node(struct io_ring_ctx *ctx, +- struct io_rsrc_data *data, int index) ++ struct io_rsrc_data *data, ++ unsigned int index) + { +- struct io_rsrc_node *node = data->nodes[index]; ++ struct io_rsrc_node *node; + ++ if (index >= data->nr) ++ return false; ++ index = array_index_nospec(index, data->nr); ++ node = data->nodes[index]; + if (!node) + return false; + io_put_rsrc_node(ctx, node); +-- +2.53.0 + diff --git a/queue-7.0/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch b/queue-7.0/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch new file mode 100644 index 0000000000..e66de2c5b5 --- /dev/null +++ b/queue-7.0/io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch @@ -0,0 +1,112 @@ +From bce63b0f85bbf0e9917de0ed56d76f61fe4630be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 15:46:16 +0200 +Subject: io_uring: take page references for NOMMU pbuf_ring mmaps + +From: Greg Kroah-Hartman + +[ Upstream commit d0be8884f56b0b800cd8966e37ce23417cd5044e ] + +Under !CONFIG_MMU, io_uring_get_unmapped_area() returns the kernel +virtual address of the io_mapped_region's backing pages directly; +the user's VMA aliases the kernel allocation. io_uring_mmap() then +just returns 0 -- it takes no page references. + +The CONFIG_MMU path uses vm_insert_pages(), which takes a reference on +each inserted page. Those references are released when the VMA is torn +down (zap_pte_range -> put_page). io_free_region() -> release_pages() +drops the io_uring-side references, but the pages survive until munmap +drops the VMA-side references. + +Under NOMMU there are no VMA-side references. io_unregister_pbuf_ring -> +io_put_bl -> io_free_region -> release_pages drops the only references +and the pages return to the buddy allocator while the user's VMA still +has vm_start pointing into them. The user can then write into whatever +the allocator hands out next. + +Mirror the MMU lifetime: take get_page references in io_uring_mmap() and +release them via vm_ops->close. NOMMU's delete_vma() calls vma_close() +which runs ->close on munmap. + +This also incidentally addresses the duplicate-vm_start case: two mmaps +of SQ_RING and CQ_RING resolve to the same ctx->ring_region pointer. +With page refs taken per mmap, the second mmap takes its own refs and +the pages survive until both mmaps are closed. The nommu rb-tree BUG_ON +on duplicate vm_start is a separate mm/nommu.c concern (it should share +the existing region rather than BUG), but the page lifetime is now +correct. + +Cc: Jens Axboe +Reported-by: Anthropic +Assisted-by: gkh_clanker_t1000 +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026042115-body-attention-d15b@gregkh +[axboe: get rid of region lookup, just iterate pages in vma] +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/memmap.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 45 insertions(+), 1 deletion(-) + +diff --git a/io_uring/memmap.c b/io_uring/memmap.c +index e6958968975a8..4f9b439319c46 100644 +--- a/io_uring/memmap.c ++++ b/io_uring/memmap.c +@@ -366,9 +366,53 @@ unsigned long io_uring_get_unmapped_area(struct file *filp, unsigned long addr, + + #else /* !CONFIG_MMU */ + ++/* ++ * Drop the pages that were initially referenced and added in ++ * io_uring_mmap(). We cannot have had a mremap() as that isn't supported, ++ * hence the vma should be identical to the one we initially referenced and ++ * mapped, and partial unmaps and splitting isn't possible on a file backed ++ * mapping. ++ */ ++static void io_uring_nommu_vm_close(struct vm_area_struct *vma) ++{ ++ unsigned long index; ++ ++ for (index = vma->vm_start; index < vma->vm_end; index += PAGE_SIZE) ++ put_page(virt_to_page((void *) index)); ++} ++ ++static const struct vm_operations_struct io_uring_nommu_vm_ops = { ++ .close = io_uring_nommu_vm_close, ++}; ++ + int io_uring_mmap(struct file *file, struct vm_area_struct *vma) + { +- return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -EINVAL; ++ struct io_ring_ctx *ctx = file->private_data; ++ struct io_mapped_region *region; ++ unsigned long i; ++ ++ if (!is_nommu_shared_mapping(vma->vm_flags)) ++ return -EINVAL; ++ ++ guard(mutex)(&ctx->mmap_lock); ++ region = io_mmap_get_region(ctx, vma->vm_pgoff); ++ if (!region || !io_region_is_set(region)) ++ return -EINVAL; ++ ++ if ((vma->vm_end - vma->vm_start) != ++ (unsigned long) region->nr_pages << PAGE_SHIFT) ++ return -EINVAL; ++ ++ /* ++ * Pin the pages so io_free_region()'s release_pages() does not ++ * drop the last reference while this VMA exists. delete_vma() ++ * in mm/nommu.c calls vma_close() which runs ->close above. ++ */ ++ for (i = 0; i < region->nr_pages; i++) ++ get_page(region->pages[i]); ++ ++ vma->vm_ops = &io_uring_nommu_vm_ops; ++ return 0; + } + + unsigned int io_uring_nommu_mmap_capabilities(struct file *file) +-- +2.53.0 + diff --git a/queue-7.0/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch b/queue-7.0/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch new file mode 100644 index 0000000000..2965c35c61 --- /dev/null +++ b/queue-7.0/iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch @@ -0,0 +1,142 @@ +From 39c4f56a12792e6f3298d0588c9fcc734f2074c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 15:37:54 +0800 +Subject: iommu/amd: Fix illegal cap/mmio access in IOMMU debugfs + +From: Guanghui Feng + +[ Upstream commit 0e59645683b7b6fa20eceb21a6f420e4f7412943 ] + +In the current AMD IOMMU debugfs, when multiple processes simultaneously +access the IOMMU mmio/cap registers using the IOMMU debugfs, illegal +access issues can occur in the following execution flow: + +1. CPU1: Sets a valid access address using iommu_mmio/capability_write, +and verifies the access address's validity in iommu_mmio/capability_show + +2. CPU2: Sets an invalid address using iommu_mmio/capability_write + +3. CPU1: accesses the IOMMU mmio/cap registers based on the invalid +address, resulting in an illegal access. + +This patch modifies the execution process to first verify the address's +validity and then access it based on the same address, ensuring +correctness and robustness. + +Signed-off-by: Guanghui Feng +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/debugfs.c | 42 +++++++++++++++++-------------------- + 1 file changed, 19 insertions(+), 23 deletions(-) + +diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c +index 0b03e0622f67e..4e66473d7ceaf 100644 +--- a/drivers/iommu/amd/debugfs.c ++++ b/drivers/iommu/amd/debugfs.c +@@ -26,22 +26,19 @@ static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf, + { + struct seq_file *m = filp->private_data; + struct amd_iommu *iommu = m->private; +- int ret; +- +- iommu->dbg_mmio_offset = -1; ++ int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1; + + if (cnt > OFS_IN_SZ) + return -EINVAL; + +- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_mmio_offset); ++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_mmio_offset); + if (ret) + return ret; + +- if (iommu->dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) { +- iommu->dbg_mmio_offset = -1; +- return -EINVAL; +- } ++ if (dbg_mmio_offset > iommu->mmio_phys_end - sizeof(u64)) ++ return -EINVAL; + ++ iommu->dbg_mmio_offset = dbg_mmio_offset; + return cnt; + } + +@@ -49,14 +46,16 @@ static int iommu_mmio_show(struct seq_file *m, void *unused) + { + struct amd_iommu *iommu = m->private; + u64 value; ++ int dbg_mmio_offset = iommu->dbg_mmio_offset; + +- if (iommu->dbg_mmio_offset < 0) { ++ if (dbg_mmio_offset < 0 || dbg_mmio_offset > ++ iommu->mmio_phys_end - sizeof(u64)) { + seq_puts(m, "Please provide mmio register's offset\n"); + return 0; + } + +- value = readq(iommu->mmio_base + iommu->dbg_mmio_offset); +- seq_printf(m, "Offset:0x%x Value:0x%016llx\n", iommu->dbg_mmio_offset, value); ++ value = readq(iommu->mmio_base + dbg_mmio_offset); ++ seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value); + + return 0; + } +@@ -67,23 +66,20 @@ static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf + { + struct seq_file *m = filp->private_data; + struct amd_iommu *iommu = m->private; +- int ret; +- +- iommu->dbg_cap_offset = -1; ++ int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1; + + if (cnt > OFS_IN_SZ) + return -EINVAL; + +- ret = kstrtou32_from_user(ubuf, cnt, 0, &iommu->dbg_cap_offset); ++ ret = kstrtou32_from_user(ubuf, cnt, 0, &dbg_cap_offset); + if (ret) + return ret; + + /* Capability register at offset 0x14 is the last IOMMU capability register. */ +- if (iommu->dbg_cap_offset > 0x14) { +- iommu->dbg_cap_offset = -1; ++ if (dbg_cap_offset > 0x14) + return -EINVAL; +- } + ++ iommu->dbg_cap_offset = dbg_cap_offset; + return cnt; + } + +@@ -91,21 +87,21 @@ static int iommu_capability_show(struct seq_file *m, void *unused) + { + struct amd_iommu *iommu = m->private; + u32 value; +- int err; ++ int err, dbg_cap_offset = iommu->dbg_cap_offset; + +- if (iommu->dbg_cap_offset < 0) { ++ if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) { + seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n"); + return 0; + } + +- err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + iommu->dbg_cap_offset, &value); ++ err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value); + if (err) { + seq_printf(m, "Not able to read capability register at 0x%x\n", +- iommu->dbg_cap_offset); ++ dbg_cap_offset); + return 0; + } + +- seq_printf(m, "Offset:0x%x Value:0x%08x\n", iommu->dbg_cap_offset, value); ++ seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch b/queue-7.0/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch new file mode 100644 index 0000000000..ae42eaec12 --- /dev/null +++ b/queue-7.0/iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch @@ -0,0 +1,104 @@ +From a061f0ec831d3dac01f9e266a6280c691a178d39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 15:37:53 +0800 +Subject: iommu/amd: Fix illegal device-id access in IOMMU debugfs + +From: Guanghui Feng + +[ Upstream commit e4172c5b53fba04fa48b13bc3afde809d0087a7f ] + +In the current AMD IOMMU debugFS, when multiple processes use the IOMMU +debugFS process simultaneously, illegal access issues can occur in the +following execution flow: + +1. CPU1: Sets a valid sbdf via devid_write, then checks the sbdf's +validity in execution flows such as devid_show, iommu_devtbl_show, +and iommu_irqtbl_show. + +2. CPU2: Sets an invalid sbdf via devid_write, at which point the sbdf +value is -1. + +3. CPU1: accesses the IOMMU device table, IRQ table, based on the +invalid SBDF value of -1, resulting in illegal access. + +This is especially problematic in monitoring scripts, where multiple +scripts may access debugFS simultaneously, and some scripts may +unexpectedly set invalid values, which triggers illegal access in +debugfs. + +This patch modifies the execution flow of devid_show, +iommu_devtbl_show, and iommu_irqtbl_show to ensure that these +processes determine the validity and access based on the +same device-id, thus guaranteeing correctness and robustness. + +Signed-off-by: Guanghui Feng +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/debugfs.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c +index 20b04996441d6..0b03e0622f67e 100644 +--- a/drivers/iommu/amd/debugfs.c ++++ b/drivers/iommu/amd/debugfs.c +@@ -197,10 +197,11 @@ static ssize_t devid_write(struct file *filp, const char __user *ubuf, + static int devid_show(struct seq_file *m, void *unused) + { + u16 devid; ++ int sbdf_shadow = sbdf; + +- if (sbdf >= 0) { +- devid = PCI_SBDF_TO_DEVID(sbdf); +- seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf), ++ if (sbdf_shadow >= 0) { ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); ++ seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf_shadow), + PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid)); + } else + seq_puts(m, "No or Invalid input provided\n"); +@@ -237,13 +238,14 @@ static int iommu_devtbl_show(struct seq_file *m, void *unused) + { + struct amd_iommu_pci_seg *pci_seg; + u16 seg, devid; ++ int sbdf_shadow = sbdf; + +- if (sbdf < 0) { ++ if (sbdf_shadow < 0) { + seq_puts(m, "Enter a valid device ID to 'devid' file\n"); + return 0; + } +- seg = PCI_SBDF_TO_SEGID(sbdf); +- devid = PCI_SBDF_TO_DEVID(sbdf); ++ seg = PCI_SBDF_TO_SEGID(sbdf_shadow); ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); + + for_each_pci_segment(pci_seg) { + if (pci_seg->id != seg) +@@ -336,19 +338,20 @@ static int iommu_irqtbl_show(struct seq_file *m, void *unused) + { + struct amd_iommu_pci_seg *pci_seg; + u16 devid, seg; ++ int sbdf_shadow = sbdf; + + if (!irq_remapping_enabled) { + seq_puts(m, "Interrupt remapping is disabled\n"); + return 0; + } + +- if (sbdf < 0) { ++ if (sbdf_shadow < 0) { + seq_puts(m, "Enter a valid device ID to 'devid' file\n"); + return 0; + } + +- seg = PCI_SBDF_TO_SEGID(sbdf); +- devid = PCI_SBDF_TO_DEVID(sbdf); ++ seg = PCI_SBDF_TO_SEGID(sbdf_shadow); ++ devid = PCI_SBDF_TO_DEVID(sbdf_shadow); + + for_each_pci_segment(pci_seg) { + if (pci_seg->id != seg) +-- +2.53.0 + diff --git a/queue-7.0/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch b/queue-7.0/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch new file mode 100644 index 0000000000..ede685c590 --- /dev/null +++ b/queue-7.0/iommu-amd-invalidate-irt-cache-for-dma-aliases.patch @@ -0,0 +1,98 @@ +From 41af1db3a0348c18c27e0b6d0b540322d7a02f00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 09:42:50 +0200 +Subject: iommu/amd: Invalidate IRT cache for DMA aliases + +From: Magnus Kalland + +[ Upstream commit 5aac28784dca6819e96e5f93e644cdee59e50f6e ] + +DMA aliasing causes interrupt remapping table entries (IRTEs) to be shared +between multiple device IDs. See commit 3c124435e8dd +("iommu/amd: Support multiple PCI DMA aliases in IRQ Remapping") for more +information on this. However, the AMD IOMMU driver currently invalidates +IRTE cache entries on a per-device basis whenever an IRTE is updated, not +for each alias. + +This approach leaves stale IRTE cache entries when an IRTE is cached under +one DMA alias but later updated and invalidated through a different alias. +In such cases, the original device ID is never invalidated, since it is +programmed via aliasing. + +This incoherency bug has been observed when IRTEs are cached for one +Non-Transparent Bridge (NTB) DMA alias, later updated via another. + +Fix this by invalidating the interrupt remapping table cache for all DMA +aliases when updating an IRTE. + +Co-developed-by: Lars B. Kristiansen +Signed-off-by: Lars B. Kristiansen +Co-developed-by: Jonas Markussen +Signed-off-by: Jonas Markussen +Co-developed-by: Tore H. Larsen +Signed-off-by: Tore H. Larsen +Signed-off-by: Magnus Kalland +Link: https://lore.kernel.org/linux-iommu/9204da81-f821-4034-b8ad-501e43383b56@amd.com/ +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 72f1f6e28138d..4516e5868fc4e 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -3184,26 +3184,44 @@ const struct iommu_ops amd_iommu_ops = { + static struct irq_chip amd_ir_chip; + static DEFINE_SPINLOCK(iommu_table_lock); + ++static int iommu_flush_dev_irt(struct pci_dev *unused, u16 devid, void *data) ++{ ++ int ret; ++ struct iommu_cmd cmd; ++ struct amd_iommu *iommu = data; ++ ++ build_inv_irt(&cmd, devid); ++ ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ return ret; ++} ++ + static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid) + { + int ret; + u64 data; + unsigned long flags; +- struct iommu_cmd cmd, cmd2; ++ struct iommu_cmd cmd; ++ struct pci_dev *pdev = NULL; ++ struct iommu_dev_data *dev_data = search_dev_data(iommu, devid); + + if (iommu->irtcachedis_enabled) + return; + +- build_inv_irt(&cmd, devid); ++ if (dev_data && dev_data->dev && dev_is_pci(dev_data->dev)) ++ pdev = to_pci_dev(dev_data->dev); + + raw_spin_lock_irqsave(&iommu->lock, flags); + data = get_cmdsem_val(iommu); +- build_completion_wait(&cmd2, iommu, data); ++ build_completion_wait(&cmd, iommu, data); + +- ret = __iommu_queue_command_sync(iommu, &cmd, true); ++ if (pdev) ++ ret = pci_for_each_dma_alias(pdev, iommu_flush_dev_irt, iommu); ++ else ++ ret = iommu_flush_dev_irt(NULL, devid, iommu); + if (ret) + goto out_err; +- ret = __iommu_queue_command_sync(iommu, &cmd2, false); ++ ++ ret = __iommu_queue_command_sync(iommu, &cmd, false); + if (ret) + goto out_err; + raw_spin_unlock_irqrestore(&iommu->lock, flags); +-- +2.53.0 + diff --git a/queue-7.0/iommu-fix-kdocs-of-pci_dev_reset_iommu_done.patch b/queue-7.0/iommu-fix-kdocs-of-pci_dev_reset_iommu_done.patch new file mode 100644 index 0000000000..aca6a2db7d --- /dev/null +++ b/queue-7.0/iommu-fix-kdocs-of-pci_dev_reset_iommu_done.patch @@ -0,0 +1,43 @@ +From ed54362b16dc85c8c036f9a507404781f03656ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 18:15:21 -0700 +Subject: iommu: Fix kdocs of pci_dev_reset_iommu_done() + +From: Nicolin Chen + +[ Upstream commit 834ab85aa96656f87bb215a8285d34af870f4b66 ] + +Remove the duplicated word. No functional change. + +Fixes: c279e83953d9 ("iommu: Introduce pci_dev_reset_iommu_prepare/done()") +Reviewed-by: Shuai Xue +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Lu Baolu +Signed-off-by: Nicolin Chen +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommu.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index ef08c2c4ec95b..d48e28ae1ebfc 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -4072,9 +4072,9 @@ EXPORT_SYMBOL_GPL(pci_dev_reset_iommu_prepare); + * @pdev: PCI device that has finished a reset routine + * + * After a PCIe device finishes a reset routine, it wants to restore its IOMMU +- * IOMMU activity, including new translation as well as cache invalidation, by +- * re-attaching all RID/PASID of the device's back to the domains retained in +- * the core-level structure. ++ * activity, including new translation and cache invalidation, by re-attaching ++ * all RID/PASID of the device back to the domains retained in the core-level ++ * structure. + * + * Caller must pair it with a successful pci_dev_reset_iommu_prepare(). + * +-- +2.53.0 + diff --git a/queue-7.0/iommu-fix-loss-of-errno-on-map-failure-for-classic-o.patch b/queue-7.0/iommu-fix-loss-of-errno-on-map-failure-for-classic-o.patch new file mode 100644 index 0000000000..177930131d --- /dev/null +++ b/queue-7.0/iommu-fix-loss-of-errno-on-map-failure-for-classic-o.patch @@ -0,0 +1,52 @@ +From 67371bf91fe0ca7e3bf76ba8769a60d521a64701 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:46:13 -0300 +Subject: iommu: Fix loss of errno on map failure for classic ops + +From: Jason Gunthorpe + +[ Upstream commit 6fc7e8a3b8115294f60f5c89de27330bf1b9c98e ] + +A typo, likely from a rebase, inverted the condition and caused +errors to be lost. Fix it to be "if (ret)". + +This was breaking iommu_create_device_direct_mappings() on drivers +that don't use iommupt and don't fully set up their domain in +alloc_pages() (i.e., SMMUv2). In this case the first call of +iommu_create_device_direct_mappings() should fail due to the +incompletely initialized domain. Since it wrongly returns success, +the second call to iommu_create_device_direct_mappings() doesn't +happen and IOMMU_RESV_DIRECT is never set up. + +Cc: stable@vger.kernel.org +Fixes: d6c65b0fd621 ("iommupt: Avoid rewalking during map") +Reported-by: Josua Mayer +Closes: https://lore.kernel.org/all/321c2e57-6a17-4aef-ba42-d2ebd577e472@solid-run.com/ +Signed-off-by: Jason Gunthorpe +Reviewed-by: Pranjal Shrivastava +Reviewed-by: Samiullah Khawaja +Reviewed-by: Mostafa Saleh +Tested-by: Josua Mayer +Signed-off-by: Joerg Roedel +Stable-dep-of: 0735c54804c7 ("iommu: Handle unmap error when iommu_debug is enabled") +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 845284a9eeaf4..280d7ed7e3a23 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2709,7 +2709,7 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + return 0; + } + ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot, gfp); +- if (!ret) ++ if (ret) + return ret; + + trace_map(iova, paddr, size); +-- +2.53.0 + diff --git a/queue-7.0/iommu-fix-up-map-unmap-debugging-for-iommupt-domains.patch b/queue-7.0/iommu-fix-up-map-unmap-debugging-for-iommupt-domains.patch new file mode 100644 index 0000000000..ee62856729 --- /dev/null +++ b/queue-7.0/iommu-fix-up-map-unmap-debugging-for-iommupt-domains.patch @@ -0,0 +1,141 @@ +From 03aea3dc52b9bfa57f4de0ac95bdb8dbce03e427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:46:14 -0300 +Subject: iommu: Fix up map/unmap debugging for iommupt domains + +From: Jason Gunthorpe + +[ Upstream commit b948a87228482235afbaf5f4d8037860b5c470fd ] + +Sashiko noticed a few issues in this path, and a few more were +found on review. Tidy them up further. These are intertwined +because the debug code depends on some of the WARN_ONs to function +right: + +Lift into iommu_map_nosync(): +- The might_sleep_if() +- 0 pgsize_bitmap WARN_ON +- Promote the illegal domain->type to a WARN_ON +- WARN_ON for illegal gfp flags + +Then remove the return 0 since it is now safe to call +iommu_debug_map(). + +Lift into __iommu_unmap(): +- 0 pgsize_bitmap WARN_ON +- Promote the illegal domain->type to a WARN_ON +- iommu_debug_unmap_begin() + +This now pairs with the unconditional iommu_debug_map() on the +mapping side. Thus iommu debugging now works for iommupt along +with some of the other debugging features. + +Fixes: 99fb8afa16ad ("iommupt: Directly call iommupt's unmap_range()") +Fixes: d6c65b0fd621 ("iommupt: Avoid rewalking during map") +Signed-off-by: Jason Gunthorpe +Reviewed-by: Pranjal Shrivastava +Reviewed-by: Samiullah Khawaja +Reviewed-by: Mostafa Saleh +Tested-by: Josua Mayer +Signed-off-by: Joerg Roedel +Stable-dep-of: 0735c54804c7 ("iommu: Handle unmap error when iommu_debug is enabled") +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommu.c | 43 ++++++++++++++++++++++--------------------- + 1 file changed, 22 insertions(+), 21 deletions(-) + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 280d7ed7e3a23..f0d46ea4d6a51 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2623,19 +2623,9 @@ static int __iommu_map_domain_pgtbl(struct iommu_domain *domain, + size_t orig_size = size; + int ret = 0; + +- might_sleep_if(gfpflags_allow_blocking(gfp)); +- +- if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) +- return -EINVAL; +- +- if (WARN_ON(!ops->map_pages || domain->pgsize_bitmap == 0UL)) ++ if (WARN_ON(!ops->map_pages)) + return -ENODEV; + +- /* Discourage passing strange GFP flags */ +- if (WARN_ON_ONCE(gfp & (__GFP_COMP | __GFP_DMA | __GFP_DMA32 | +- __GFP_HIGHMEM))) +- return -EINVAL; +- + /* find out the minimum page size supported */ + min_pagesz = 1 << __ffs(domain->pgsize_bitmap); + +@@ -2697,6 +2687,15 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + struct pt_iommu *pt = iommupt_from_domain(domain); + int ret; + ++ might_sleep_if(gfpflags_allow_blocking(gfp)); ++ ++ /* Discourage passing strange GFP flags or illegal domains */ ++ if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING) || ++ !domain->pgsize_bitmap || ++ (gfp & (__GFP_COMP | __GFP_DMA | __GFP_DMA32 | ++ __GFP_HIGHMEM)))) ++ return -EINVAL; ++ + if (pt) { + size_t mapped = 0; + +@@ -2706,11 +2705,12 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + iommu_unmap(domain, iova, mapped); + return ret; + } +- return 0; ++ } else { ++ ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot, ++ gfp); ++ if (ret) ++ return ret; + } +- ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot, gfp); +- if (ret) +- return ret; + + trace_map(iova, paddr, size); + iommu_debug_map(domain, paddr, size); +@@ -2742,10 +2742,7 @@ __iommu_unmap_domain_pgtbl(struct iommu_domain *domain, unsigned long iova, + size_t unmapped_page, unmapped = 0; + unsigned int min_pagesz; + +- if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) +- return 0; +- +- if (WARN_ON(!ops->unmap_pages || domain->pgsize_bitmap == 0UL)) ++ if (WARN_ON(!ops->unmap_pages)) + return 0; + + /* find out the minimum page size supported */ +@@ -2764,8 +2761,6 @@ __iommu_unmap_domain_pgtbl(struct iommu_domain *domain, unsigned long iova, + + pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size); + +- iommu_debug_unmap_begin(domain, iova, size); +- + /* + * Keep iterating until we either unmap 'size' bytes (or more) + * or we hit an area that isn't mapped. +@@ -2801,6 +2796,12 @@ static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long iova, + struct pt_iommu *pt = iommupt_from_domain(domain); + size_t unmapped; + ++ if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING) || ++ !domain->pgsize_bitmap)) ++ return 0; ++ ++ iommu_debug_unmap_begin(domain, iova, size); ++ + if (pt) + unmapped = pt->ops->unmap_range(pt, iova, size, iotlb_gather); + else +-- +2.53.0 + diff --git a/queue-7.0/iommu-handle-unmap-error-when-iommu_debug-is-enabled.patch b/queue-7.0/iommu-handle-unmap-error-when-iommu_debug-is-enabled.patch new file mode 100644 index 0000000000..8e61325ee5 --- /dev/null +++ b/queue-7.0/iommu-handle-unmap-error-when-iommu_debug-is-enabled.patch @@ -0,0 +1,134 @@ +From 284f6d840508d966ac8efc921d9689a43f0f9d0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:46:15 -0300 +Subject: iommu: Handle unmap error when iommu_debug is enabled + +From: Jason Gunthorpe + +[ Upstream commit 0735c54804c709d1b292f3b6947cfb560b2ce552 ] + +Sashiko noticed a latent bug where the map error flow called iommu_unmap() +which calls iommu_debug_unmap_begin()/iommu_debug_unmap_end() however +since this is an error path the map flow never actually established the +original iommu_debug_map() it will malfunction. + +Lift the unmap error handling into iommu_map_nosync() and reorder it so +the trace_map()/iommu_debug_map() records the partial mapping and then +immediately unmaps it. This avoid creating the unbalanced tracking and +provides saner tracing instead of a unmap unmatched to any map. + +Fixes: ccc21213f013 ("iommu: Add calls for IOMMU_DEBUG_PAGEALLOC") +Signed-off-by: Jason Gunthorpe +Reviewed-by: Pranjal Shrivastava +Reviewed-by: Samiullah Khawaja +Reviewed-by: Mostafa Saleh +Tested-by: Josua Mayer +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommu.c | 49 +++++++++++++++++-------------------------- + 1 file changed, 19 insertions(+), 30 deletions(-) + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index f0d46ea4d6a51..76cafbaadefa2 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2615,12 +2615,11 @@ static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova, + + static int __iommu_map_domain_pgtbl(struct iommu_domain *domain, + unsigned long iova, phys_addr_t paddr, +- size_t size, int prot, gfp_t gfp) ++ size_t size, int prot, gfp_t gfp, ++ size_t *mapped) + { + const struct iommu_domain_ops *ops = domain->ops; +- unsigned long orig_iova = iova; + unsigned int min_pagesz; +- size_t orig_size = size; + int ret = 0; + + if (WARN_ON(!ops->map_pages)) +@@ -2643,31 +2642,25 @@ static int __iommu_map_domain_pgtbl(struct iommu_domain *domain, + pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); + + while (size) { +- size_t pgsize, count, mapped = 0; ++ size_t pgsize, count, op_mapped = 0; + + pgsize = iommu_pgsize(domain, iova, paddr, size, &count); + + pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %zu\n", + iova, &paddr, pgsize, count); + ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot, +- gfp, &mapped); ++ gfp, &op_mapped); + /* + * Some pages may have been mapped, even if an error occurred, + * so we should account for those so they can be unmapped. + */ +- size -= mapped; +- ++ *mapped += op_mapped; + if (ret) +- break; +- +- iova += mapped; +- paddr += mapped; +- } ++ return ret; + +- /* unroll mapping in case something went wrong */ +- if (ret) { +- iommu_unmap(domain, orig_iova, orig_size - size); +- return ret; ++ size -= op_mapped; ++ iova += op_mapped; ++ paddr += op_mapped; + } + return 0; + } +@@ -2685,6 +2678,7 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct pt_iommu *pt = iommupt_from_domain(domain); ++ size_t mapped = 0; + int ret; + + might_sleep_if(gfpflags_allow_blocking(gfp)); +@@ -2696,24 +2690,19 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + __GFP_HIGHMEM)))) + return -EINVAL; + +- if (pt) { +- size_t mapped = 0; +- ++ if (pt) + ret = pt->ops->map_range(pt, iova, paddr, size, prot, gfp, + &mapped); +- if (ret) { +- iommu_unmap(domain, iova, mapped); +- return ret; +- } +- } else { ++ else + ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot, +- gfp); +- if (ret) +- return ret; +- } ++ gfp, &mapped); + +- trace_map(iova, paddr, size); +- iommu_debug_map(domain, paddr, size); ++ trace_map(iova, paddr, mapped); ++ iommu_debug_map(domain, paddr, mapped); ++ if (ret) { ++ iommu_unmap(domain, iova, mapped); ++ return ret; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/iommu-iova-add-null-check-in-iova_magazine_free.patch b/queue-7.0/iommu-iova-add-null-check-in-iova_magazine_free.patch new file mode 100644 index 0000000000..e9b19dd33e --- /dev/null +++ b/queue-7.0/iommu-iova-add-null-check-in-iova_magazine_free.patch @@ -0,0 +1,49 @@ +From 34fbe49b4c06fa8b950f84f84e705aa2dde44625 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Feb 2026 08:09:19 +0000 +Subject: iommu/iova: Add NULL check in iova_magazine_free() + +From: lynn + +[ Upstream commit fa8fb60d36375ca3166a60589a624f0d0bc9ddb5 ] + +When iova_domain_init_rcaches() fails to allocate an iova_magazine +during the initialization of per-cpu rcaches, it jumps to out_err and +calls free_iova_rcaches() for cleanup. + +In free_iova_rcaches(), the code iterates through all possible CPUs to +free both cpu_rcache->loaded and cpu_rcache->prev. However, if the +original allocation failed mid-way through the CPU loop, the pointers +for the remaining CPUs remain NULL. + +Since kmem_cache_free() does not explicitly handle NULL pointers like +kfree() does, passing these NULL pointers leads to a kernel paging +request fault. + +Add a NULL check in iova_magazine_free() to safely handle partially +initialized rcaches in error paths. + +Signed-off-by: lynn +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/iova.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c +index f9cd18316d16b..021daf6528de1 100644 +--- a/drivers/iommu/iova.c ++++ b/drivers/iommu/iova.c +@@ -611,7 +611,8 @@ static struct iova_magazine *iova_magazine_alloc(gfp_t flags) + + static void iova_magazine_free(struct iova_magazine *mag) + { +- kmem_cache_free(iova_magazine_cache, mag); ++ if (mag) ++ kmem_cache_free(iova_magazine_cache, mag); + } + + static void +-- +2.53.0 + diff --git a/queue-7.0/iommupt-avoid-rewalking-during-map.patch b/queue-7.0/iommupt-avoid-rewalking-during-map.patch new file mode 100644 index 0000000000..f9d65cb883 --- /dev/null +++ b/queue-7.0/iommupt-avoid-rewalking-during-map.patch @@ -0,0 +1,493 @@ +From c585f02f83617d8f58b98dd1e2f498e0e4203d0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:30:11 -0400 +Subject: iommupt: Avoid rewalking during map + +From: Jason Gunthorpe + +[ Upstream commit d6c65b0fd6218bd21ed0be7a8d3218e8f6dc91de ] + +Currently the core code provides a simplified interface to drivers where +it fragments a requested multi-page map into single page size steps after +doing all the calculations to figure out what page size is +appropriate. Each step rewalks the page tables from the start. + +Since iommupt has a single implementation of the mapping algorithm it can +internally compute each step as it goes while retaining its current +position in the walk. + +Add a new function pt_pgsz_count() which computes the same page size +fragement of a large mapping operations. + +Compute the next fragment when all the leaf entries of the current +fragement have been written, then continue walking from the current +point. + +The function pointer is run through pt_iommu_ops instead of +iommu_domain_ops to discourage using it outside iommupt. All drivers with +their own page tables should continue to use the simplified map_pages() +style interfaces. + +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Signed-off-by: Jason Gunthorpe +Reviewed-by: Lu Baolu +Signed-off-by: Joerg Roedel +Stable-dep-of: 0735c54804c7 ("iommu: Handle unmap error when iommu_debug is enabled") +Signed-off-by: Sasha Levin +--- + drivers/iommu/generic_pt/iommu_pt.h | 133 ++++++++++++-------- + drivers/iommu/generic_pt/kunit_generic_pt.h | 12 ++ + drivers/iommu/generic_pt/pt_iter.h | 22 ++++ + drivers/iommu/iommu.c | 39 ++++-- + include/linux/generic_pt/iommu.h | 34 ++++- + 5 files changed, 175 insertions(+), 65 deletions(-) + +diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h +index 8bc4683a64dc1..c0241b24a6098 100644 +--- a/drivers/iommu/generic_pt/iommu_pt.h ++++ b/drivers/iommu/generic_pt/iommu_pt.h +@@ -466,6 +466,7 @@ struct pt_iommu_map_args { + pt_oaddr_t oa; + unsigned int leaf_pgsize_lg2; + unsigned int leaf_level; ++ pt_vaddr_t num_leaves; + }; + + /* +@@ -518,11 +519,15 @@ static int clear_contig(const struct pt_state *start_pts, + static int __map_range_leaf(struct pt_range *range, void *arg, + unsigned int level, struct pt_table_p *table) + { ++ struct pt_iommu *iommu_table = iommu_from_common(range->common); + struct pt_state pts = pt_init(range, level, table); + struct pt_iommu_map_args *map = arg; + unsigned int leaf_pgsize_lg2 = map->leaf_pgsize_lg2; + unsigned int start_index; + pt_oaddr_t oa = map->oa; ++ unsigned int num_leaves; ++ unsigned int orig_end; ++ pt_vaddr_t last_va; + unsigned int step; + bool need_contig; + int ret = 0; +@@ -536,6 +541,15 @@ static int __map_range_leaf(struct pt_range *range, void *arg, + + _pt_iter_first(&pts); + start_index = pts.index; ++ orig_end = pts.end_index; ++ if (pts.index + map->num_leaves < pts.end_index) { ++ /* Need to stop in the middle of the table to change sizes */ ++ pts.end_index = pts.index + map->num_leaves; ++ num_leaves = 0; ++ } else { ++ num_leaves = map->num_leaves - (pts.end_index - pts.index); ++ } ++ + do { + pts.type = pt_load_entry_raw(&pts); + if (pts.type != PT_ENTRY_EMPTY || need_contig) { +@@ -561,7 +575,40 @@ static int __map_range_leaf(struct pt_range *range, void *arg, + flush_writes_range(&pts, start_index, pts.index); + + map->oa = oa; +- return ret; ++ map->num_leaves = num_leaves; ++ if (ret || num_leaves) ++ return ret; ++ ++ /* range->va is not valid if we reached the end of the table */ ++ pts.index -= step; ++ pt_index_to_va(&pts); ++ pts.index += step; ++ last_va = range->va + log2_to_int(leaf_pgsize_lg2); ++ ++ if (last_va - 1 == range->last_va) { ++ PT_WARN_ON(pts.index != orig_end); ++ return 0; ++ } ++ ++ /* ++ * Reached a point where the page size changed, compute the new ++ * parameters. ++ */ ++ map->leaf_pgsize_lg2 = pt_compute_best_pgsize( ++ iommu_table->domain.pgsize_bitmap, last_va, range->last_va, oa); ++ map->leaf_level = ++ pt_pgsz_lg2_to_level(range->common, map->leaf_pgsize_lg2); ++ map->num_leaves = pt_pgsz_count(iommu_table->domain.pgsize_bitmap, ++ last_va, range->last_va, oa, ++ map->leaf_pgsize_lg2); ++ ++ /* Didn't finish this table level, caller will repeat it */ ++ if (pts.index != orig_end) { ++ if (pts.index != start_index) ++ pt_index_to_va(&pts); ++ return -EAGAIN; ++ } ++ return 0; + } + + static int __map_range(struct pt_range *range, void *arg, unsigned int level, +@@ -584,14 +631,9 @@ static int __map_range(struct pt_range *range, void *arg, unsigned int level, + if (pts.type != PT_ENTRY_EMPTY) + return -EADDRINUSE; + ret = pt_iommu_new_table(&pts, &map->attrs); +- if (ret) { +- /* +- * Racing with another thread installing a table +- */ +- if (ret == -EAGAIN) +- continue; ++ /* EAGAIN on a race will loop again */ ++ if (ret) + return ret; +- } + } else { + pts.table_lower = pt_table_ptr(&pts); + /* +@@ -615,10 +657,12 @@ static int __map_range(struct pt_range *range, void *arg, unsigned int level, + * The already present table can possibly be shared with another + * concurrent map. + */ +- if (map->leaf_level == level - 1) +- ret = pt_descend(&pts, arg, __map_range_leaf); +- else +- ret = pt_descend(&pts, arg, __map_range); ++ do { ++ if (map->leaf_level == level - 1) ++ ret = pt_descend(&pts, arg, __map_range_leaf); ++ else ++ ret = pt_descend(&pts, arg, __map_range); ++ } while (ret == -EAGAIN); + if (ret) + return ret; + +@@ -626,6 +670,14 @@ static int __map_range(struct pt_range *range, void *arg, unsigned int level, + pt_index_to_va(&pts); + if (pts.index >= pts.end_index) + break; ++ ++ /* ++ * This level is currently running __map_range_leaf() which is ++ * not correct if the target level has been updated to this ++ * level. Have the caller invoke __map_range_leaf. ++ */ ++ if (map->leaf_level == level) ++ return -EAGAIN; + } while (true); + return 0; + } +@@ -797,12 +849,13 @@ static int check_map_range(struct pt_iommu *iommu_table, struct pt_range *range, + static int do_map(struct pt_range *range, struct pt_common *common, + bool single_page, struct pt_iommu_map_args *map) + { ++ int ret; ++ + /* + * The __map_single_page() fast path does not support DMA_INCOHERENT + * flushing to keep its .text small. + */ + if (single_page && !pt_feature(common, PT_FEAT_DMA_INCOHERENT)) { +- int ret; + + ret = pt_walk_range(range, __map_single_page, map); + if (ret != -EAGAIN) +@@ -810,50 +863,25 @@ static int do_map(struct pt_range *range, struct pt_common *common, + /* EAGAIN falls through to the full path */ + } + +- if (map->leaf_level == range->top_level) +- return pt_walk_range(range, __map_range_leaf, map); +- return pt_walk_range(range, __map_range, map); ++ do { ++ if (map->leaf_level == range->top_level) ++ ret = pt_walk_range(range, __map_range_leaf, map); ++ else ++ ret = pt_walk_range(range, __map_range, map); ++ } while (ret == -EAGAIN); ++ return ret; + } + +-/** +- * map_pages() - Install translation for an IOVA range +- * @domain: Domain to manipulate +- * @iova: IO virtual address to start +- * @paddr: Physical/Output address to start +- * @pgsize: Length of each page +- * @pgcount: Length of the range in pgsize units starting from @iova +- * @prot: A bitmap of IOMMU_READ/WRITE/CACHE/NOEXEC/MMIO +- * @gfp: GFP flags for any memory allocations +- * @mapped: Total bytes successfully mapped +- * +- * The range starting at IOVA will have paddr installed into it. The caller +- * must specify a valid pgsize and pgcount to segment the range into compatible +- * blocks. +- * +- * On error the caller will probably want to invoke unmap on the range from iova +- * up to the amount indicated by @mapped to return the table back to an +- * unchanged state. +- * +- * Context: The caller must hold a write range lock that includes the whole +- * range. +- * +- * Returns: -ERRNO on failure, 0 on success. The number of bytes of VA that were +- * mapped are added to @mapped, @mapped is not zerod first. +- */ +-int DOMAIN_NS(map_pages)(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t pgsize, size_t pgcount, +- int prot, gfp_t gfp, size_t *mapped) ++static int NS(map_range)(struct pt_iommu *iommu_table, dma_addr_t iova, ++ phys_addr_t paddr, dma_addr_t len, unsigned int prot, ++ gfp_t gfp, size_t *mapped) + { +- struct pt_iommu *iommu_table = +- container_of(domain, struct pt_iommu, domain); + pt_vaddr_t pgsize_bitmap = iommu_table->domain.pgsize_bitmap; + struct pt_common *common = common_from_iommu(iommu_table); + struct iommu_iotlb_gather iotlb_gather; +- pt_vaddr_t len = pgsize * pgcount; + struct pt_iommu_map_args map = { + .iotlb_gather = &iotlb_gather, + .oa = paddr, +- .leaf_pgsize_lg2 = vaffs(pgsize), + }; + bool single_page = false; + struct pt_range range; +@@ -881,13 +909,13 @@ int DOMAIN_NS(map_pages)(struct iommu_domain *domain, unsigned long iova, + return ret; + + /* Calculate target page size and level for the leaves */ +- if (pt_has_system_page_size(common) && pgsize == PAGE_SIZE && +- pgcount == 1) { ++ if (pt_has_system_page_size(common) && len == PAGE_SIZE) { + PT_WARN_ON(!(pgsize_bitmap & PAGE_SIZE)); + if (log2_mod(iova | paddr, PAGE_SHIFT)) + return -ENXIO; + map.leaf_pgsize_lg2 = PAGE_SHIFT; + map.leaf_level = 0; ++ map.num_leaves = 1; + single_page = true; + } else { + map.leaf_pgsize_lg2 = pt_compute_best_pgsize( +@@ -896,6 +924,9 @@ int DOMAIN_NS(map_pages)(struct iommu_domain *domain, unsigned long iova, + return -ENXIO; + map.leaf_level = + pt_pgsz_lg2_to_level(common, map.leaf_pgsize_lg2); ++ map.num_leaves = pt_pgsz_count(pgsize_bitmap, range.va, ++ range.last_va, paddr, ++ map.leaf_pgsize_lg2); + } + + ret = check_map_range(iommu_table, &range, &map); +@@ -918,7 +949,6 @@ int DOMAIN_NS(map_pages)(struct iommu_domain *domain, unsigned long iova, + *mapped += map.oa - paddr; + return ret; + } +-EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(map_pages), "GENERIC_PT_IOMMU"); + + struct pt_unmap_args { + struct iommu_pages_list free_list; +@@ -1087,6 +1117,7 @@ static void NS(deinit)(struct pt_iommu *iommu_table) + } + + static const struct pt_iommu_ops NS(ops) = { ++ .map_range = NS(map_range), + .unmap_range = NS(unmap_range), + #if IS_ENABLED(CONFIG_IOMMUFD_DRIVER) && defined(pt_entry_is_write_dirty) && \ + IS_ENABLED(CONFIG_IOMMUFD_TEST) && defined(pt_entry_make_write_dirty) +diff --git a/drivers/iommu/generic_pt/kunit_generic_pt.h b/drivers/iommu/generic_pt/kunit_generic_pt.h +index 68278bf15cfe0..374e475f591e1 100644 +--- a/drivers/iommu/generic_pt/kunit_generic_pt.h ++++ b/drivers/iommu/generic_pt/kunit_generic_pt.h +@@ -312,6 +312,17 @@ static void test_best_pgsize(struct kunit *test) + } + } + ++static void test_pgsz_count(struct kunit *test) ++{ ++ KUNIT_EXPECT_EQ(test, ++ pt_pgsz_count(SZ_4K, 0, SZ_1G - 1, 0, ilog2(SZ_4K)), ++ SZ_1G / SZ_4K); ++ KUNIT_EXPECT_EQ(test, ++ pt_pgsz_count(SZ_2M | SZ_4K, SZ_4K, SZ_1G - 1, SZ_4K, ++ ilog2(SZ_4K)), ++ (SZ_2M - SZ_4K) / SZ_4K); ++} ++ + /* + * Check that pt_install_table() and pt_table_pa() match + */ +@@ -770,6 +781,7 @@ static struct kunit_case generic_pt_test_cases[] = { + KUNIT_CASE_FMT(test_init), + KUNIT_CASE_FMT(test_bitops), + KUNIT_CASE_FMT(test_best_pgsize), ++ KUNIT_CASE_FMT(test_pgsz_count), + KUNIT_CASE_FMT(test_table_ptr), + KUNIT_CASE_FMT(test_max_va), + KUNIT_CASE_FMT(test_table_radix), +diff --git a/drivers/iommu/generic_pt/pt_iter.h b/drivers/iommu/generic_pt/pt_iter.h +index c0d8617cce292..3e45dbde6b832 100644 +--- a/drivers/iommu/generic_pt/pt_iter.h ++++ b/drivers/iommu/generic_pt/pt_iter.h +@@ -569,6 +569,28 @@ static inline unsigned int pt_compute_best_pgsize(pt_vaddr_t pgsz_bitmap, + return pgsz_lg2; + } + ++/* ++ * Return the number of pgsize_lg2 leaf entries that can be mapped for ++ * va to oa. This accounts for any requirement to reduce or increase the page ++ * size across the VA range. ++ */ ++static inline pt_vaddr_t pt_pgsz_count(pt_vaddr_t pgsz_bitmap, pt_vaddr_t va, ++ pt_vaddr_t last_va, pt_oaddr_t oa, ++ unsigned int pgsize_lg2) ++{ ++ pt_vaddr_t len = last_va - va + 1; ++ pt_vaddr_t next_pgsizes = log2_set_mod(pgsz_bitmap, 0, pgsize_lg2 + 1); ++ ++ if (next_pgsizes) { ++ unsigned int next_pgsize_lg2 = vaffs(next_pgsizes); ++ ++ if (log2_mod(va ^ oa, next_pgsize_lg2) == 0) ++ len = min(len, log2_set_mod_max(va, next_pgsize_lg2) - ++ va + 1); ++ } ++ return log2_div(len, pgsize_lg2); ++} ++ + #define _PT_MAKE_CALL_LEVEL(fn) \ + static __always_inline int fn(struct pt_range *range, void *arg, \ + unsigned int level, \ +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 3f63feb2be167..845284a9eeaf4 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -2613,14 +2613,14 @@ static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova, + return pgsize; + } + +-int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot, gfp_t gfp) ++static int __iommu_map_domain_pgtbl(struct iommu_domain *domain, ++ unsigned long iova, phys_addr_t paddr, ++ size_t size, int prot, gfp_t gfp) + { + const struct iommu_domain_ops *ops = domain->ops; + unsigned long orig_iova = iova; + unsigned int min_pagesz; + size_t orig_size = size; +- phys_addr_t orig_paddr = paddr; + int ret = 0; + + might_sleep_if(gfpflags_allow_blocking(gfp)); +@@ -2677,12 +2677,9 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, + /* unroll mapping in case something went wrong */ + if (ret) { + iommu_unmap(domain, orig_iova, orig_size - size); +- } else { +- trace_map(orig_iova, orig_paddr, orig_size); +- iommu_debug_map(domain, orig_paddr, orig_size); ++ return ret; + } +- +- return ret; ++ return 0; + } + + int iommu_sync_map(struct iommu_domain *domain, unsigned long iova, size_t size) +@@ -2694,6 +2691,32 @@ int iommu_sync_map(struct iommu_domain *domain, unsigned long iova, size_t size) + return ops->iotlb_sync_map(domain, iova, size); + } + ++int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) ++{ ++ struct pt_iommu *pt = iommupt_from_domain(domain); ++ int ret; ++ ++ if (pt) { ++ size_t mapped = 0; ++ ++ ret = pt->ops->map_range(pt, iova, paddr, size, prot, gfp, ++ &mapped); ++ if (ret) { ++ iommu_unmap(domain, iova, mapped); ++ return ret; ++ } ++ return 0; ++ } ++ ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot, gfp); ++ if (!ret) ++ return ret; ++ ++ trace_map(iova, paddr, size); ++ iommu_debug_map(domain, paddr, size); ++ return 0; ++} ++ + int iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { +diff --git a/include/linux/generic_pt/iommu.h b/include/linux/generic_pt/iommu.h +index f094f8f44e4e8..43cc98c9c55f7 100644 +--- a/include/linux/generic_pt/iommu.h ++++ b/include/linux/generic_pt/iommu.h +@@ -87,6 +87,33 @@ struct pt_iommu_info { + }; + + struct pt_iommu_ops { ++ /** ++ * @map_range: Install translation for an IOVA range ++ * @iommu_table: Table to manipulate ++ * @iova: IO virtual address to start ++ * @paddr: Physical/Output address to start ++ * @len: Length of the range starting from @iova ++ * @prot: A bitmap of IOMMU_READ/WRITE/CACHE/NOEXEC/MMIO ++ * @gfp: GFP flags for any memory allocations ++ * ++ * The range starting at IOVA will have paddr installed into it. The ++ * rage is automatically segmented into optimally sized table entries, ++ * and can have any valid alignment. ++ * ++ * On error the caller will probably want to invoke unmap on the range ++ * from iova up to the amount indicated by @mapped to return the table ++ * back to an unchanged state. ++ * ++ * Context: The caller must hold a write range lock that includes ++ * the whole range. ++ * ++ * Returns: -ERRNO on failure, 0 on success. The number of bytes of VA ++ * that were mapped are added to @mapped, @mapped is not zerod first. ++ */ ++ int (*map_range)(struct pt_iommu *iommu_table, dma_addr_t iova, ++ phys_addr_t paddr, dma_addr_t len, unsigned int prot, ++ gfp_t gfp, size_t *mapped); ++ + /** + * @unmap_range: Make a range of IOVA empty/not present + * @iommu_table: Table to manipulate +@@ -224,10 +251,6 @@ struct pt_iommu_cfg { + #define IOMMU_PROTOTYPES(fmt) \ + phys_addr_t pt_iommu_##fmt##_iova_to_phys(struct iommu_domain *domain, \ + dma_addr_t iova); \ +- int pt_iommu_##fmt##_map_pages(struct iommu_domain *domain, \ +- unsigned long iova, phys_addr_t paddr, \ +- size_t pgsize, size_t pgcount, \ +- int prot, gfp_t gfp, size_t *mapped); \ + int pt_iommu_##fmt##_read_and_clear_dirty( \ + struct iommu_domain *domain, unsigned long iova, size_t size, \ + unsigned long flags, struct iommu_dirty_bitmap *dirty); \ +@@ -248,8 +271,7 @@ struct pt_iommu_cfg { + * iommu_pt + */ + #define IOMMU_PT_DOMAIN_OPS(fmt) \ +- .iova_to_phys = &pt_iommu_##fmt##_iova_to_phys, \ +- .map_pages = &pt_iommu_##fmt##_map_pages ++ .iova_to_phys = &pt_iommu_##fmt##_iova_to_phys + #define IOMMU_PT_DIRTY_OPS(fmt) \ + .read_and_clear_dirty = &pt_iommu_##fmt##_read_and_clear_dirty + +-- +2.53.0 + diff --git a/queue-7.0/iommupt-check-for-missing-page_size-in-the-pgsize_bi.patch b/queue-7.0/iommupt-check-for-missing-page_size-in-the-pgsize_bi.patch new file mode 100644 index 0000000000..f1f559ca17 --- /dev/null +++ b/queue-7.0/iommupt-check-for-missing-page_size-in-the-pgsize_bi.patch @@ -0,0 +1,45 @@ +From bbc74568885d4726a2c6363c83ad62076c27112d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:46:16 -0300 +Subject: iommupt: Check for missing PAGE_SIZE in the pgsize_bitmap + +From: Jason Gunthorpe + +[ Upstream commit 8ef3f77c440005c7f04229a75976bfc078364247 ] + +Sashiko pointed out that the driver could drop PAGE_SIZE from the +pgsize_bitmap. That is technically allowed but nothing does it, and +such an iommu_domain would not be used with the DMA API today. + +Still, it is against the design and it is trivial to fix up. Lift +the PT_WARN_ON to the if branch and just skip the fast path. + +Fixes: dcd6a011a8d5 ("iommupt: Add map_pages op") +Signed-off-by: Jason Gunthorpe +Reviewed-by: Pranjal Shrivastava +Reviewed-by: Samiullah Khawaja +Tested-by: Josua Mayer +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/generic_pt/iommu_pt.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h +index c0241b24a6098..4be33c45bedc9 100644 +--- a/drivers/iommu/generic_pt/iommu_pt.h ++++ b/drivers/iommu/generic_pt/iommu_pt.h +@@ -909,8 +909,8 @@ static int NS(map_range)(struct pt_iommu *iommu_table, dma_addr_t iova, + return ret; + + /* Calculate target page size and level for the leaves */ +- if (pt_has_system_page_size(common) && len == PAGE_SIZE) { +- PT_WARN_ON(!(pgsize_bitmap & PAGE_SIZE)); ++ if (pt_has_system_page_size(common) && len == PAGE_SIZE && ++ likely(pgsize_bitmap & PAGE_SIZE)) { + if (log2_mod(iova | paddr, PAGE_SHIFT)) + return -ENXIO; + map.leaf_pgsize_lg2 = PAGE_SHIFT; +-- +2.53.0 + diff --git a/queue-7.0/iommupt-directly-call-iommupt-s-unmap_range.patch b/queue-7.0/iommupt-directly-call-iommupt-s-unmap_range.patch new file mode 100644 index 0000000000..2e88e713be --- /dev/null +++ b/queue-7.0/iommupt-directly-call-iommupt-s-unmap_range.patch @@ -0,0 +1,239 @@ +From df95f152e3bd2fc6765dc48f236f73c77e84d9e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:30:10 -0400 +Subject: iommupt: Directly call iommupt's unmap_range() + +From: Jason Gunthorpe + +[ Upstream commit 99fb8afa16add85ed016baee9735231bca0c32b4 ] + +The common algorithm in iommupt does not require the iommu_pgsize() +calculations, it can directly unmap any arbitrary range. Add a new function +pointer to directly call an iommupt unmap_range op and make +__iommu_unmap() call it directly. + +Gives about a 5% gain on single page unmappings. + +The function pointer is run through pt_iommu_ops instead of +iommu_domain_ops to discourage using it outside iommupt. All drivers with +their own page tables should continue to use the simplified +map/unmap_pages() style interfaces. + +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Signed-off-by: Jason Gunthorpe +Reviewed-by: Lu Baolu +Signed-off-by: Joerg Roedel +Stable-dep-of: 0735c54804c7 ("iommu: Handle unmap error when iommu_debug is enabled") +Signed-off-by: Sasha Levin +--- + drivers/iommu/generic_pt/iommu_pt.h | 29 ++++------------------ + drivers/iommu/iommu.c | 27 ++++++++++++++++----- + include/linux/generic_pt/iommu.h | 37 ++++++++++++++++++++++++----- + include/linux/iommu.h | 1 + + 4 files changed, 57 insertions(+), 37 deletions(-) + +diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h +index 7e7a6e7abdeed..8bc4683a64dc1 100644 +--- a/drivers/iommu/generic_pt/iommu_pt.h ++++ b/drivers/iommu/generic_pt/iommu_pt.h +@@ -1020,34 +1020,12 @@ static __maybe_unused int __unmap_range(struct pt_range *range, void *arg, + return ret; + } + +-/** +- * unmap_pages() - Make a range of IOVA empty/not present +- * @domain: Domain to manipulate +- * @iova: IO virtual address to start +- * @pgsize: Length of each page +- * @pgcount: Length of the range in pgsize units starting from @iova +- * @iotlb_gather: Gather struct that must be flushed on return +- * +- * unmap_pages() will remove a translation created by map_pages(). It cannot +- * subdivide a mapping created by map_pages(), so it should be called with IOVA +- * ranges that match those passed to map_pages(). The IOVA range can aggregate +- * contiguous map_pages() calls so long as no individual range is split. +- * +- * Context: The caller must hold a write range lock that includes +- * the whole range. +- * +- * Returns: Number of bytes of VA unmapped. iova + res will be the point +- * unmapping stopped. +- */ +-size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova, +- size_t pgsize, size_t pgcount, ++static size_t NS(unmap_range)(struct pt_iommu *iommu_table, dma_addr_t iova, ++ dma_addr_t len, + struct iommu_iotlb_gather *iotlb_gather) + { +- struct pt_iommu *iommu_table = +- container_of(domain, struct pt_iommu, domain); + struct pt_unmap_args unmap = { .free_list = IOMMU_PAGES_LIST_INIT( + unmap.free_list) }; +- pt_vaddr_t len = pgsize * pgcount; + struct pt_range range; + int ret; + +@@ -1062,7 +1040,6 @@ size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova, + + return unmap.unmapped; + } +-EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(unmap_pages), "GENERIC_PT_IOMMU"); + + static void NS(get_info)(struct pt_iommu *iommu_table, + struct pt_iommu_info *info) +@@ -1110,6 +1087,7 @@ static void NS(deinit)(struct pt_iommu *iommu_table) + } + + static const struct pt_iommu_ops NS(ops) = { ++ .unmap_range = NS(unmap_range), + #if IS_ENABLED(CONFIG_IOMMUFD_DRIVER) && defined(pt_entry_is_write_dirty) && \ + IS_ENABLED(CONFIG_IOMMUFD_TEST) && defined(pt_entry_make_write_dirty) + .set_dirty = NS(set_dirty), +@@ -1172,6 +1150,7 @@ static int pt_iommu_init_domain(struct pt_iommu *iommu_table, + + domain->type = __IOMMU_DOMAIN_PAGING; + domain->pgsize_bitmap = info.pgsize_bitmap; ++ domain->is_iommupt = true; + + if (pt_feature(common, PT_FEAT_DYNAMIC_TOP)) + range = _pt_top_range(common, +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index d48e28ae1ebfc..3f63feb2be167 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "dma-iommu.h" + #include "iommu-priv.h" +@@ -2710,13 +2711,12 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, + } + EXPORT_SYMBOL_GPL(iommu_map); + +-static size_t __iommu_unmap(struct iommu_domain *domain, +- unsigned long iova, size_t size, +- struct iommu_iotlb_gather *iotlb_gather) ++static size_t ++__iommu_unmap_domain_pgtbl(struct iommu_domain *domain, unsigned long iova, ++ size_t size, struct iommu_iotlb_gather *iotlb_gather) + { + const struct iommu_domain_ops *ops = domain->ops; + size_t unmapped_page, unmapped = 0; +- unsigned long orig_iova = iova; + unsigned int min_pagesz; + + if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) +@@ -2768,8 +2768,23 @@ static size_t __iommu_unmap(struct iommu_domain *domain, + unmapped += unmapped_page; + } + +- trace_unmap(orig_iova, size, unmapped); +- iommu_debug_unmap_end(domain, orig_iova, size, unmapped); ++ return unmapped; ++} ++ ++static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long iova, ++ size_t size, ++ struct iommu_iotlb_gather *iotlb_gather) ++{ ++ struct pt_iommu *pt = iommupt_from_domain(domain); ++ size_t unmapped; ++ ++ if (pt) ++ unmapped = pt->ops->unmap_range(pt, iova, size, iotlb_gather); ++ else ++ unmapped = __iommu_unmap_domain_pgtbl(domain, iova, size, ++ iotlb_gather); ++ trace_unmap(iova, size, unmapped); ++ iommu_debug_unmap_end(domain, iova, size, unmapped); + return unmapped; + } + +diff --git a/include/linux/generic_pt/iommu.h b/include/linux/generic_pt/iommu.h +index 9eefbb74efd08..f094f8f44e4e8 100644 +--- a/include/linux/generic_pt/iommu.h ++++ b/include/linux/generic_pt/iommu.h +@@ -66,6 +66,13 @@ struct pt_iommu { + struct device *iommu_device; + }; + ++static inline struct pt_iommu *iommupt_from_domain(struct iommu_domain *domain) ++{ ++ if (!IS_ENABLED(CONFIG_IOMMU_PT) || !domain->is_iommupt) ++ return NULL; ++ return container_of(domain, struct pt_iommu, domain); ++} ++ + /** + * struct pt_iommu_info - Details about the IOMMU page table + * +@@ -80,6 +87,29 @@ struct pt_iommu_info { + }; + + struct pt_iommu_ops { ++ /** ++ * @unmap_range: Make a range of IOVA empty/not present ++ * @iommu_table: Table to manipulate ++ * @iova: IO virtual address to start ++ * @len: Length of the range starting from @iova ++ * @iotlb_gather: Gather struct that must be flushed on return ++ * ++ * unmap_range() will remove a translation created by map_range(). It ++ * cannot subdivide a mapping created by map_range(), so it should be ++ * called with IOVA ranges that match those passed to map_pages. The ++ * IOVA range can aggregate contiguous map_range() calls so long as no ++ * individual range is split. ++ * ++ * Context: The caller must hold a write range lock that includes ++ * the whole range. ++ * ++ * Returns: Number of bytes of VA unmapped. iova + res will be the ++ * point unmapping stopped. ++ */ ++ size_t (*unmap_range)(struct pt_iommu *iommu_table, dma_addr_t iova, ++ dma_addr_t len, ++ struct iommu_iotlb_gather *iotlb_gather); ++ + /** + * @set_dirty: Make the iova write dirty + * @iommu_table: Table to manipulate +@@ -198,10 +228,6 @@ struct pt_iommu_cfg { + unsigned long iova, phys_addr_t paddr, \ + size_t pgsize, size_t pgcount, \ + int prot, gfp_t gfp, size_t *mapped); \ +- size_t pt_iommu_##fmt##_unmap_pages( \ +- struct iommu_domain *domain, unsigned long iova, \ +- size_t pgsize, size_t pgcount, \ +- struct iommu_iotlb_gather *iotlb_gather); \ + int pt_iommu_##fmt##_read_and_clear_dirty( \ + struct iommu_domain *domain, unsigned long iova, size_t size, \ + unsigned long flags, struct iommu_dirty_bitmap *dirty); \ +@@ -223,8 +249,7 @@ struct pt_iommu_cfg { + */ + #define IOMMU_PT_DOMAIN_OPS(fmt) \ + .iova_to_phys = &pt_iommu_##fmt##_iova_to_phys, \ +- .map_pages = &pt_iommu_##fmt##_map_pages, \ +- .unmap_pages = &pt_iommu_##fmt##_unmap_pages ++ .map_pages = &pt_iommu_##fmt##_map_pages + #define IOMMU_PT_DIRTY_OPS(fmt) \ + .read_and_clear_dirty = &pt_iommu_##fmt##_read_and_clear_dirty + +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 555597b54083c..563d0f104114b 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -223,6 +223,7 @@ enum iommu_domain_cookie_type { + struct iommu_domain { + unsigned type; + enum iommu_domain_cookie_type cookie_type; ++ bool is_iommupt; + const struct iommu_domain_ops *ops; + const struct iommu_dirty_ops *dirty_ops; + const struct iommu_ops *owner; /* Whose domain_alloc we came from */ +-- +2.53.0 + diff --git a/queue-7.0/iommupt-fix-the-end_index-calculation-in-__map_range.patch b/queue-7.0/iommupt-fix-the-end_index-calculation-in-__map_range.patch new file mode 100644 index 0000000000..9983644e34 --- /dev/null +++ b/queue-7.0/iommupt-fix-the-end_index-calculation-in-__map_range.patch @@ -0,0 +1,88 @@ +From 6157d467a50b2ebff2782a64b19f35196ceb7e54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:46:17 -0300 +Subject: iommupt: Fix the end_index calculation in __map_range_leaf() + +From: Jason Gunthorpe + +[ Upstream commit 58829512ad461af8f35941069c209941e3a97b65 ] + +Sashiko noticed a mismatch of units in this math: num_leaves is +actually the number of leaf *entries* (so a 16-item contiguous leaf +is one num_leaves), while index is in items. The mismatch in maths +causes __map_range_leaf() to exit early instead of efficiently +filling a larger range of contiguous PTEs. + +The early exit is caught by the functions above and then +__map_range_leaf() is re-invoked, so there is no functional issue. + +Correct the misuse of units by adjusting num_leaves with the leaf +size and avoid the performance cost of looping externally. + +There are also some mismatched types for num_leaves; simplify +things to remove the duplicated calculations. + +Fixes: d6c65b0fd621 ("iommupt: Avoid rewalking during map") +Signed-off-by: Jason Gunthorpe +Reviewed-by: Samiullah Khawaja +Reviewd-by: Pranjal Shrivastava +Tested-by: Josua Mayer +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/generic_pt/iommu_pt.h | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h +index 4be33c45bedc9..55faad4b9dc75 100644 +--- a/drivers/iommu/generic_pt/iommu_pt.h ++++ b/drivers/iommu/generic_pt/iommu_pt.h +@@ -523,10 +523,12 @@ static int __map_range_leaf(struct pt_range *range, void *arg, + struct pt_state pts = pt_init(range, level, table); + struct pt_iommu_map_args *map = arg; + unsigned int leaf_pgsize_lg2 = map->leaf_pgsize_lg2; ++ unsigned int leaves_avail; + unsigned int start_index; + pt_oaddr_t oa = map->oa; +- unsigned int num_leaves; ++ pt_vaddr_t num_leaves; + unsigned int orig_end; ++ unsigned int step_lg2; + pt_vaddr_t last_va; + unsigned int step; + bool need_contig; +@@ -535,21 +537,25 @@ static int __map_range_leaf(struct pt_range *range, void *arg, + PT_WARN_ON(map->leaf_level != level); + PT_WARN_ON(!pt_can_have_leaf(&pts)); + +- step = log2_to_int_t(unsigned int, +- leaf_pgsize_lg2 - pt_table_item_lg2sz(&pts)); +- need_contig = leaf_pgsize_lg2 != pt_table_item_lg2sz(&pts); ++ step_lg2 = leaf_pgsize_lg2 - pt_table_item_lg2sz(&pts); ++ step = log2_to_int_t(unsigned int, step_lg2); ++ need_contig = step_lg2 != 0; + + _pt_iter_first(&pts); + start_index = pts.index; + orig_end = pts.end_index; +- if (pts.index + map->num_leaves < pts.end_index) { ++ leaves_avail = ++ log2_div_t(unsigned int, pts.end_index - pts.index, step_lg2); ++ if (map->num_leaves <= leaves_avail) { + /* Need to stop in the middle of the table to change sizes */ +- pts.end_index = pts.index + map->num_leaves; ++ pts.end_index = pts.index + log2_mul(map->num_leaves, step_lg2); + num_leaves = 0; + } else { +- num_leaves = map->num_leaves - (pts.end_index - pts.index); ++ num_leaves = map->num_leaves - leaves_avail; + } + ++ PT_WARN_ON( ++ log2_mod_t(unsigned int, pts.end_index - pts.index, step_lg2)); + do { + pts.type = pt_load_entry_raw(&pts); + if (pts.type != PT_ENTRY_EMPTY || need_contig) { +-- +2.53.0 + diff --git a/queue-7.0/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch b/queue-7.0/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch new file mode 100644 index 0000000000..be05f97703 --- /dev/null +++ b/queue-7.0/ipmi-ssif_bmc-cancel-response-timer-on-remove.patch @@ -0,0 +1,39 @@ +From f1c04d93555f816480fe4f55aca1b511a6074c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:58 +0800 +Subject: ipmi: ssif_bmc: cancel response timer on remove + +From: Jian Zhang + +[ Upstream commit 7fc3e2546cf3fa9a28a2acc92a512c779a8e5038 ] + +The response timer can stay armed across device teardown. If it fires after +remove, the callback dereferences the SSIF context and the i2c client after +teardown has started. + +Cancel the timer in remove so the callback cannot run after the device is +unregistered. + +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-1-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index a45e80d13e10e..646a1e9ffbb70 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -859,6 +859,7 @@ static void ssif_bmc_remove(struct i2c_client *client) + { + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + ++ timer_delete_sync(&ssif_bmc->response_timer); + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + } +-- +2.53.0 + diff --git a/queue-7.0/ipv4-validate-ipv4_devconf-attributes-properly.patch b/queue-7.0/ipv4-validate-ipv4_devconf-attributes-properly.patch new file mode 100644 index 0000000000..9fbc8db9b0 --- /dev/null +++ b/queue-7.0/ipv4-validate-ipv4_devconf-attributes-properly.patch @@ -0,0 +1,106 @@ +From 80776a0a608042f284e01d0f0426fa7356fc8cad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:26:37 +0100 +Subject: ipv4: validate IPV4_DEVCONF attributes properly + +From: Fernando Fernandez Mancera + +[ Upstream commit fa8fca88714c3a4a74f972ed37328e2f0bbef9fa ] + +As the IPV4_DEVCONF netlink attributes are not being validated, it is +possible to use netlink to set read-only values like mc_forwarding. In +addition, valid ranges are not being validated neither but that is less +relevant as they aren't in sysctl. + +To avoid similar situations in the future, define a NLA policy for +IPV4_DEVCONF attributes which are nested in IFLA_INET_CONF. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260312142637.5704-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 55 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 537bb6c315d2e..58fe7cb69545c 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -2063,12 +2063,50 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { + [IFLA_INET_CONF] = { .type = NLA_NESTED }, + }; + ++static const struct nla_policy inet_devconf_policy[IPV4_DEVCONF_MAX + 1] = { ++ [IPV4_DEVCONF_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MC_FORWARDING] = { .type = NLA_REJECT }, ++ [IPV4_DEVCONF_PROXY_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SECURE_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SEND_REDIRECTS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SHARED_MEDIA] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_RP_FILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BOOTP_RELAY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_LOG_MARTIANS] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_TAG] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_ARPFILTER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_MEDIUM_ID] = NLA_POLICY_MIN(NLA_S32, -1), ++ [IPV4_DEVCONF_NOXFRM] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_NOPOLICY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_FORCE_IGMP_VERSION] = NLA_POLICY_RANGE(NLA_U32, 0, 3), ++ [IPV4_DEVCONF_ARP_ANNOUNCE] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_IGNORE] = NLA_POLICY_RANGE(NLA_U32, 0, 8), ++ [IPV4_DEVCONF_PROMOTE_SECONDARIES] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_ACCEPT] = NLA_POLICY_RANGE(NLA_U32, 0, 2), ++ [IPV4_DEVCONF_ARP_NOTIFY] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ACCEPT_LOCAL] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_SRC_VMARK] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_PROXY_ARP_PVLAN] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ROUTE_LOCALNET] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_BC_FORWARDING] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL] = { .type = NLA_U32 }, ++ [IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = ++ NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_DROP_GRATUITOUS_ARP] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++ [IPV4_DEVCONF_ARP_EVICT_NOCARRIER] = NLA_POLICY_RANGE(NLA_U32, 0, 1), ++}; ++ + static int inet_validate_link_af(const struct net_device *dev, + const struct nlattr *nla, + struct netlink_ext_ack *extack) + { +- struct nlattr *a, *tb[IFLA_INET_MAX+1]; +- int err, rem; ++ struct nlattr *tb[IFLA_INET_MAX + 1], *nested_tb[IPV4_DEVCONF_MAX + 1]; ++ int err; + + if (dev && !__in_dev_get_rtnl(dev)) + return -EAFNOSUPPORT; +@@ -2079,15 +2117,12 @@ static int inet_validate_link_af(const struct net_device *dev, + return err; + + if (tb[IFLA_INET_CONF]) { +- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { +- int cfgid = nla_type(a); ++ err = nla_parse_nested(nested_tb, IPV4_DEVCONF_MAX, ++ tb[IFLA_INET_CONF], inet_devconf_policy, ++ extack); + +- if (nla_len(a) < 4) +- return -EINVAL; +- +- if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) +- return -EINVAL; +- } ++ if (err < 0) ++ return err; + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch b/queue-7.0/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch new file mode 100644 index 0000000000..8d609c7bc8 --- /dev/null +++ b/queue-7.0/ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch @@ -0,0 +1,73 @@ +From 5619da2db97a76bf41de90114ad464045b19da69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 22:24:06 +0200 +Subject: ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim + +From: Daniel Borkmann + +[ Upstream commit 076b8cad77aa96557719fb5effe8703bfb64df00 ] + +Commit 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and +Destination options") added net.ipv6.max_{hbh,dst}_opts_{cnt,len} +and applied them in ip6_parse_tlv(), the generic TLV walker +invoked from ipv6_destopt_rcv() and ipv6_parse_hopopts(). + +ip6_tnl_parse_tlv_enc_lim() does not go through ip6_parse_tlv(); +it has its own hand-rolled TLV scanner inside its NEXTHDR_DEST +branch which looks for IPV6_TLV_TNL_ENCAP_LIMIT. That inner +loop is bounded only by optlen, which can be up to 2048 bytes. +Stuffing the Destination Options header with 2046 Pad1 (type=0) +entries advances the scanner a single byte at a time, yielding +~2000 TLV iterations per extension header. + +Reusing max_dst_opts_cnt to bound the TLV iterations, matching +the semantics from 47d3d7ac656a, would require duplicating +ip6_parse_tlv() to also validate Pad1/PadN payload. It would +also mandate enforcing max_dst_opts_len, since otherwise an +attacker shifts the axis to few options with a giant PadN and +recovers the original DoS. Allowing up to 8 options before the +tunnel encapsulation limit TLV is liberal enough; in practice +encap limit is the first TLV. Thus, go with a hard-coded limit +IP6_TUNNEL_MAX_DEST_TLVS (8). + +Signed-off-by: Daniel Borkmann +Reviewed-by: Ido Schimmel +Reviewed-by: Justin Iurman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_tunnel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 0b53488a92290..b9d41b5d1853b 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -62,6 +62,8 @@ MODULE_LICENSE("GPL"); + MODULE_ALIAS_RTNL_LINK("ip6tnl"); + MODULE_ALIAS_NETDEV("ip6tnl0"); + ++#define IP6_TUNNEL_MAX_DEST_TLVS 8 ++ + #define IP6_TUNNEL_HASH_SIZE_SHIFT 5 + #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +@@ -428,11 +430,15 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) + break; + } + if (nexthdr == NEXTHDR_DEST) { ++ int tlv_cnt = 0; + u16 i = 2; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + ++ if (unlikely(tlv_cnt++ >= IP6_TUNNEL_MAX_DEST_TLVS)) ++ break; ++ + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; +-- +2.53.0 + diff --git a/queue-7.0/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch b/queue-7.0/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch new file mode 100644 index 0000000000..bfaf5ba73d --- /dev/null +++ b/queue-7.0/ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch @@ -0,0 +1,59 @@ +From ccc230dd5839756a23f104ddabba84b6ffc06c77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 14:37:58 +0100 +Subject: ipv6: discard fragment queue earlier if there is malformed datagram + +From: Fernando Fernandez Mancera + +[ Upstream commit 9ff2d2a9837015ff4b3579b028aeae8c180aa8d3 ] + +Currently the kernel IPv6 implementation is not dicarding the fragment +queue upon receiving a IPv6 fragment that is not 8 bytes aligned. It +relies on queue expiration to free the queue. + +While RFC 8200 section 4.5 does not explicitly mention that the rest of +fragments must be discarded, it does not make sense to keep them. The +parameter problem message is sent regardless that. In addition, if the +sender is able to re-compose the datagram so it is 8 bytes aligned it +would qualify as a new whole datagram not fitting into the same fragment +queue. + +The same situation happens if segment end is exceeding the IPv6 maximum +packet length. The sooner we can free resources the better during +reassembly, the better. + +Signed-off-by: Fernando Fernandez Mancera +Link: https://patch.msgid.link/20260225133758.4553-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/reassembly.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 25ec8001898df..11f9144bebbe2 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -132,6 +132,9 @@ static int ip6_frag_queue(struct net *net, + /* note that if prob_offset is set, the skb is freed elsewhere, + * we do not free it here. + */ ++ inet_frag_kill(&fq->q, refs); ++ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), ++ IPSTATS_MIB_REASMFAILS); + return -1; + } + +@@ -163,6 +166,9 @@ static int ip6_frag_queue(struct net *net, + * this case. -DaveM + */ + *prob_offset = offsetof(struct ipv6hdr, payload_len); ++ inet_frag_kill(&fq->q, refs); ++ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), ++ IPSTATS_MIB_REASMFAILS); + return -1; + } + if (end > fq->q.len) { +-- +2.53.0 + diff --git a/queue-7.0/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch b/queue-7.0/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch new file mode 100644 index 0000000000..d55e7bf275 --- /dev/null +++ b/queue-7.0/ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch @@ -0,0 +1,150 @@ +From 5042645ea991a7df92a1864201b764374e951ad4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:36:49 +0200 +Subject: ipv6: move IFA_F_PERMANENT percpu allocation in process scope + +From: Paolo Abeni + +[ Upstream commit 8e6405f8218b3f412d36b772318e94d589513eba ] + +Observed at boot time: + + CPU: 43 UID: 0 PID: 3595 Comm: (t-daemon) Not tainted 6.12.0 #1 + Call Trace: + + dump_stack_lvl+0x4e/0x70 + pcpu_alloc_noprof.cold+0x1f/0x4b + fib_nh_common_init+0x4c/0x110 + fib6_nh_init+0x387/0x740 + ip6_route_info_create+0x46d/0x640 + addrconf_f6i_alloc+0x13b/0x180 + addrconf_permanent_addr+0xd0/0x220 + addrconf_notify+0x93/0x540 + notifier_call_chain+0x5a/0xd0 + __dev_notify_flags+0x5c/0xf0 + dev_change_flags+0x54/0x70 + do_setlink+0x36c/0xce0 + rtnl_setlink+0x11f/0x1d0 + rtnetlink_rcv_msg+0x142/0x3f0 + netlink_rcv_skb+0x50/0x100 + netlink_unicast+0x242/0x390 + netlink_sendmsg+0x21b/0x470 + __sys_sendto+0x1dc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x7d/0x160 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + RIP: 0033:0x7f5c3852f127 + Code: 0c 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 80 3d 85 ef 0c 00 00 41 89 ca 74 10 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 71 c3 55 48 83 ec 30 44 89 4c 24 2c 4c 89 44 + RSP: 002b:00007ffe86caf4c8 EFLAGS: 00000202 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 0000556c5cd93210 RCX: 00007f5c3852f127 + RDX: 0000000000000020 RSI: 0000556c5cd938b0 RDI: 0000000000000003 + RBP: 00007ffe86caf5a0 R08: 00007ffe86caf4e0 R09: 0000000000000080 + R10: 0000000000000000 R11: 0000000000000202 R12: 0000556c5cd932d0 + R13: 00000000021d05d1 R14: 00000000021d05d1 R15: 0000000000000001 + +IFA_F_PERMANENT addresses require the allocation of a bunch of percpu +pointers, currently in atomic scope. + +Similar to commit 51454ea42c1a ("ipv6: fix locking issues with loops +over idev->addr_list"), move fixup_permanent_addr() outside the +&idev->lock scope, and do the allocations with GFP_KERNEL. With such +change fixup_permanent_addr() is invoked with the BH enabled, and the +ifp lock acquired there needs the BH variant. + +Note that we don't need to acquire a reference to the permanent +addresses before releasing the mentioned write lock, because +addrconf_permanent_addr() runs under RTNL and ifa removal always happens +under RTNL, too. + +Also the PERMANENT flag is constant in the relevant scope, as it can be +cleared only by inet6_addr_modify() under the RTNL lock. + +Reviewed-by: David Ahern +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/46a7a030727e236af2dc7752994cd4f04f4a91d2.1775658924.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index dd0b4d80e0f84..77c77e843c96c 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3585,15 +3585,15 @@ static int fixup_permanent_addr(struct net *net, + struct fib6_info *f6i, *prev; + + f6i = addrconf_f6i_alloc(net, idev, &ifp->addr, false, +- GFP_ATOMIC, NULL); ++ GFP_KERNEL, NULL); + if (IS_ERR(f6i)) + return PTR_ERR(f6i); + + /* ifp->rt can be accessed outside of rtnl */ +- spin_lock(&ifp->lock); ++ spin_lock_bh(&ifp->lock); + prev = ifp->rt; + ifp->rt = f6i; +- spin_unlock(&ifp->lock); ++ spin_unlock_bh(&ifp->lock); + + fib6_info_release(prev); + } +@@ -3601,7 +3601,7 @@ static int fixup_permanent_addr(struct net *net, + if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, + ifp->rt_priority, idev->dev, 0, 0, +- GFP_ATOMIC); ++ GFP_KERNEL); + } + + if (ifp->state == INET6_IFADDR_STATE_PREDAD) +@@ -3612,29 +3612,36 @@ static int fixup_permanent_addr(struct net *net, + + static void addrconf_permanent_addr(struct net *net, struct net_device *dev) + { +- struct inet6_ifaddr *ifp, *tmp; ++ struct inet6_ifaddr *ifp; ++ LIST_HEAD(tmp_addr_list); + struct inet6_dev *idev; + ++ /* Mutual exclusion with other if_list_aux users. */ ++ ASSERT_RTNL(); ++ + idev = __in6_dev_get(dev); + if (!idev) + return; + + write_lock_bh(&idev->lock); ++ list_for_each_entry(ifp, &idev->addr_list, if_list) { ++ if (ifp->flags & IFA_F_PERMANENT) ++ list_add_tail(&ifp->if_list_aux, &tmp_addr_list); ++ } ++ write_unlock_bh(&idev->lock); + +- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { +- if ((ifp->flags & IFA_F_PERMANENT) && +- fixup_permanent_addr(net, idev, ifp) < 0) { +- write_unlock_bh(&idev->lock); ++ while (!list_empty(&tmp_addr_list)) { ++ ifp = list_first_entry(&tmp_addr_list, ++ struct inet6_ifaddr, if_list_aux); ++ list_del(&ifp->if_list_aux); + ++ if (fixup_permanent_addr(net, idev, ifp) < 0) { + net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n", + idev->dev->name, &ifp->addr); + in6_ifa_hold(ifp); + ipv6_del_addr(ifp); +- write_lock_bh(&idev->lock); + } + } +- +- write_unlock_bh(&idev->lock); + } + + static int addrconf_notify(struct notifier_block *this, unsigned long event, +-- +2.53.0 + diff --git a/queue-7.0/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch b/queue-7.0/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch new file mode 100644 index 0000000000..5c2c14cb29 --- /dev/null +++ b/queue-7.0/irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch @@ -0,0 +1,68 @@ +From 6c6b1207dd9ff9a6d56b80115a5f1e9751d7071e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:32:29 +0800 +Subject: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 91840be8f710370607f949a627e070896faeddb8 ] + +On PREEMPT_RT, non-HARD irq_work runs in per-CPU kthreads via +run_irq_workd(), so irq_work_sync() uses rcuwait() to wait for BUSY==0. + +After irq_work_single() clears BUSY via atomic_cmpxchg(), it still +dereferences @work for irq_work_is_hard() and rcuwait_wake_up(). + +An irq_work_sync() caller on another CPU that enters after BUSY is cleared +can observe BUSY==0 immediately, return, and free the work before those +accesses complete — causing a use-after-free. + +Fix this by wrapping run_irq_workd() in guard(rcu)() so that the entire +irq_work_single() execution is within an RCU read-side critical +section. Then add synchronize_rcu() in irq_work_sync() after +rcuwait_wait_event() to ensure the caller waits for the RCU grace period +before returning, preventing premature frees. + +Fixes: 810979682ccc ("irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.") +Suggested-by: Sebastian Andrzej Siewior +Suggested-by: Steven Rostedt +Signed-off-by: Jiayuan Chen +Signed-off-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260330073234.303732-1-jiayuan.chen@linux.dev +Signed-off-by: Sasha Levin +--- + kernel/irq_work.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 73f7e1fd4ab4d..bf411656c3160 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -292,6 +292,12 @@ void irq_work_sync(struct irq_work *work) + !arch_irq_work_has_interrupt()) { + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work), + TASK_UNINTERRUPTIBLE); ++ /* ++ * Ensure irq_work_single() does not access @work ++ * after removing IRQ_WORK_BUSY. It is always ++ * accessed within a RCU-read section. ++ */ ++ synchronize_rcu(); + return; + } + +@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); + + static void run_irq_workd(unsigned int cpu) + { ++ guard(rcu)(); + irq_work_run_list(this_cpu_ptr(&lazy_list)); + } + +-- +2.53.0 + diff --git a/queue-7.0/irqchip-ath79-cpu-remove-unused-function.patch b/queue-7.0/irqchip-ath79-cpu-remove-unused-function.patch new file mode 100644 index 0000000000..cff4cf1bea --- /dev/null +++ b/queue-7.0/irqchip-ath79-cpu-remove-unused-function.patch @@ -0,0 +1,46 @@ +From 37dd5a582f8427446a508a740667e5368d82c78c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 01:55:22 -0700 +Subject: irqchip/ath79-cpu: Remove unused function + +From: Rosen Penev + +[ Upstream commit 0fa10fb77069fb67aa51384868ef3702b7791465 ] + +ath79_cpu_irq_init() was part of the legacy pre-OF code that got removed a +while back. + +Remove it to get rid of a missing prototype warning, reported by the kernel test +robot. + +[ tglx: Fix the subject prefix. Sigh ... ] + +Fixes: 51fa4f8912c0 ("MIPS: ath79: drop legacy IRQ code") +Reported-by: kernel test robot +Signed-off-by: Rosen Penev +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260506085522.1210143-1-rosenp@gmail.com +Closes: https://lore.kernel.org/oe-kbuild-all/202412011509.kGQkDr1y-lkp@intel.com/ +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-ath79-cpu.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c +index 923e4bba37767..9b7273a7f8ced 100644 +--- a/drivers/irqchip/irq-ath79-cpu.c ++++ b/drivers/irqchip/irq-ath79-cpu.c +@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( + } + IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc", + ar79_cpu_intc_of_init); +- +-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3) +-{ +- irq_wb_chan[2] = irq_wb_chan2; +- irq_wb_chan[3] = irq_wb_chan3; +- mips_cpu_irq_init(); +-} +-- +2.53.0 + diff --git a/queue-7.0/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch b/queue-7.0/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch new file mode 100644 index 0000000000..dc67a762e0 --- /dev/null +++ b/queue-7.0/jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch @@ -0,0 +1,268 @@ +From 535c123314bc50e86152f5e95a6d993403cd20c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Nov 2025 23:51:50 +0800 +Subject: jfs: add dmapctl integrity check to prevent invalid operations + +From: Yun Zhou + +[ Upstream commit cce219b203c4b9cb445e910c7090d1f58af847c5 ] + +Add check_dmapctl() to validate dmapctl structure integrity, focusing on +preventing invalid operations caused by on-disk corruption. + +Key checks: + - nleafs bounded by [0, LPERCTL] (maximum leaf nodes per dmapctl). + - l2nleafs bounded by [0, L2LPERCTL] and consistent with nleafs + (nleafs must be 2^l2nleafs). + - leafidx must be exactly CTLLEAFIND (expected leaf index position). + - height bounded by [0, L2LPERCTL >> 1] (valid tree height range). + - budmin validity: NOFREE only if nleafs=0; otherwise >= BUDMIN. + - Leaf nodes fit within stree array (leafidx + nleafs <= CTLTREESIZE). + - Leaf node values are either non-negative or NOFREE. + +Invoked in dbAllocAG(), dbFindCtl(), dbAdjCtl() and dbExtendFS() when +accessing dmapctl pages, catching corruption early before dmap operations +trigger invalid memory access or logic errors. + +This fixes the following UBSAN warning. + +[58245.668090][T14017] ------------[ cut here ]------------ +[58245.668103][T14017] UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2641:11 +[58245.668119][T14017] shift exponent 110 is too large for 32-bit type 'int' +[58245.668137][T14017] CPU: 0 UID: 0 PID: 14017 Comm: 4c1966e88c28fa9 Tainted: G E 6.18.0-rc4-00253-g21ce5d4ba045-dirty #124 PREEMPT_{RT,(full)} +[58245.668174][T14017] Tainted: [E]=UNSIGNED_MODULE +[58245.668176][T14017] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[58245.668184][T14017] Call Trace: +[58245.668200][T14017] +[58245.668208][T14017] dump_stack_lvl+0x189/0x250 +[58245.668288][T14017] ? __pfx_dump_stack_lvl+0x10/0x10 +[58245.668301][T14017] ? __pfx__printk+0x10/0x10 +[58245.668315][T14017] ? lock_metapage+0x303/0x400 [jfs] +[58245.668406][T14017] ubsan_epilogue+0xa/0x40 +[58245.668422][T14017] __ubsan_handle_shift_out_of_bounds+0x386/0x410 +[58245.668462][T14017] dbSplit+0x1f8/0x200 [jfs] +[58245.668543][T14017] dbAdjCtl+0x34c/0xa20 [jfs] +[58245.668628][T14017] dbAllocNear+0x2ee/0x3d0 [jfs] +[58245.668710][T14017] dbAlloc+0x933/0xba0 [jfs] +[58245.668797][T14017] ea_write+0x374/0xdd0 [jfs] +[58245.668888][T14017] ? __pfx_ea_write+0x10/0x10 [jfs] +[58245.668966][T14017] ? __jfs_setxattr+0x76e/0x1120 [jfs] +[58245.669046][T14017] __jfs_setxattr+0xa01/0x1120 [jfs] +[58245.669135][T14017] ? __pfx___jfs_setxattr+0x10/0x10 [jfs] +[58245.669216][T14017] ? mutex_lock_nested+0x154/0x1d0 +[58245.669252][T14017] ? __jfs_xattr_set+0xb9/0x170 [jfs] +[58245.669333][T14017] __jfs_xattr_set+0xda/0x170 [jfs] +[58245.669430][T14017] ? __pfx___jfs_xattr_set+0x10/0x10 [jfs] +[58245.669509][T14017] ? xattr_full_name+0x6f/0x90 +[58245.669546][T14017] ? jfs_xattr_set+0x33/0x60 [jfs] +[58245.669636][T14017] ? __pfx_jfs_xattr_set+0x10/0x10 [jfs] +[58245.669726][T14017] __vfs_setxattr+0x43c/0x480 +[58245.669743][T14017] __vfs_setxattr_noperm+0x12d/0x660 +[58245.669756][T14017] vfs_setxattr+0x16b/0x2f0 +[58245.669768][T14017] ? __pfx_vfs_setxattr+0x10/0x10 +[58245.669782][T14017] filename_setxattr+0x274/0x600 +[58245.669795][T14017] ? __pfx_filename_setxattr+0x10/0x10 +[58245.669806][T14017] ? getname_flags+0x1e5/0x540 +[58245.669829][T14017] path_setxattrat+0x364/0x3a0 +[58245.669840][T14017] ? __pfx_path_setxattrat+0x10/0x10 +[58245.669859][T14017] ? __se_sys_chdir+0x1b9/0x280 +[58245.669876][T14017] __x64_sys_lsetxattr+0xbf/0xe0 +[58245.669888][T14017] do_syscall_64+0xfa/0xfa0 +[58245.669901][T14017] ? lockdep_hardirqs_on+0x9c/0x150 +[58245.669913][T14017] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[58245.669927][T14017] ? exc_page_fault+0xab/0x100 +[58245.669937][T14017] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Reported-by: syzbot+4c1966e88c28fa96e053@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4c1966e88c28fa96e053 +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 111 insertions(+), 3 deletions(-) + +diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c +index 2abe8cc02ee6f..a841cf21da7de 100644 +--- a/fs/jfs/jfs_dmap.c ++++ b/fs/jfs/jfs_dmap.c +@@ -133,6 +133,93 @@ static const s8 budtab[256] = { + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 + }; + ++/* ++ * check_dmapctl - Validate integrity of a dmapctl structure ++ * @dcp: Pointer to the dmapctl structure to check ++ * ++ * Return: true if valid, false if corrupted ++ */ ++static bool check_dmapctl(struct dmapctl *dcp) ++{ ++ s8 budmin = dcp->budmin; ++ u32 nleafs, l2nleafs, leafidx, height; ++ int i; ++ ++ nleafs = le32_to_cpu(dcp->nleafs); ++ /* Check basic field ranges */ ++ if (unlikely(nleafs > LPERCTL)) { ++ jfs_err("dmapctl: invalid nleafs %u (max %u)", ++ nleafs, LPERCTL); ++ return false; ++ } ++ ++ l2nleafs = le32_to_cpu(dcp->l2nleafs); ++ if (unlikely(l2nleafs > L2LPERCTL)) { ++ jfs_err("dmapctl: invalid l2nleafs %u (max %u)", ++ l2nleafs, L2LPERCTL); ++ return false; ++ } ++ ++ /* Verify nleafs matches l2nleafs (must be power of two) */ ++ if (unlikely((1U << l2nleafs) != nleafs)) { ++ jfs_err("dmapctl: nleafs %u != 2^%u", ++ nleafs, l2nleafs); ++ return false; ++ } ++ ++ leafidx = le32_to_cpu(dcp->leafidx); ++ /* Check leaf index matches expected position */ ++ if (unlikely(leafidx != CTLLEAFIND)) { ++ jfs_err("dmapctl: invalid leafidx %u (expected %u)", ++ leafidx, CTLLEAFIND); ++ return false; ++ } ++ ++ height = le32_to_cpu(dcp->height); ++ /* Check tree height is within valid range */ ++ if (unlikely(height > (L2LPERCTL >> 1))) { ++ jfs_err("dmapctl: invalid height %u (max %u)", ++ height, L2LPERCTL >> 1); ++ return false; ++ } ++ ++ /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ ++ if (budmin == NOFREE) { ++ if (unlikely(nleafs > 0)) { ++ jfs_err("dmapctl: budmin is NOFREE but nleafs %u", ++ nleafs); ++ return false; ++ } ++ } else if (unlikely(budmin < BUDMIN)) { ++ jfs_err("dmapctl: invalid budmin %d (min %d)", ++ budmin, BUDMIN); ++ return false; ++ } ++ ++ /* Check leaf nodes fit within stree array */ ++ if (unlikely(leafidx + nleafs > CTLTREESIZE)) { ++ jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", ++ leafidx + nleafs, CTLTREESIZE); ++ return false; ++ } ++ ++ /* Check leaf nodes have valid values */ ++ for (i = leafidx; i < leafidx + nleafs; i++) { ++ s8 val = dcp->stree[i]; ++ ++ if (unlikely(val < NOFREE)) { ++ jfs_err("dmapctl: invalid leaf value %d at index %d", ++ val, i); ++ return false; ++ } else if (unlikely(val > 31)) { ++ jfs_err("dmapctl: leaf value %d too large at index %d", val, i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * NAME: dbMount() + * +@@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) + dcp = (struct dmapctl *) mp->data; + budmin = dcp->budmin; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, + "Corrupt dmapctl page\n"); + release_metapage(mp); +@@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) + return -EIO; + dcp = (struct dmapctl *) mp->data; + +- if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { ++ if (unlikely(!check_dmapctl(dcp))) { + jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); + release_metapage(mp); + return -EIO; +@@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + return -EIO; + } + l2dcp = (struct dmapctl *) l2mp->data; ++ if (unlikely(!check_dmapctl(l2dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ release_metapage(l2mp); ++ return -EIO; ++ } + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; +@@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l1mp == NULL) + goto errout; + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; +@@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l1dcp = (struct dmapctl *) l1mp->data; ++ if (unlikely(!check_dmapctl(l1dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start L0 */ + j = 0; +@@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + if (l0mp == NULL) + goto errout; + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> +@@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) + goto errout; + + l0dcp = (struct dmapctl *) l0mp->data; ++ if (unlikely(!check_dmapctl(l0dcp))) { ++ jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); ++ goto errout; ++ } + + /* compute start dmap */ + i = 0; +-- +2.53.0 + diff --git a/queue-7.0/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch b/queue-7.0/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch new file mode 100644 index 0000000000..c6423aaf93 --- /dev/null +++ b/queue-7.0/jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch @@ -0,0 +1,195 @@ +From 898aa073b135e5055138ad2890c9c4509c396513 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Nov 2025 23:43:50 +0800 +Subject: jfs: add dtroot integrity check to prevent index out-of-bounds + +From: Yun Zhou + +[ Upstream commit c83abc766aeb153e69cb46363bf7c9de0c9f3268 ] + +Add check_dtroot() to validate dtroot_t integrity, focusing on preventing +index/pointer overflows from on-disk corruption. + +Key checks: + - freecnt bounded by [0, DTROOTMAXSLOT-1] (slot[0] reserved for header). + - freelist validity: -1 when freecnt=0; 1~DTROOTMAXSLOT-1 when non-zero, + with linked list checks (no duplicates, proper termination via next=-1). + - stbl bounds: nextindex within stbl array size; entries within 0~8, no + duplicates (excluding idx=0). + +Invoked in copy_from_dinode() when loading directory inodes, catching +corruption early before directory operations trigger out-of-bounds access. + +This fixes the following UBSAN warning. + +[ 101.832754][ T5960] ------------[ cut here ]------------ +[ 101.832762][ T5960] UBSAN: array-index-out-of-bounds in fs/jfs/jfs_dtree.c:3713:8 +[ 101.832792][ T5960] index -1 is out of range for type 'struct dtslot[128]' +[ 101.832807][ T5960] CPU: 2 UID: 0 PID: 5960 Comm: 5f7f0caf9979e9d Tainted: G E 6.18.0-rc4-00250-g2603eb907f03 #119 PREEMPT_{RT,(full +[ 101.832817][ T5960] Tainted: [E]=UNSIGNED_MODULE +[ 101.832819][ T5960] Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 101.832823][ T5960] Call Trace: +[ 101.832833][ T5960] +[ 101.832838][ T5960] dump_stack_lvl+0x189/0x250 +[ 101.832909][ T5960] ? __pfx_dump_stack_lvl+0x10/0x10 +[ 101.832925][ T5960] ? __pfx__printk+0x10/0x10 +[ 101.832934][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.832959][ T5960] ubsan_epilogue+0xa/0x40 +[ 101.832966][ T5960] __ubsan_handle_out_of_bounds+0xe9/0xf0 +[ 101.833007][ T5960] dtInsertEntry+0x936/0x1430 [jfs] +[ 101.833094][ T5960] dtSplitPage+0x2c8b/0x3ed0 [jfs] +[ 101.833177][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833193][ T5960] dtInsert+0x109b/0x6000 [jfs] +[ 101.833283][ T5960] ? rt_mutex_slowunlock+0x493/0x8a0 +[ 101.833296][ T5960] ? __pfx_rt_mutex_slowunlock+0x10/0x10 +[ 101.833307][ T5960] ? rt_spin_unlock+0x161/0x200 +[ 101.833315][ T5960] ? __pfx_dtInsert+0x10/0x10 [jfs] +[ 101.833391][ T5960] ? txLock+0xaf9/0x1cb0 [jfs] +[ 101.833477][ T5960] ? dtInitRoot+0x22a/0x670 [jfs] +[ 101.833556][ T5960] jfs_mkdir+0x6ec/0xa70 [jfs] +[ 101.833636][ T5960] ? __pfx_jfs_mkdir+0x10/0x10 [jfs] +[ 101.833721][ T5960] ? generic_permission+0x2e5/0x690 +[ 101.833760][ T5960] ? bpf_lsm_inode_mkdir+0x9/0x20 +[ 101.833776][ T5960] vfs_mkdir+0x306/0x510 +[ 101.833786][ T5960] do_mkdirat+0x247/0x590 +[ 101.833795][ T5960] ? __pfx_do_mkdirat+0x10/0x10 +[ 101.833804][ T5960] ? getname_flags+0x1e5/0x540 +[ 101.833815][ T5960] __x64_sys_mkdir+0x6c/0x80 +[ 101.833823][ T5960] do_syscall_64+0xfa/0xfa0 +[ 101.833832][ T5960] ? lockdep_hardirqs_on+0x9c/0x150 +[ 101.833840][ T5960] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f +[ 101.833847][ T5960] ? exc_page_fault+0xab/0x100 +[ 101.833856][ T5960] entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_dtree.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/jfs/jfs_dtree.h | 2 ++ + fs/jfs/jfs_imap.c | 4 +++ + 3 files changed, 92 insertions(+) + +diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c +index 9ab3f2fc61d17..8abd9c7663ea4 100644 +--- a/fs/jfs/jfs_dtree.c ++++ b/fs/jfs/jfs_dtree.c +@@ -4297,3 +4297,89 @@ int dtModify(tid_t tid, struct inode *ip, + + return 0; + } ++ ++bool check_dtroot(dtroot_t *p) ++{ ++ DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; ++ int i; ++ ++ /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 ++ * (since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freecnt < 0 || ++ p->header.freecnt > DTROOTMAXSLOT - 1)) { ++ jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); ++ return false; ++ } else if (p->header.freecnt == 0) { ++ /* No free slots: freelist must be -1 */ ++ if (unlikely(p->header.freelist != -1)) { ++ jfs_err("freecnt=0, but freelist=%d in dtroot\n", ++ p->header.freelist); ++ return false; ++ } ++ } else { ++ int fsi, i; ++ /* When there are free slots, freelist must be a valid slot index in ++ * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). ++ */ ++ if (unlikely(p->header.freelist < 1 || ++ p->header.freelist >= DTROOTMAXSLOT)) { ++ jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); ++ return false; ++ } ++ ++ /* Traverse the free list to check validity of all node indices */ ++ fsi = p->header.freelist; ++ for (i = 0; i < p->header.freecnt - 1; i++) { ++ /* Check for duplicate indices in the free list */ ++ if (unlikely(__test_and_set_bit(fsi, bitmap))) { ++ jfs_err("duplicate index%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ fsi = p->slot[fsi].next; ++ ++ /* Ensure the next slot index in the free list is valid */ ++ if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { ++ jfs_err("Bad index:%d in slot in dtroot\n", fsi); ++ return false; ++ } ++ } ++ ++ /* The last node in the free list must terminate with next = -1 */ ++ if (unlikely(p->slot[fsi].next != -1)) { ++ jfs_err("Bad next:%d of the last slot in dtroot\n", ++ p->slot[fsi].next); ++ return false; ++ } ++ } ++ ++ /* Validate nextindex (next free entry index in stbl) ++ * stbl array has size 8 (indices 0~7). ++ * It may get set to 8 when the last free slot has been filled. ++ */ ++ if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { ++ jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); ++ return false; ++ } ++ ++ /* Validate index validity of stbl array (8 elements) ++ * Each entry in stbl is a slot index, with valid range: -1 (invalid) ++ * or 0~8 (slot[0]~slot[8]) ++ */ ++ for (i = 0; i < p->header.nextindex; i++) { ++ int idx = p->header.stbl[i]; ++ ++ if (unlikely(idx < 0 || idx >= 9)) { ++ jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); ++ return false; /* stbl entry points out of slot array range */ ++ } ++ ++ /* Check for duplicate valid indices (skip check for idx=0) */ ++ if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { ++ jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); ++ return false; ++ } ++ } ++ ++ return true; ++} +diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h +index 1758289647a0e..94dc16123c87e 100644 +--- a/fs/jfs/jfs_dtree.h ++++ b/fs/jfs/jfs_dtree.h +@@ -253,4 +253,6 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, + ino_t * orig_ino, ino_t new_ino, int flag); + + extern int jfs_readdir(struct file *file, struct dir_context *ctx); ++ ++extern bool check_dtroot(dtroot_t *p); + #endif /* !_H_JFS_DTREE */ +diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c +index 294a67327c735..fbb5f7966b754 100644 +--- a/fs/jfs/jfs_imap.c ++++ b/fs/jfs/jfs_imap.c +@@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) + + if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); ++ if (!check_dtroot(&jfs_ip->i_dtroot)) { ++ jfs_error(ip->i_sb, "Corrupt dtroot\n"); ++ return -EIO; ++ } + } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } else +-- +2.53.0 + diff --git a/queue-7.0/jfs-always-load-filesystem-uuid-during-mount.patch b/queue-7.0/jfs-always-load-filesystem-uuid-during-mount.patch new file mode 100644 index 0000000000..e46d67259c --- /dev/null +++ b/queue-7.0/jfs-always-load-filesystem-uuid-during-mount.patch @@ -0,0 +1,55 @@ +From 0895929d9425a747b9ef8f06ac794563bc4e0cc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 02:55:39 +0000 +Subject: JFS: always load filesystem UUID during mount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: João Paredes + +[ Upstream commit 679330e4a7af1d102d035b13b2b9d41bc1dfbbf7 ] + +The filesystem UUID was only being loaded into super_block sb when an +external journal device was in use. When mounting without an external +journal, the UUID remained unset, which prevented the computation of +a filesystem ID (fsid), which could be confirmed via `stat -f -c "%i"` +and thus user space could not use fanotify correctly. + +A missing filesystem ID causes fanotify to return ENODEV when marking +the filesystem for events like FAN_CREATE, FAN_DELETE, FAN_MOVED_TO, +and FAN_MOVED_FROM. As a result, applications relying on fanotify +could not monitor these events on JFS filesystems without an external +journal. + +Moved the UUID initialization so it is always performed during mount, +ensuring the superblock UUID is consistently available. + +Signed-off-by: João Paredes +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_mount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c +index 52e6b58c5dbd2..dac822f150701 100644 +--- a/fs/jfs/jfs_mount.c ++++ b/fs/jfs/jfs_mount.c +@@ -378,11 +378,12 @@ static int chkSuper(struct super_block *sb) + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; ++ uuid_copy(&sbi->uuid, &j_sb->s_uuid); ++ + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); +- uuid_copy(&sbi->uuid, &j_sb->s_uuid); + uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); + } + sbi->fsckpxd = j_sb->s_fsckpxd; +-- +2.53.0 + diff --git a/queue-7.0/jfs-fix-corrupted-list-in-dbupdatepmap.patch b/queue-7.0/jfs-fix-corrupted-list-in-dbupdatepmap.patch new file mode 100644 index 0000000000..a7a7f398b6 --- /dev/null +++ b/queue-7.0/jfs-fix-corrupted-list-in-dbupdatepmap.patch @@ -0,0 +1,111 @@ +From 37fa8ec345283f3c50d87f6fd90ad7d86e7dc0aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Nov 2025 15:58:18 +0800 +Subject: jfs: fix corrupted list in dbUpdatePMap + +From: Yun Zhou + +[ Upstream commit 3c778ec882084626ac915d6c6ec88aff87b82221 ] + +This patch resolves the "list_add corruption. next is NULL" Oops +reported by syzkaller in dbUpdatePMap(). The root cause is uninitialized +synclist nodes in struct metapage and struct TxBlock, plus improper list +node removal using list_del() (which leaves nodes in an invalid state). + +This fixes the following Oops reported by syzkaller. + +list_add corruption. next is NULL. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:28! +Oops: invalid opcode: 0000 [#1] SMP KASAN PTI +CPU: 1 UID: 0 PID: 122 Comm: jfsCommit Not tainted syzkaller #0 +PREEMPT_{RT,(full)} +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 10/02/2025 +RIP: 0010:__list_add_valid_or_report+0xc3/0x130 lib/list_debug.c:27 +Code: 4c 89 f2 48 89 d9 e8 0c 88 a4 fc 90 0f 0b 48 c7 c7 20 de 3d 8b e8 +fd 87 a4 fc 90 0f 0b 48 c7 c7 c0 de 3d 8b e8 ee 87 a4 fc 90 <0f> 0b 48 +89 df e8 13 c3 7d fd 42 80 7c 2d 00 00 74 08 4c 89 e7 e8 +RSP: 0018:ffffc9000395fa20 EFLAGS: 00010246 +RAX: 0000000000000022 RBX: 0000000000000000 RCX: 270c5dfadb559700 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +RBP: 00000000000f0000 R08: 0000000000000000 R09: 0000000000000000 +R10: dffffc0000000000 R11: fffff5200072bee9 R12: 0000000000000000 +R13: dffffc0000000000 R14: 0000000000000004 R15: 1ffff92000632266 +FS: 0000000000000000(0000) GS:ffff888126ef9000(0000) +knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000056341fdb86c0 CR3: 0000000040a18000 CR4: 00000000003526f0 +Call Trace: + + __list_add_valid include/linux/list.h:96 [inline] + __list_add include/linux/list.h:158 [inline] + list_add include/linux/list.h:177 [inline] + dbUpdatePMap+0x7e4/0xeb0 fs/jfs/jfs_dmap.c:577 + txAllocPMap+0x57d/0x6b0 fs/jfs/jfs_txnmgr.c:2426 + txUpdateMap+0x81e/0x9c0 fs/jfs/jfs_txnmgr.c:2364 + txLazyCommit fs/jfs/jfs_txnmgr.c:2665 [inline] + jfs_lazycommit+0x3f1/0xa10 fs/jfs/jfs_txnmgr.c:2734 + kthread+0x711/0x8a0 kernel/kthread.c:463 + ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +Modules linked in: +---[ end trace 0000000000000000 ]--- + +Reported-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=4d0a0feb49c5138cac46 +Tested-by: syzbot+4d0a0feb49c5138cac46@syzkaller.appspotmail.com +Signed-off-by: Yun Zhou +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_metapage.c | 3 ++- + fs/jfs/jfs_txnmgr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c +index 64c6eaa7f3f26..78dd8a1b29b7d 100644 +--- a/fs/jfs/jfs_metapage.c ++++ b/fs/jfs/jfs_metapage.c +@@ -270,6 +270,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) + mp->clsn = 0; + mp->log = NULL; + init_waitqueue_head(&mp->wait); ++ INIT_LIST_HEAD(&mp->synclist); + } + return mp; + } +@@ -379,7 +380,7 @@ static void remove_from_logsync(struct metapage *mp) + mp->lsn = 0; + mp->clsn = 0; + log->count--; +- list_del(&mp->synclist); ++ list_del_init(&mp->synclist); + } + LOGSYNC_UNLOCK(log, flags); + } +diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c +index c16578af3a77e..083dbbb0c3268 100644 +--- a/fs/jfs/jfs_txnmgr.c ++++ b/fs/jfs/jfs_txnmgr.c +@@ -275,6 +275,7 @@ int txInit(void) + for (k = 0; k < nTxBlock; k++) { + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); ++ INIT_LIST_HEAD(&TxBlock[k].synclist); + } + + for (k = 1; k < nTxBlock - 1; k++) { +@@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) + if (tblk->lsn) { + LOGSYNC_LOCK(log, flags); + log->count--; +- list_del(&tblk->synclist); ++ list_del_init(&tblk->synclist); + LOGSYNC_UNLOCK(log, flags); + } + } +-- +2.53.0 + diff --git a/queue-7.0/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch b/queue-7.0/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch new file mode 100644 index 0000000000..d661cc0859 --- /dev/null +++ b/queue-7.0/jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch @@ -0,0 +1,115 @@ +From abbcfe7cd671c4185e6e1c9dc2eebfad7d2121b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:11:50 -0300 +Subject: jfs: hold LOG_LOCK on umount to avoid null-ptr-deref + +From: Helen Koike + +[ Upstream commit ca5848ae87d24886a7886f5a22278bd4045c15f8 ] + +write_special_inodes() function iterate through the log->sb_list and +access the sbi fields, which can be set to NULL concurrently by umount. + +Fix concurrency issue by holding LOG_LOCK and checking for NULL. + +Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77 +Signed-off-by: Helen Koike +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 16 +++++++--------- + fs/jfs/jfs_logmgr.h | 7 +++++++ + fs/jfs/jfs_umount.c | 10 ++++++++++ + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index ada00d5bc2146..d8266220776e8 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; + static DEFINE_SPINLOCK(log_redrive_lock); + + +-/* +- * log read/write serialization (per log) +- */ +-#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +-#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +-#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + + + /* +@@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, + struct jfs_sb_info *sbi; + + list_for_each_entry(sbi, &log->sb_list, log_list) { +- writer(sbi->ipbmap->i_mapping); +- writer(sbi->ipimap->i_mapping); +- writer(sbi->direct_inode->i_mapping); ++ /* These pointers can be NULL before list_del during umount */ ++ if (sbi->ipbmap) ++ writer(sbi->ipbmap->i_mapping); ++ if (sbi->ipimap) ++ writer(sbi->ipimap->i_mapping); ++ if (sbi->direct_inode) ++ writer(sbi->direct_inode->i_mapping); + } + } + +diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h +index 8b8994e48cd08..09e0ef6aeccef 100644 +--- a/fs/jfs/jfs_logmgr.h ++++ b/fs/jfs/jfs_logmgr.h +@@ -402,6 +402,13 @@ struct jfs_log { + int no_integrity; /* 3: flag to disable journaling to disk */ + }; + ++/* ++ * log read/write serialization (per log) ++ */ ++#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) ++#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) ++#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) ++ + /* + * Log flag + */ +diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c +index 8ec43f53f6865..18569f1eaabdb 100644 +--- a/fs/jfs/jfs_umount.c ++++ b/fs/jfs/jfs_umount.c +@@ -20,6 +20,7 @@ + #include "jfs_superblock.h" + #include "jfs_dmap.h" + #include "jfs_imap.h" ++#include "jfs_logmgr.h" + #include "jfs_metapage.h" + #include "jfs_debug.h" + +@@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) + */ + jfs_flush_journal(log, 2); + ++ /* ++ * Hold log lock so write_special_inodes (lmLogSync) cannot see ++ * this sbi with a NULL inode pointer while iterating log->sb_list. ++ */ ++ if (log) ++ LOG_LOCK(log); + /* + * close fileset inode allocation map (aka fileset inode) + */ +@@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) + */ + filemap_write_and_wait(sbi->direct_inode->i_mapping); + ++ if (log) ++ LOG_UNLOCK(log); ++ + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are +-- +2.53.0 + diff --git a/queue-7.0/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch b/queue-7.0/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch new file mode 100644 index 0000000000..6f12aaf5f0 --- /dev/null +++ b/queue-7.0/jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch @@ -0,0 +1,124 @@ +From 5fefd80910f29c8aa7b39b1e2c0479ee3c01d653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Dec 2025 21:57:51 +0800 +Subject: jfs: Set the lbmDone flag at the end of lbmIODone + +From: Edward Adam Davis + +[ Upstream commit b15e4310633f90072d66cc9b6692acbf6b4d7d00 ] + +In lbmRead(), the I/O event waited for by wait_event() finishes before +it goes to sleep, and the lbmIODone() prematurely sets the flag to +lbmDONE, thus ending the wait. This causes wait_event() to return before +lbmREAD is cleared (because lbmDONE was set first), the premature return +of wait_event() leads to the release of lbuf before lbmIODone() returns, +thus triggering the use-after-free vulnerability reported in [1]. + +Moving the operation of setting the lbmDONE flag to after clearing lbmREAD +in lbmIODone() avoids the use-after-free vulnerability reported in [1]. + +[1] +BUG: KASAN: slab-use-after-free in rt_spin_lock+0x88/0x3e0 kernel/locking/spinlock_rt.c:56 +Call Trace: + blk_update_request+0x57e/0xe60 block/blk-mq.c:1007 + blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1169 + blk_complete_reqs block/blk-mq.c:1244 [inline] + blk_done_softirq+0x10a/0x160 block/blk-mq.c:1249 + +Allocated by task 6101: + lbmLogInit fs/jfs/jfs_logmgr.c:1821 [inline] + lmLogInit+0x3d0/0x19e0 fs/jfs/jfs_logmgr.c:1269 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Freed by task 6101: + kfree+0x1bd/0x900 mm/slub.c:6876 + lbmLogShutdown fs/jfs/jfs_logmgr.c:1864 [inline] + lmLogInit+0x1137/0x19e0 fs/jfs/jfs_logmgr.c:1415 + open_inline_log fs/jfs/jfs_logmgr.c:1175 [inline] + lmLogOpen+0x4e1/0xfa0 fs/jfs/jfs_logmgr.c:1069 + jfs_mount_rw+0xe9/0x670 fs/jfs/jfs_mount.c:257 + jfs_fill_super+0x754/0xd80 fs/jfs/super.c:532 + +Reported-by: syzbot+1d38eedcb25a3b5686a7@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=1d38eedcb25a3b5686a7 +Signed-off-by: Edward Adam Davis +Signed-off-by: Dave Kleikamp +Signed-off-by: Sasha Levin +--- + fs/jfs/jfs_logmgr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c +index d8266220776e8..306165e61438c 100644 +--- a/fs/jfs/jfs_logmgr.c ++++ b/fs/jfs/jfs_logmgr.c +@@ -2178,8 +2178,6 @@ static void lbmIODone(struct bio *bio) + + LCACHE_LOCK(flags); /* disable+lock */ + +- bp->l_flag |= lbmDONE; +- + if (bio->bi_status) { + bp->l_flag |= lbmERROR; + +@@ -2194,12 +2192,10 @@ static void lbmIODone(struct bio *bio) + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + +- return; ++ goto out; + } + + /* +@@ -2223,8 +2219,7 @@ static void lbmIODone(struct bio *bio) + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); +- LCACHE_UNLOCK(flags); +- return; ++ goto out; + } + + tail = log->wqueue; +@@ -2276,8 +2271,6 @@ static void lbmIODone(struct bio *bio) + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { +- LCACHE_UNLOCK(flags); /* unlock+enable */ +- + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } +@@ -2288,6 +2281,7 @@ static void lbmIODone(struct bio *bio) + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); ++ LCACHE_LOCK(flags); /* disable+lock */ + } + + /* +@@ -2300,9 +2294,11 @@ static void lbmIODone(struct bio *bio) + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); +- +- LCACHE_UNLOCK(flags); /* unlock+enable */ + } ++ ++out: ++ bp->l_flag |= lbmDONE; ++ LCACHE_UNLOCK(flags); + } + + int jfsIOWait(void *arg) +-- +2.53.0 + diff --git a/queue-7.0/kho-skip-kho-for-crash-kernel.patch b/queue-7.0/kho-skip-kho-for-crash-kernel.patch new file mode 100644 index 0000000000..c68545880f --- /dev/null +++ b/queue-7.0/kho-skip-kho-for-crash-kernel.patch @@ -0,0 +1,60 @@ +From d402ceec30c9651693661638a4d6568837f545ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 01:16:05 +0000 +Subject: kho: skip KHO for crash kernel + +From: Evangelos Petrongonas + +[ Upstream commit a6715d7ec472a476db17787697a4abda62962284 ] + +kho_fill_kimage() unconditionally populates the kimage with KHO +metadata for every kexec image type. When the image is a crash kernel, +this can be problematic as the crash kernel can run in a small reserved +region and the KHO scratch areas can sit outside it. +The crash kernel then faults during kho_memory_init() when it +tries phys_to_virt() on the KHO FDT address: + + Unable to handle kernel paging request at virtual address xxxxxxxx + ... + fdt_offset_ptr+... + fdt_check_node_offset_+... + fdt_first_property_offset+... + fdt_get_property_namelen_+... + fdt_getprop+... + kho_memory_init+... + mm_core_init+... + start_kernel+... + +kho_locate_mem_hole() already skips KHO logic for KEXEC_TYPE_CRASH +images, but kho_fill_kimage() was missing the same guard. As +kho_fill_kimage() is the single point that populates image->kho.fdt +and image->kho.scratch, fixing it here is sufficient for both arm64 +and x86 as the FDT and boot_params path are bailing out when these +fields are unset. + +Fixes: d7255959b69a ("kho: allow kexec load before KHO finalization") +Signed-off-by: Evangelos Petrongonas +Reviewed-by: Mike Rapoport (Microsoft) +Link: https://patch.msgid.link/20260410011609.1103-1-epetron@amazon.de +Signed-off-by: Mike Rapoport (Microsoft) +Signed-off-by: Sasha Levin +--- + kernel/liveupdate/kexec_handover.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c +index 479c42e08b74a..d8893f2adce8a 100644 +--- a/kernel/liveupdate/kexec_handover.c ++++ b/kernel/liveupdate/kexec_handover.c +@@ -1556,7 +1556,7 @@ int kho_fill_kimage(struct kimage *image) + int err = 0; + struct kexec_buf scratch; + +- if (!kho_enable) ++ if (!kho_enable || image->type == KEXEC_TYPE_CRASH) + return 0; + + image->kho.fdt = virt_to_phys(kho_out.fdt); +-- +2.53.0 + diff --git a/queue-7.0/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch b/queue-7.0/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch new file mode 100644 index 0000000000..2ccdbc236d --- /dev/null +++ b/queue-7.0/kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch @@ -0,0 +1,103 @@ +From c42f93a4b649d2a4f296896c3aba7e90f5a92435 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist() + +From: Jianpeng Chang + +[ Upstream commit 307abfac04a254c09c5705d816b33354acee97a0 ] + +When kprobe_add_area_blacklist() iterates through a section like +.kprobes.text, the start address may not correspond to a named symbol. +On ARM64 with CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y (introduced by +commit baaf553d3bc3 ("arm64: Implement +HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS")), the compiler flag +-fpatchable-function-entry=4,2 inserts 2 NOPs before each function entry +point for ftrace call_ops. These pre-function NOPs sit at the section base +address, before the first named function symbol. The compiler emits a $x +mapping symbol at offset 0x00 to mark the start of code, but +find_kallsyms_symbol() ignores mapping symbols. + +Without CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS (e.g. defconfig), no +pre-function NOPs are inserted, the first function starts at offset +0x00, and the bug does not trigger. + +This only affects modules that have a .kprobes.text section (i.e. those +using the __kprobes annotation). Modules using NOKPROBE_SYMBOL() instead +(like kretprobe_example.ko) blacklist exact function addresses via the +_kprobe_blacklist section and are not affected. + +For kprobe_example.ko on ARM64 with -fpatchable-function-entry=4,2, +the .kprobes.text section layout is: + + offset 0x00: $x + 2 NOPs (mapping symbol + ftrace preamble) + offset 0x08: handler_post (64 bytes) + offset 0x50: handler_pre (68 bytes) + +kprobe_add_area_blacklist() starts iterating from the section base +address (offset 0x00), which only has the $x mapping symbol. +kprobe_add_ksym_blacklist() then calls kallsyms_lookup_size_offset() +for this address, which goes through: + + kallsyms_lookup_size_offset() + -> module_address_lookup() + -> find_kallsyms_symbol() + +find_kallsyms_symbol() scans all module symbols to find the closest +preceding symbol. + +Since no named text symbol exists at offset 0x00, +find_kallsyms_symbol() picks __UNIQUE_ID_vermagic (a .modinfo symbol +whose address is in the temporary image) as the "best" match. The +computed "size" = next_text_symbol - modinfo_symbol spans across +these two unrelated memory regions, creating a blacklist entry with +a bogus range of tens of terabytes. + +Whether this causes a visible failure depends on address randomization, +here is what happens on Raspberry Pi 4/5: + + - On RPi5, the bogus size was ~35 TB. start + size stayed within + 64-bit range, so the blacklist entry covered the entire kernel + text. register_kprobe() in the module's own init function failed + with -EINVAL. + + - On RPi4, the bogus size was ~75 TB. start + size overflowed + 64 bits and wrapped to a small address near zero. The range + check (addr >= start && addr < end) then failed because end + wrapped around, so the bogus entry was accidentally harmless + and kprobes worked by luck. + +The same bug exists on both machines, but randomization determines whether +the integer overflow masks it or not. + +Fix this by adding notrace to the __kprobes macro. Functions in +.kprobes.text are kprobe infrastructure handlers that should never be +traced by ftrace. With notrace, the compiler stops inserting them and the +non-symbol gap at the section start disappears entirely. + +Link: https://lore.kernel.org/all/20260506012706.2785785-1-jianpeng.chang.cn@windriver.com/ + +Fixes: baaf553d3bc3 ("arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS") +Signed-off-by: Jianpeng Chang +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + include/asm-generic/kprobes.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/asm-generic/kprobes.h b/include/asm-generic/kprobes.h +index 060eab094e5a2..5290a2b2e15a0 100644 +--- a/include/asm-generic/kprobes.h ++++ b/include/asm-generic/kprobes.h +@@ -14,7 +14,7 @@ static unsigned long __used \ + _kbl_addr_##fname = (unsigned long)fname; + # define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) + /* Use this to forbid a kprobes attach on very low level functions */ +-# define __kprobes __section(".kprobes.text") ++# define __kprobes notrace __section(".kprobes.text") + # define nokprobe_inline __always_inline + #else + # define NOKPROBE_SYMBOL(fname) +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch b/queue-7.0/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch new file mode 100644 index 0000000000..20ea1d898b --- /dev/null +++ b/queue-7.0/ksmbd-fix-createoptions-sanitization-clobbering-the-.patch @@ -0,0 +1,60 @@ +From 041d6f0898b0102e71524dd20aedcf9fd1509f28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 02:51:25 +0900 +Subject: ksmbd: fix CreateOptions sanitization clobbering the whole field + +From: DaeMyung Kang + +[ Upstream commit 5d115fa84027e4b999c3d3c7b1294849cf35cdb2 ] + +smb2_open() attempts to clear conflicting CreateOptions bits +(FILE_SEQUENTIAL_ONLY_LE together with FILE_RANDOM_ACCESS_LE, and +FILE_NO_COMPRESSION_LE on a directory open), but uses a plain +assignment of the bitwise negation of the target flag: + + req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); + req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); + +This replaces the entire field with 0xFFFFFFFB / 0xFFFFFFEF rather +than clearing a single bit. With the SEQUENTIAL/RANDOM case, the +next check for FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +FILE_RESERVE_OPFILTER_LE then trivially matches and a legitimate +request is rejected with -EOPNOTSUPP. With the NO_COMPRESSION case, +every downstream test (FILE_DELETE_ON_CLOSE, etc.) operates on a +corrupted CreateOptions value. + +Use &= ~FLAG to clear only the intended bit in both places. + +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index fd38058fa23da..86a99f705bc83 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3058,7 +3058,7 @@ int smb2_open(struct ksmbd_work *work) + } else { + if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE && + req->CreateOptions & FILE_RANDOM_ACCESS_LE) +- req->CreateOptions = ~(FILE_SEQUENTIAL_ONLY_LE); ++ req->CreateOptions &= ~FILE_SEQUENTIAL_ONLY_LE; + + if (req->CreateOptions & + (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION | +@@ -3072,7 +3072,7 @@ int smb2_open(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out2; + } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) { +- req->CreateOptions = ~(FILE_NO_COMPRESSION_LE); ++ req->CreateOptions &= ~FILE_NO_COMPRESSION_LE; + } + } + } +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch b/queue-7.0/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch new file mode 100644 index 0000000000..f9d634b788 --- /dev/null +++ b/queue-7.0/ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch @@ -0,0 +1,41 @@ +From 3b4c5d6d34390bb7c94b8c679c6a4c3a64479060 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:58:26 +0900 +Subject: ksmbd: fix O(N^2) DoS in smb2_lock via unbounded LockCount + +From: Akif Sait + +[ Upstream commit bd0a1ca52b6da64b1a163f103b28b488b20497fe ] + +smb2_lock() performs O(N^2) conflict detection with no cap on LockCount. +Cap lock_count at 64 to prevent CPU exhaustion from a single request. + +Signed-off-by: Akif Sait +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 86a99f705bc83..0c7ebdafb7473 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -7480,7 +7480,12 @@ int smb2_lock(struct ksmbd_work *work) + lock_ele = req->locks; + + ksmbd_debug(SMB, "lock count is %d\n", lock_count); +- if (!lock_count) { ++ /* ++ * Cap lock_count at 64. The MS-SMB2 spec defines Open.LockSequenceArray ++ * as exactly 64 entries so 64 is the intended ceiling. No real workload ++ * comes close to this in a single request. ++ */ ++ if (!lock_count || lock_count > 64) { + err = -EINVAL; + goto out2; + } +-- +2.53.0 + diff --git a/queue-7.0/kunit-config-enable-kunit_debugfs-by-default.patch b/queue-7.0/kunit-config-enable-kunit_debugfs-by-default.patch new file mode 100644 index 0000000000..12c3982b81 --- /dev/null +++ b/queue-7.0/kunit-config-enable-kunit_debugfs-by-default.patch @@ -0,0 +1,42 @@ +From 5f170967efb883c92f5e02730812fe62cdd47352 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:53 +0800 +Subject: kunit: config: Enable KUNIT_DEBUGFS by default + +From: David Gow + +[ Upstream commit 17e4c68ff35090d8cb743e3c82c09f92fda1ebda ] + +The KUNIT_DEBUGFS option is currently enabled based on the value of +KUNIT_ALL_TESTS, but it really doesn't have anything to do with the set of +enabled tests, so just enable it by default anyway. In particular, this +shouldn't be only visible if KUNIT_ALL_TESTS is set, which is quite +confusing. + +Link: https://lore.kernel.org/r/20260425034155.53913-1-david@davidgow.net +Fixes: beaed42c427d ("kunit: default KUNIT_* fragments to KUNIT_ALL_TESTS") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index 498cc51e493dc..f80ca3aeedb05 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -16,8 +16,8 @@ menuconfig KUNIT + if KUNIT + + config KUNIT_DEBUGFS +- bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if !KUNIT_ALL_TESTS +- default KUNIT_ALL_TESTS ++ bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ default y + help + Enable debugfs representation for kunit. Currently this consists + of /sys/kernel/debug/kunit//results files for each +-- +2.53.0 + diff --git a/queue-7.0/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch b/queue-7.0/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch new file mode 100644 index 0000000000..ce55153ce4 --- /dev/null +++ b/queue-7.0/kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch @@ -0,0 +1,36 @@ +From 0877dbff0808ab290f081fc795aa9b4095090920 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 11:41:54 +0800 +Subject: kunit: config: KUNIT_DEBUGFS should depend on DEBUG_FS + +From: David Gow + +[ Upstream commit 8f80b5b227ef9ea422080487715c841856339aed ] + +CONFIG_KUNIT_DEBUGFS is totally useless without debugfs, so it should +depend on CONFIG_DEBUG_FS. + +Link: https://lore.kernel.org/r/20260425034155.53913-2-david@davidgow.net +Fixes: e2219db280e3 ("kunit: add debugfs /sys/kernel/debug/kunit//results display") +Signed-off-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + lib/kunit/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig +index f80ca3aeedb05..94ff8e4089bfb 100644 +--- a/lib/kunit/Kconfig ++++ b/lib/kunit/Kconfig +@@ -17,6 +17,7 @@ if KUNIT + + config KUNIT_DEBUGFS + bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" ++ depends on DEBUG_FS + default y + help + Enable debugfs representation for kunit. Currently this consists +-- +2.53.0 + diff --git a/queue-7.0/leds-core-implement-fallback-to-software-node-name-f.patch b/queue-7.0/leds-core-implement-fallback-to-software-node-name-f.patch new file mode 100644 index 0000000000..2a03652e0d --- /dev/null +++ b/queue-7.0/leds-core-implement-fallback-to-software-node-name-f.patch @@ -0,0 +1,44 @@ +From 61b3ab89c8b0823942e20d4355562e03c3998b20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 18:43:27 -0700 +Subject: leds: core: Implement fallback to software node name for LED names + +From: Dmitry Torokhov + +[ Upstream commit 4f530c65487636dc1536b3fa1041f9a877a66a7f ] + +If a software node defining an LED is missing explicit 'label', 'color', +or 'function' properties, led_compose_name() currently fails with +-EINVAL, because fallback to using node name in place of LED name/label +is only implemented for OF nodes. + +Implement similar fallback for software nodes. Unlike OF nodes, which +use the short 'name' attribute of the device tree node to avoid +including the address block, use fwnode_get_name() directly since +swnodes do not include an address block and always have a valid name. + +Signed-off-by: Dmitry Torokhov +Link: https://patch.msgid.link/20260311-led-swnode-name-v1-1-798a49e041c6@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/led-core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c +index 59473f286b31f..8ce41b36c6455 100644 +--- a/drivers/leds/led-core.c ++++ b/drivers/leds/led-core.c +@@ -581,6 +581,9 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data, + } else if (is_of_node(fwnode)) { + n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", + to_of_node(fwnode)->name); ++ } else if (is_software_node(fwnode)) { ++ n = snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s", ++ fwnode_get_name(fwnode)); + } else + return -EINVAL; + +-- +2.53.0 + diff --git a/queue-7.0/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch b/queue-7.0/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch new file mode 100644 index 0000000000..ccbe99e6f3 --- /dev/null +++ b/queue-7.0/leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch @@ -0,0 +1,35 @@ +From f47683c07c2ff0a576360d11b178bd4c54d20a08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 22:09:52 +0100 +Subject: leds: lgm-sso: Fix typo in macro for src offset + +From: Lukas Kraft + +[ Upstream commit 0e2287999f0432b51a54c235db660789ca657f53 ] + +Replace unused argument pinc with used argument pin. + +Signed-off-by: Lukas Kraft +Link: https://patch.msgid.link/20260312210958.48467-1-rebootrequired42@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 3d9ef9a54805c..0f27c68e27411 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -25,7 +25,7 @@ + #define LED_BLINK_H8_0 0x0 + #define LED_BLINK_H8_1 0x4 + #define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2)) +-#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4) ++#define GET_SRC_OFFSET(pin) (((pin) * 6) + 4) + + #define DUTY_CYCLE(x) (0x8 + ((x) * 4)) + #define SSO_CON0 0x2B0 +-- +2.53.0 + diff --git a/queue-7.0/m68k-fix-task-info-flags-handling-for-68000.patch b/queue-7.0/m68k-fix-task-info-flags-handling-for-68000.patch new file mode 100644 index 0000000000..dd697e5151 --- /dev/null +++ b/queue-7.0/m68k-fix-task-info-flags-handling-for-68000.patch @@ -0,0 +1,84 @@ +From 4fc368edbf60243dee3c985b517926513a91ef54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 11:31:08 +0900 +Subject: m68k: Fix task info flags handling for 68000 + +From: Daniel Palmer + +[ Upstream commit 2c6805145e1605cef39459f78979f7edee251b41 ] + +The logic for deciding what to do after a syscall should be checking +if any of the lower byte bits are set and then checking if the reschedule +bit is set. + +Currently we are loading the top word, checking if any bits are set +(which never seems to be true) and thus jumping over loading the +whole long and checking if the reschedule bit is set. + +We get the thread info in two places so split that logic out in +a macro and then fix the code so that it loads the byte of the flags +we need to check, checks if anything is set and then checks if +the reschedule bit in particular is set. + +Reported-by: Christoph Plattner +Signed-off-by: Daniel Palmer +Signed-off-by: Greg Ungerer +Signed-off-by: Sasha Levin +--- + arch/m68k/68000/entry.S | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S +index 72e95663b62ff..c257cc415c478 100644 +--- a/arch/m68k/68000/entry.S ++++ b/arch/m68k/68000/entry.S +@@ -18,6 +18,13 @@ + + .text + ++/* get thread_info pointer into a2 */ ++ .macro getthreadinfo ++ movel %sp,%d1 ++ andl #-THREAD_SIZE,%d1 ++ movel %d1,%a2 ++ .endm ++ + .globl system_call + .globl resume + .globl ret_from_exception +@@ -70,9 +77,8 @@ ENTRY(system_call) + + movel %sp@(PT_OFF_ORIG_D0),%d0 + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ /* Doing a trace ? */ ++ getthreadinfo + btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) + jne do_trace + cmpl #NR_syscalls,%d0 +@@ -96,16 +102,15 @@ Luser_return: + /* heavy interrupt load*/ + andw #ALLOWINT,%sr + +- movel %sp,%d1 /* get thread_info pointer */ +- andl #-THREAD_SIZE,%d1 +- movel %d1,%a2 ++ getthreadinfo + 1: +- move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if any of the flags are set */ ++ moveb %a2@(TINFO_FLAGS + 3),%d1 /* thread_info->flags (low 8 bits) */ + jne Lwork_to_do + RESTORE_ALL + + Lwork_to_do: +- movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */ ++ /* check if reschedule needs to be called */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +-- +2.53.0 + diff --git a/queue-7.0/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch b/queue-7.0/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch new file mode 100644 index 0000000000..2f92860744 --- /dev/null +++ b/queue-7.0/mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch @@ -0,0 +1,43 @@ +From ed04630337660b64f889680b01028be54cc5c9ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 16:34:52 +0800 +Subject: mailbox: cix: Add IRQF_NO_SUSPEND to mailbox interrupt + +From: Dylan Wu + +[ Upstream commit 80784b427970219ebc338a6fb4118cde67a6c317 ] + +During the system suspend process, device interrupts are masked in the +noirq phase. However, SCMI often needs to exchange final messages with the +firmware to complete the power-down transition. Without the IRQF_NO_SUSPEND +flag, the mailbox ISR cannot run during this late stage, leading to SCMI +communication timeouts and error messages like "SCMI protocol wait for +resp timeout" during suspend. + +Add the IRQF_NO_SUSPEND flag to the interrupt request to ensure the mailbox +can continue to handle responses during the noirq stages of suspend and +resume, thereby ensuring a reliable power state transition. + +Signed-off-by: Dylan Wu +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/cix-mailbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c +index 443620e8ae37f..933820b12772d 100644 +--- a/drivers/mailbox/cix-mailbox.c ++++ b/drivers/mailbox/cix-mailbox.c +@@ -405,7 +405,7 @@ static int cix_mbox_startup(struct mbox_chan *chan) + int index = cp->index, ret; + u32 val; + +- ret = request_irq(priv->irq, cix_mbox_isr, 0, ++ ret = request_irq(priv->irq, cix_mbox_isr, IRQF_NO_SUSPEND, + dev_name(priv->dev), chan); + if (ret) { + dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); +-- +2.53.0 + diff --git a/queue-7.0/md-raid0-use-kvzalloc-kvfree-for-strip_zone-and-devl.patch b/queue-7.0/md-raid0-use-kvzalloc-kvfree-for-strip_zone-and-devl.patch new file mode 100644 index 0000000000..444dde6127 --- /dev/null +++ b/queue-7.0/md-raid0-use-kvzalloc-kvfree-for-strip_zone-and-devl.patch @@ -0,0 +1,84 @@ +From 8741e7b394a498016e33612bd70de260c843ebb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 19:42:02 -0400 +Subject: md/raid0: use kvzalloc/kvfree for strip_zone and devlist allocations + +From: Gregory Price + +[ Upstream commit 078d1d8e688d75419abfedcae47eab8e42b991bb ] + +syzbot reported a WARNING at mm/page_alloc.c:__alloc_frozen_pages_noprof() +triggered by create_strip_zones() in the RAID0 driver. + +When raid_disks is large, the allocation size exceeds MAX_PAGE_ORDER (4MB +on x86), causing WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER). + +Convert the strip_zone and devlist allocations from kzalloc/kzalloc_objs to +kvzalloc/kvzalloc_objs, which first attempts a contiguous allocation with +__GFP_NOWARN and then falls back to vmalloc for large sizes. Convert the +corresponding kfree calls to kvfree. + +Both arrays are pure metadata lookup tables (arrays of pointers and zone +descriptors) accessed only via indexing, so they do not require physically +contiguous memory. + +Reported-by: syzbot+924649752adf0d3ac9dd@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69adaba8.a00a0220.b130.0005.GAE@google.com/ +Signed-off-by: Gregory Price +Reviewed-by: Yu Kuai +Reviewed-by: Li Nan +Link: https://lore.kernel.org/linux-raid/20260308234202.3118119-1-gourry@gourry.net/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid0.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c +index ef0045db409fc..5e38a51e349ad 100644 +--- a/drivers/md/raid0.c ++++ b/drivers/md/raid0.c +@@ -143,13 +143,13 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) + } + + err = -ENOMEM; +- conf->strip_zone = kzalloc_objs(struct strip_zone, conf->nr_strip_zones); ++ conf->strip_zone = kvzalloc_objs(struct strip_zone, conf->nr_strip_zones); + if (!conf->strip_zone) + goto abort; +- conf->devlist = kzalloc(array3_size(sizeof(struct md_rdev *), +- conf->nr_strip_zones, +- mddev->raid_disks), +- GFP_KERNEL); ++ conf->devlist = kvzalloc(array3_size(sizeof(struct md_rdev *), ++ conf->nr_strip_zones, ++ mddev->raid_disks), ++ GFP_KERNEL); + if (!conf->devlist) + goto abort; + +@@ -291,8 +291,8 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) + + return 0; + abort: +- kfree(conf->strip_zone); +- kfree(conf->devlist); ++ kvfree(conf->strip_zone); ++ kvfree(conf->devlist); + kfree(conf); + *private_conf = ERR_PTR(err); + return err; +@@ -373,8 +373,8 @@ static void raid0_free(struct mddev *mddev, void *priv) + { + struct r0conf *conf = priv; + +- kfree(conf->strip_zone); +- kfree(conf->devlist); ++ kvfree(conf->strip_zone); ++ kvfree(conf->devlist); + kfree(conf); + } + +-- +2.53.0 + diff --git a/queue-7.0/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch b/queue-7.0/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch new file mode 100644 index 0000000000..931286f24b --- /dev/null +++ b/queue-7.0/md-raid5-fix-uaf-on-io-across-the-reshape-position.patch @@ -0,0 +1,144 @@ +From 745eb6ebb51a7281c092cc403017c505d85c8140 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 00:35:48 -0400 +Subject: md/raid5: Fix UAF on IO across the reshape position + +From: Benjamin Marzinski + +[ Upstream commit 418b3e64e4459feb3f75979de9ec89e085745343 ] + +If make_stripe_request() returns STRIPE_WAIT_RESHAPE, +raid5_make_request() will free the cloned bio. But raid5_make_request() +can call make_stripe_request() multiple times, writing to the various +stripes. If that bio got added to the toread or towrite lists of a +stripe disk in an earlier call to make_stripe_request(), then it's not +safe to just free the bio if a later part of it is found to cross the +reshape position. Doing so can lead to a UAF error, when bio_endio() +is called on the bio for the earlier stripes. + +Instead, raid5_make_request() needs to wait until all parts of the bio +have called bio_endio(). To do this, bios that cross the reshape +position while the reshape can't make progress are flagged as needing to +wait for all parts to complete. When raid5_make_request() has a bio that +failed make_stripe_request() with STRIPE_WAIT_RESHAPE, it sets +bi->bi_private to a completion struct and waits for completion after +ending the bio. When the bio_endio() is called for the last time on a +clone bio with bi->bi_private set, it wakes up the waiter. This +guarantees that raid5_make_request() doesn't return until the cloned bio +needing a retry for io across the reshape boundary is safely cleaned up. + +There is a simple reproducer available at [1]. Compile the kernel with +KASAN for more useful reporting when the error is triggered (this is not +necessary to see the bug). + +[1] https://gist.github.com/bmarzins/e48598824305cf2171289e47d7241fa5 + +Signed-off-by: Benjamin Marzinski +Reviewed-by: Xiao Ni +Link: https://lore.kernel.org/r/20260408043548.1695157-1-bmarzins@redhat.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 31 ++++++++----------------------- + drivers/md/md.h | 1 - + drivers/md/raid5.c | 7 ++++++- + 3 files changed, 14 insertions(+), 25 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 32927c24ebf7c..aa5b55f8b4e20 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -9395,9 +9395,11 @@ static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone) + + static void md_end_clone_io(struct bio *bio) + { +- struct md_io_clone *md_io_clone = bio->bi_private; ++ struct md_io_clone *md_io_clone = container_of(bio, struct md_io_clone, ++ bio_clone); + struct bio *orig_bio = md_io_clone->orig_bio; + struct mddev *mddev = md_io_clone->mddev; ++ struct completion *reshape_completion = bio->bi_private; + + if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) + md_bitmap_end(mddev, md_io_clone); +@@ -9409,7 +9411,10 @@ static void md_end_clone_io(struct bio *bio) + bio_end_io_acct(orig_bio, md_io_clone->start_time); + + bio_put(bio); +- bio_endio(orig_bio); ++ if (unlikely(reshape_completion)) ++ complete(reshape_completion); ++ else ++ bio_endio(orig_bio); + percpu_ref_put(&mddev->active_io); + } + +@@ -9434,7 +9439,7 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio) + } + + clone->bi_end_io = md_end_clone_io; +- clone->bi_private = md_io_clone; ++ clone->bi_private = NULL; + *bio = clone; + } + +@@ -9445,26 +9450,6 @@ void md_account_bio(struct mddev *mddev, struct bio **bio) + } + EXPORT_SYMBOL_GPL(md_account_bio); + +-void md_free_cloned_bio(struct bio *bio) +-{ +- struct md_io_clone *md_io_clone = bio->bi_private; +- struct bio *orig_bio = md_io_clone->orig_bio; +- struct mddev *mddev = md_io_clone->mddev; +- +- if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) +- md_bitmap_end(mddev, md_io_clone); +- +- if (bio->bi_status && !orig_bio->bi_status) +- orig_bio->bi_status = bio->bi_status; +- +- if (md_io_clone->start_time) +- bio_end_io_acct(orig_bio, md_io_clone->start_time); +- +- bio_put(bio); +- percpu_ref_put(&mddev->active_io); +-} +-EXPORT_SYMBOL_GPL(md_free_cloned_bio); +- + /* md_allow_write(mddev) + * Calling this ensures that the array is marked 'active' so that writes + * may proceed without blocking. It is important to call this before +diff --git a/drivers/md/md.h b/drivers/md/md.h +index 409c8f61695d3..d3f0ac39a2238 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -917,7 +917,6 @@ extern void md_finish_reshape(struct mddev *mddev); + void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev, + struct bio *bio, sector_t start, sector_t size); + void md_account_bio(struct mddev *mddev, struct bio **bio); +-void md_free_cloned_bio(struct bio *bio); + + extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); + void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev, +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 8feecd60a86c8..5e0ca832d4eb5 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -6219,7 +6219,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) + + mempool_free(ctx, conf->ctx_pool); + if (res == STRIPE_WAIT_RESHAPE) { +- md_free_cloned_bio(bi); ++ DECLARE_COMPLETION_ONSTACK(done); ++ WRITE_ONCE(bi->bi_private, &done); ++ ++ bio_endio(bi); ++ ++ wait_for_completion(&done); + return false; + } + +-- +2.53.0 + diff --git a/queue-7.0/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch b/queue-7.0/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch new file mode 100644 index 0000000000..989f27a0b8 --- /dev/null +++ b/queue-7.0/md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch @@ -0,0 +1,56 @@ +From ceb80d12f2b3402b13f2c6657b1f9219c510d59a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:33:51 +0800 +Subject: md/raid5: skip 2-failure compute when other disk is R5_LOCKED + +From: FengWei Shih + +[ Upstream commit 52e4324935be917f8f3267354b3cc06bb8ffcec1 ] + +When skip_copy is enabled on a doubly-degraded RAID6, a device that is +being written to will be in R5_LOCKED state with R5_UPTODATE cleared. +If a new read triggers fetch_block() while the write is still in +flight, the 2-failure compute path may select this locked device as a +compute target because it is not R5_UPTODATE. + +Because skip_copy makes the device page point directly to the bio page, +reconstructing data into it might be risky. Also, since the compute +marks the device R5_UPTODATE, it triggers WARN_ON in ops_run_io() +which checks that R5_SkipCopy and R5_UPTODATE are not both set. + +This can be reproduced by running small-range concurrent read/write on +a doubly-degraded RAID6 with skip_copy enabled, for example: + + mdadm -C /dev/md0 -l6 -n6 -R -f /dev/loop[0-3] missing missing + echo 1 > /sys/block/md0/md/skip_copy + fio --filename=/dev/md0 --rw=randrw --bs=4k --numjobs=8 \ + --iodepth=32 --size=4M --runtime=30 --time_based --direct=1 + +Fix by checking R5_LOCKED before proceeding with the compute. The +compute will be retried once the lock is cleared on IO completion. + +Signed-off-by: FengWei Shih +Reviewed-by: Yu Kuai +Link: https://lore.kernel.org/linux-raid/20260319053351.3676794-1-dannyshih@synology.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 335d2b6b10796..8feecd60a86c8 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -3916,6 +3916,8 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + break; + } + BUG_ON(other < 0); ++ if (test_bit(R5_LOCKED, &sh->dev[other].flags)) ++ return 0; + pr_debug("Computing stripe %llu blocks %d,%d\n", + (unsigned long long)sh->sector, + disk_idx, other); +-- +2.53.0 + diff --git a/queue-7.0/media-au0828-fix-green-screen-in-analog.patch b/queue-7.0/media-au0828-fix-green-screen-in-analog.patch new file mode 100644 index 0000000000..befc937380 --- /dev/null +++ b/queue-7.0/media-au0828-fix-green-screen-in-analog.patch @@ -0,0 +1,70 @@ +From 15b85b144038c447e8eb6135efc681fec3790a4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 16:07:20 -0500 +Subject: media: au0828: Fix green screen in analog + +From: Bradford Love + +[ Upstream commit 58119a0cffa8a597ce5d39587beb0f5a763434a0 ] + +When the driver was converted to VB2 the original function to fix +green frame detection was removed and a default vb2 dqbuf function +was used instead. This vb2 dqbuf function leads to green frames not +being detected and correupting stream captures. + +The vidioc_dqbuf function checks the greenscreen flag, and, if set +resets the stream to discard the green frame and decode a real frame. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/au0828/au0828-video.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c +index fbaa542c8259a..3c53105f3d2b3 100644 +--- a/drivers/media/usb/au0828/au0828-video.c ++++ b/drivers/media/usb/au0828/au0828-video.c +@@ -1671,6 +1671,27 @@ static int vidioc_log_status(struct file *file, void *fh) + return 0; + } + ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) ++{ ++ struct au0828_dev *dev = video_drvdata(file); ++ int rc; ++ ++ rc = check_dev(dev); ++ if (rc < 0) ++ return rc; ++ ++ /* Workaround for a bug in the au0828 hardware design that ++ * sometimes results in the colorspace being inverted ++ */ ++ if (dev->greenscreen_detected == 1) { ++ dprintk(1, "Detected green frame. Resetting stream...\n"); ++ au0828_analog_stream_reset(dev); ++ dev->greenscreen_detected = 0; ++ } ++ ++ return vb2_ioctl_dqbuf(file, priv, b); ++} ++ + void au0828_v4l2_suspend(struct au0828_dev *dev) + { + struct urb *urb; +@@ -1764,8 +1785,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, +- .vidioc_dqbuf = vb2_ioctl_dqbuf, +- .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, +-- +2.53.0 + diff --git a/queue-7.0/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch b/queue-7.0/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch new file mode 100644 index 0000000000..76d7d154a0 --- /dev/null +++ b/queue-7.0/media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch @@ -0,0 +1,48 @@ +From e6708f735c879fe44302a1aeb39d535e0ee60735 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:16:37 +0300 +Subject: media: ccs-pll: Fix pre-PLL divider calculation for + EXT_IP_PLL_DIVIDER flag + +From: Alexander Shiyan + +[ Upstream commit b7ef8bbb9fbd43d33ecb92e23aa7c5a55dab5513 ] + +When the CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER flag is set, odd pre-PLL divider +values are allowed. However, in the operational timing branch the +calculation of the minimum pre-PLL divider incorrectly uses clk_div_even_up, +forcing the minimum value to be even, even if the flag is set. This prevents +selecting a valid odd divider like 3, which may be required for certain +sensor configurations. + +Fix this by removing the forced even rounding from the minimum pre-PLL +divider calculation. The loop later uses the flag to determine the step, +so odd values will be considered when the flag is set. + +Signed-off-by: Alexander Shiyan +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ccs-pll.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c +index 4eb83636e1027..1605cfa5db19d 100644 +--- a/drivers/media/i2c/ccs-pll.c ++++ b/drivers/media/i2c/ccs-pll.c +@@ -824,9 +824,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(u16, op_lim_fr->min_pre_pll_clk_div, +- clk_div_even_up( +- DIV_ROUND_UP(pll->ext_clk_freq_hz, +- op_lim_fr->max_pll_ip_clk_freq_hz))); ++ DIV_ROUND_UP(pll->ext_clk_freq_hz, ++ op_lim_fr->max_pll_ip_clk_freq_hz)); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + +-- +2.53.0 + diff --git a/queue-7.0/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch b/queue-7.0/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch new file mode 100644 index 0000000000..afb5395116 --- /dev/null +++ b/queue-7.0/media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch @@ -0,0 +1,83 @@ +From 6a64320eafbe0d67446805c61b777950b941f4b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:23 -0500 +Subject: media: cx25840: Fix NTSC-J, PAL-N, and SECAM standards + +From: Bradford Love + +[ Upstream commit 36200241f5a3dd28b95fdefb2885ca9fd52f6387 ] + +Formats did not correctly decode prior. + +Modifications are based off cx25840 datasheet. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/cx25840/cx25840-core.c | 29 ++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c +index a863063043303..69d5cc648c0fc 100644 +--- a/drivers/media/i2c/cx25840/cx25840-core.c ++++ b/drivers/media/i2c/cx25840/cx25840-core.c +@@ -1652,10 +1652,14 @@ static int set_v4lstd(struct i2c_client *client) + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; ++ u8 pal_n = 0; ++ u8 ntsc_j = 0; ++ u8 tmp_reg = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; ++ ntsc_j = 0x80; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { +@@ -1663,6 +1667,7 @@ static int set_v4lstd(struct i2c_client *client) + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; ++ pal_n = 0x40; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { +@@ -1689,10 +1694,30 @@ static int set_v4lstd(struct i2c_client *client) + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ +- cx25840_and_or(client, 0x47b, ~6, 0); ++ cx25840_and_or(client, 0x47b, ~0x6, 0); ++ } else if (fmt == 0xc) { /* SECAM - Step 9c - toggle CKILLEN */ ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); + } ++ + cx25840_and_or(client, 0x400, ~0xf, fmt); +- cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ ++ if (fmt >= 4 && fmt < 8) { ++ tmp_reg = cx25840_read(client, 0x401); ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x00 : 0x40); /* CAGCEN */ ++ cx25840_and_or(client, 0x401, ~0x40, tmp_reg & 0x40 ? 0x40 : 0x00); ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x00 : 0x20); /* CKILLEN */ ++ cx25840_and_or(client, 0x401, ~0x20, tmp_reg & 0x20 ? 0x20 : 0x00); ++ } ++ ++ if (pal_m) ++ cx25840_and_or(client, 0x403, ~0x3, pal_m); ++ else if (pal_n) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x40, pal_n); ++ else if (ntsc_j) /* cx25840 datasheet table 3-19 */ ++ cx25840_and_or(client, 0x403, ~0x80, ntsc_j); ++ + if (is_cx23888(state)) + cx23888_std_setup(client); + else +-- +2.53.0 + diff --git a/queue-7.0/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch b/queue-7.0/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch new file mode 100644 index 0000000000..c631bcbf07 --- /dev/null +++ b/queue-7.0/media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch @@ -0,0 +1,111 @@ +From 9d6718f2c73604f5443c07c998d92385bebf19d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 16:50:24 +0100 +Subject: media: dw100: Fix kernel oops with PREEMPT_RT enabled + +From: Stefan Klug + +[ Upstream commit 557ec8cc29ade6c72ea768e59389db08cb7742c9 ] + +On kernels with PREEMPT_RT enabled, a "BUG: scheduling while atomic" +kernel oops occurs inside dw100_irq_handler -> vb2_buffer_done. This is +because vb2_buffer_done takes a spinlock which is not allowed within +interrupt context on PREEMPT_RT. + +The first attempt to fix this was to just drop the IRQF_ONESHOT so that +the interrupt is handled threaded on PREEMPT_RT systems. This introduced +a new issue. The dw100 has an internal timeout counter that is gated by +the DW100_BUS_CTRL_AXI_MASTER_ENABLE bit. Depending on the time it takes +for the threaded handler to run and the geometry of the data being +processed it is possible to reach the timeout resulting in +DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT being set and "dw100 +32e30000.dwe: Interrupt error: 0x1" errors in dmesg. + +To properly fix that, split the interrupt into two halves, reset the +DW100_BUS_CTRL_AXI_MASTER_ENABLE bit in the hard interrupt handler and +do the v4l2 buffer handling in the threaded half. The IRQF_ONESHOT can +still be dropped as the interrupt gets disabled in the hard handler and +will only be reenabled on the next dw100_device_run which will not be +called before the current job has finished. + +Signed-off-by: Stefan Klug +Reviewed-by: Xavier Roumegue +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260304-sklug-v6-16-topic-dw100-v3-1-dev-v5-3-1a7e1f721b50@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/nxp/dw100/dw100.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c +index bdebbe3f41985..bdf1fdf2e6cca 100644 +--- a/drivers/media/platform/nxp/dw100/dw100.c ++++ b/drivers/media/platform/nxp/dw100/dw100.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,7 @@ struct dw100_device { + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; ++ bool frame_failed; + }; + + struct dw100_q_data { +@@ -1386,7 +1388,8 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + { + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; +- bool with_error = true; ++ ++ dw_dev->frame_failed = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; +@@ -1394,7 +1397,7 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); +- with_error = false; ++ dw_dev->frame_failed = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } +@@ -1407,7 +1410,14 @@ static irqreturn_t dw100_irq_handler(int irq, void *dev_id) + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + +- dw100_job_finish(dw_dev, with_error); ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dw100_irq_thread_fn(int irq, void *dev_id) ++{ ++ struct dw100_device *dw_dev = dev_id; ++ ++ dw100_job_finish(dw_dev, dw_dev->frame_failed); + + return IRQ_HANDLED; + } +@@ -1555,8 +1565,9 @@ static int dw100_probe(struct platform_device *pdev) + + pm_runtime_put_sync(&pdev->dev); + +- ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, +- dev_name(&pdev->dev), dw_dev); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, dw100_irq_handler, ++ dw100_irq_thread_fn, 0, ++ dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_pm; +-- +2.53.0 + diff --git a/queue-7.0/media-em28xx-add-a-variety-of-dualhd-usb-id.patch b/queue-7.0/media-em28xx-add-a-variety-of-dualhd-usb-id.patch new file mode 100644 index 0000000000..5e28ccb770 --- /dev/null +++ b/queue-7.0/media-em28xx-add-a-variety-of-dualhd-usb-id.patch @@ -0,0 +1,49 @@ +From 26255b3fa26ce097cdd203c882f0b04f91ea6dc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:31 -0500 +Subject: media: em28xx: Add a variety of DualHD usb id + +From: Bradford Love + +[ Upstream commit 724e16b166534bd01d4f5bdf310310146bd4da56 ] + +Include possible vid:pid combination of DualHD models +that are in the wild. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 59a2e4db75b72..2d19f8ecd6857 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2757,10 +2757,22 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8269), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8278), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x026d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826e), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x826f), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8270), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, ++ { USB_DEVICE(0x2040, 0x8271), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x846d), + .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, + { USB_DEVICE(0x0438, 0xb002), +-- +2.53.0 + diff --git a/queue-7.0/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch b/queue-7.0/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch new file mode 100644 index 0000000000..e83b309292 --- /dev/null +++ b/queue-7.0/media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch @@ -0,0 +1,55 @@ +From 6ad3399d9fb8d28e71d5694a8bcb9093ca33c1ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:32 -0500 +Subject: media: em28xx: remove tuner type from Hauppauge DVB DualHD + +From: Bradford Love + +[ Upstream commit a5dcbff7d50a89bf0376e7f2fb1ba3163a6dac0a ] + +This reverts a patch which was perhaps inadvertently added. + +This was changed during the 5.15-rc4 merge. The faulty commit appears +lost in the pull request somehow, I cannot find it to check the +explanation. + +commit c52e7b855b33 ("Merge tag 'v5.15-rc4' into media_tree") + +There was nothing wrong with this device and no reason to moodify the +board profile. The DVB capabilities are added via dvb_module_probe. +Additionally, the device contains *zero* analog inputs, so I'm not +sure why one was added. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/usb/em28xx/em28xx-cards.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 2d19f8ecd6857..d7075ebabceb8 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2522,17 +2522,12 @@ const struct em28xx_board em28xx_boards[] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, +- .tuner_type = TUNER_SI2157, ++ .tuner_type = TUNER_ABSENT, + .tuner_gpio = hauppauge_dualhd_dvb, + .has_dvb = 1, + .has_dual_ts = 1, + .ir_codes = RC_MAP_HAUPPAUGE, + .leds = hauppauge_dualhd_leds, +- .input = { { +- .type = EM28XX_VMUX_COMPOSITE, +- .vmux = TVP5150_COMPOSITE1, +- .amux = EM28XX_AMUX_LINE_IN, +- } }, + }, + /* + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. +-- +2.53.0 + diff --git a/queue-7.0/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch b/queue-7.0/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch new file mode 100644 index 0000000000..abbd3a69c9 --- /dev/null +++ b/queue-7.0/media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch @@ -0,0 +1,47 @@ +From 47a281707db4292139443b99a6ef56f36f16f823 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:18:15 +0800 +Subject: media: i2c: ar0521: Check return value of devm_gpiod_get_optional() + in ar0521_probe() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chen Ni + +[ Upstream commit 46c2891cf12c767de031a248cbb1f96d203bd3f6 ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Acked-by: Krzysztof Hałasa +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/ar0521.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c +index f156058500e3d..ed324c2d87aa2 100644 +--- a/drivers/media/i2c/ar0521.c ++++ b/drivers/media/i2c/ar0521.c +@@ -1094,6 +1094,9 @@ static int ar0521_probe(struct i2c_client *client) + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(sensor->reset_gpio)) ++ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), ++ "failed to get reset gpio\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + +-- +2.53.0 + diff --git a/queue-7.0/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch b/queue-7.0/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch new file mode 100644 index 0000000000..3f42b21c7c --- /dev/null +++ b/queue-7.0/media-i2c-imx258-add-missing-mutex-protection-for-fo.patch @@ -0,0 +1,85 @@ +From 7987f140d39e7124904ca67b48b31c081e41a159 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 02:31:54 +0000 +Subject: media: i2c: imx258: add missing mutex protection for format code + access + +From: Ziyi Guo + +[ Upstream commit c3109ecc3bb76aab9ef65f2e795a97a764a0b4a3 ] + +imx258_open(), imx258_enum_mbus_code(), and imx258_enum_frame_size() +call imx258_get_format_code() without holding imx258->mutex. However, +imx258_get_format_code() has lockdep_assert_held(&imx258->mutex) +indicating that callers must hold this lock. + +All other callers of imx258_get_format_code() properly acquire the mutex: +- imx258_set_pad_format() acquires mutex at imx258.c:918 +- imx258_get_pad_format() acquires mutex at imx258.c:896 + +The mutex is needed to protect access to imx258->vflip->val and +imx258->hflip->val which are used to calculate the bayer format code. + +Add mutex_lock()/mutex_unlock() around the imx258_get_format_code() +calls in the affected functions to fix the missing lock protection. + +Signed-off-by: Ziyi Guo +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/imx258.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index e50dcfd830f52..bc9ee449a87c5 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -709,12 +709,16 @@ static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) + v4l2_subdev_state_get_format(fh->state, 0); + struct v4l2_rect *try_crop; + ++ mutex_lock(&imx258->mutex); ++ + /* Initialize try_fmt */ + try_fmt->width = supported_modes[0].width; + try_fmt->height = supported_modes[0].height; + try_fmt->code = imx258_get_format_code(imx258); + try_fmt->field = V4L2_FIELD_NONE; + ++ mutex_unlock(&imx258->mutex); ++ + /* Initialize try_crop */ + try_crop = v4l2_subdev_state_get_crop(fh->state, 0); + try_crop->left = IMX258_PIXEL_ARRAY_LEFT; +@@ -839,7 +843,9 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd, + if (code->index > 0) + return -EINVAL; + ++ mutex_lock(&imx258->mutex); + code->code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); + + return 0; + } +@@ -849,10 +855,16 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_size_enum *fse) + { + struct imx258 *imx258 = to_imx258(sd); ++ u32 code; ++ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + +- if (fse->code != imx258_get_format_code(imx258)) ++ mutex_lock(&imx258->mutex); ++ code = imx258_get_format_code(imx258); ++ mutex_unlock(&imx258->mutex); ++ ++ if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; +-- +2.53.0 + diff --git a/queue-7.0/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch b/queue-7.0/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch new file mode 100644 index 0000000000..e2222e0f2a --- /dev/null +++ b/queue-7.0/media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch @@ -0,0 +1,44 @@ +From 0fb2fd4ae33f043dfed16d07926e98a3b4dccc24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 10:43:12 +0800 +Subject: media: i2c: mt9p031: Check return value of devm_gpiod_get_optional() + in mt9p031_probe() + +From: Chen Ni + +[ Upstream commit c8e0585dce5df525308f0fba40b618df03aaf7fc ] + +The devm_gpiod_get_optional() function may return an error pointer +(ERR_PTR) in case of a genuine failure during GPIO acquisition, not just +NULL which indicates the legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the function call to catch such errors and +propagate them to the probe function, ensuring the driver fails to load +safely rather than proceeding with an invalid pointer. + +Signed-off-by: Chen Ni +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/mt9p031.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c +index 1500ee4db47ec..ea5d43d925ffa 100644 +--- a/drivers/media/i2c/mt9p031.c ++++ b/drivers/media/i2c/mt9p031.c +@@ -1183,6 +1183,10 @@ static int mt9p031_probe(struct i2c_client *client) + + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ++ if (IS_ERR(mt9p031->reset)) { ++ ret = PTR_ERR(mt9p031->reset); ++ goto done; ++ } + + ret = mt9p031_clk_setup(mt9p031); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/media-ipu-bridge-add-ov5675-sensor-config.patch b/queue-7.0/media-ipu-bridge-add-ov5675-sensor-config.patch new file mode 100644 index 0000000000..554b6051c8 --- /dev/null +++ b/queue-7.0/media-ipu-bridge-add-ov5675-sensor-config.patch @@ -0,0 +1,42 @@ +From 874e8344cafe3650ab786471e27780204c91624e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 10:45:45 +0100 +Subject: media: ipu-bridge: Add OV5675 sensor config + +From: Leif Skunberg + +[ Upstream commit d6576b85d3fe75238e67d3e311222e7f69730b09 ] + +Add the Omnivision OV5675 (ACPI HID OVTI5675) to the +ipu_supported_sensors[] table with a link frequency of 450 MHz. + +This sensor is found in the Lenovo ThinkPad X1 Fold 16 Gen 1 behind +an Intel Vision Sensing Controller (IVSC). Without this entry the IPU +bridge does not create the software-node fwnode graph for the sensor, +preventing the camera from being enumerated. + +Signed-off-by: Leif Skunberg +Reviewed-by: Hans de Goede +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/pci/intel/ipu-bridge.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c +index 3028293eeb752..fc6608e33de40 100644 +--- a/drivers/media/pci/intel/ipu-bridge.c ++++ b/drivers/media/pci/intel/ipu-bridge.c +@@ -91,6 +91,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { + IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), + /* Omnivision OV2680 */ + IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), ++ /* Omnivision OV5675 */ ++ IPU_SENSOR_CONFIG("OVTI5675", 1, 450000000), + /* Omnivision OV8856 */ + IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), + /* Sony IMX471 */ +-- +2.53.0 + diff --git a/queue-7.0/media-pulse8-cec-handle-partial-deinit.patch b/queue-7.0/media-pulse8-cec-handle-partial-deinit.patch new file mode 100644 index 0000000000..651e08e842 --- /dev/null +++ b/queue-7.0/media-pulse8-cec-handle-partial-deinit.patch @@ -0,0 +1,57 @@ +From 77f78429fb923be8a23db5ef7a5f6796f108f73c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:50:34 -0700 +Subject: media: pulse8-cec: Handle partial deinit + +From: Vicki Pfau + +[ Upstream commit 323f52e02be68889c8630c4a0415ef5b78f9dc63 ] + +In the event that the cec dev node is held open while the adapter is +disconnected the serio device will be cleaned up but the cec device won't +be. As the serio device is freed but the ping_eeprom_work is not canceled, +the next ping will still attempt to send, leading to a kernel oops. + +This patch both cancels the ping_eeprom_work in the serio cleanup as well +as checking to make sure the serio is still present before attempting to +write to it. Note that while the added serio = NULL line looks similar to +one that was removed in commit 024e01dead12c ("media: pulse8-cec: fix +duplicate free at disconnect or probe error"), it notably happens before +calling cec_unregister_adapter, and as such shouldn't lead to the +user-after-free that removing it fixed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/cec/usb/pulse8/pulse8-cec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c +index 0df3af152762c..fa5df10627539 100644 +--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c ++++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c +@@ -235,6 +235,9 @@ static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + { + int err; + ++ if (!pulse8->serio) ++ return -ENODEV; ++ + if (debug > 1) + dev_info(pulse8->dev, "transmit %s: %*ph\n", + pulse8_msgname(cmd[0]), cmd_len, cmd); +@@ -655,6 +658,10 @@ static void pulse8_disconnect(struct serio *serio) + { + struct pulse8 *pulse8 = serio_get_drvdata(serio); + ++ cancel_delayed_work_sync(&pulse8->ping_eeprom_work); ++ mutex_lock(&pulse8->lock); ++ pulse8->serio = NULL; ++ mutex_unlock(&pulse8->lock); + cec_unregister_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); + serio_close(serio); +-- +2.53.0 + diff --git a/queue-7.0/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch b/queue-7.0/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch new file mode 100644 index 0000000000..e68b0c318b --- /dev/null +++ b/queue-7.0/media-rc-fix-race-between-unregister-and-urb-irq-cal.patch @@ -0,0 +1,758 @@ +From 924c59740c14cc9afd08c8008566096b3fa4745c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Dec 2025 10:33:26 +0000 +Subject: media: rc: fix race between unregister and urb/irq callbacks + +From: Sean Young + +[ Upstream commit dccc0c3ddf8f16071736f98a7d6dd46a2d43e037 ] + +Some rc device drivers have a race condition between rc_unregister_device() +and irq or urb callbacks. This is because rc_unregister_device() does two +things, it marks the device as unregistered so no new commands can be +issued and then it calls rc_free_device(). This means the driver has no +chance to cancel any pending urb callbacks or interrupts after the device +has been marked as unregistered. Those callbacks may access struct rc_dev +or its members (e.g. struct ir_raw_event_ctrl), which have been freed by +rc_free_device(). + +This change removes the implicit call to rc_free_device() from +rc_unregister_device(). This means that device drivers can call +rc_unregister_device() in their remove or disconnect function, then cancel +all the urbs and interrupts before explicitly calling rc_free_device(). + +Note this is an alternative fix for an issue found by Haotian Zhang, see +the Closes: tags. + +Reported-by: Haotian Zhang +Closes: https://lore.kernel.org/linux-media/20251114101432.2566-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114101418.2548-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114101346.2530-1-vulab@iscas.ac.cn/ +Closes: https://lore.kernel.org/linux-media/20251114090605.2413-1-vulab@iscas.ac.cn/ +Reviewed-by: Patrice Chotard +Signed-off-by: Sean Young +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/sil-sii8620.c | 1 + + drivers/hid/hid-picolcd_cir.c | 1 + + drivers/media/cec/core/cec-core.c | 2 +- + drivers/media/common/siano/smsir.c | 1 + + drivers/media/i2c/ir-kbd-i2c.c | 2 ++ + drivers/media/pci/bt8xx/bttv-input.c | 3 ++- + drivers/media/pci/cx23885/cx23885-input.c | 1 + + drivers/media/pci/cx88/cx88-input.c | 3 ++- + drivers/media/pci/dm1105/dm1105.c | 1 + + drivers/media/pci/mantis/mantis_input.c | 1 + + drivers/media/pci/saa7134/saa7134-input.c | 1 + + drivers/media/pci/smipcie/smipcie-ir.c | 1 + + drivers/media/pci/ttpci/budget-ci.c | 1 + + drivers/media/rc/ati_remote.c | 6 +++--- + drivers/media/rc/ene_ir.c | 2 +- + drivers/media/rc/fintek-cir.c | 3 ++- + drivers/media/rc/igorplugusb.c | 1 + + drivers/media/rc/iguanair.c | 1 + + drivers/media/rc/img-ir/img-ir-hw.c | 3 ++- + drivers/media/rc/img-ir/img-ir-raw.c | 3 ++- + drivers/media/rc/imon.c | 3 ++- + drivers/media/rc/ir-hix5hd2.c | 2 +- + drivers/media/rc/ir_toy.c | 1 + + drivers/media/rc/ite-cir.c | 2 +- + drivers/media/rc/mceusb.c | 1 + + drivers/media/rc/rc-ir-raw.c | 5 ----- + drivers/media/rc/rc-loopback.c | 1 + + drivers/media/rc/rc-main.c | 6 +----- + drivers/media/rc/redrat3.c | 4 +++- + drivers/media/rc/st_rc.c | 2 +- + drivers/media/rc/streamzap.c | 7 ++++--- + drivers/media/rc/sunxi-cir.c | 1 + + drivers/media/rc/ttusbir.c | 2 +- + drivers/media/rc/winbond-cir.c | 2 +- + drivers/media/rc/xbox_remote.c | 5 +++-- + drivers/media/usb/au0828/au0828-input.c | 1 + + drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 1 + + drivers/media/usb/dvb-usb/dvb-usb-remote.c | 6 ++++-- + drivers/media/usb/em28xx/em28xx-input.c | 1 + + drivers/staging/media/av7110/av7110_ir.c | 1 + + include/media/rc-core.h | 2 -- + 41 files changed, 58 insertions(+), 36 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c +index d3f238b1f2a94..982306eb4f0a7 100644 +--- a/drivers/gpu/drm/bridge/sil-sii8620.c ++++ b/drivers/gpu/drm/bridge/sil-sii8620.c +@@ -2221,6 +2221,7 @@ static void sii8620_detach(struct drm_bridge *bridge) + return; + + rc_unregister_device(ctx->rc_dev); ++ rc_free_device(ctx->rc_dev); + } + + static int sii8620_is_packing_required(struct sii8620 *ctx, +diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c +index d6faa0e00f95a..6d4c636e1c9f7 100644 +--- a/drivers/hid/hid-picolcd_cir.c ++++ b/drivers/hid/hid-picolcd_cir.c +@@ -134,5 +134,6 @@ void picolcd_exit_cir(struct picolcd_data *data) + + data->rc_dev = NULL; + rc_unregister_device(rdev); ++ rc_free_device(rdev); + } + +diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c +index 1953ce559ecaf..0fcd3b5e60c8d 100644 +--- a/drivers/media/cec/core/cec-core.c ++++ b/drivers/media/cec/core/cec-core.c +@@ -338,8 +338,8 @@ int cec_register_adapter(struct cec_adapter *adap, + res = cec_devnode_register(&adap->devnode, adap->owner); + if (res) { + #ifdef CONFIG_MEDIA_CEC_RC +- /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); ++ rc_free_device(adap->rc); + adap->rc = NULL; + #endif + return res; +diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c +index af07fed21ae12..283770d583d56 100644 +--- a/drivers/media/common/siano/smsir.c ++++ b/drivers/media/common/siano/smsir.c +@@ -92,6 +92,7 @@ int sms_ir_init(struct smscore_device_t *coredev) + void sms_ir_exit(struct smscore_device_t *coredev) + { + rc_unregister_device(coredev->ir.dev); ++ rc_free_device(coredev->ir.dev); + + pr_debug("\n"); + } +diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c +index 5588cdd7ec20d..6047453170043 100644 +--- a/drivers/media/i2c/ir-kbd-i2c.c ++++ b/drivers/media/i2c/ir-kbd-i2c.c +@@ -355,6 +355,7 @@ static void ir_work(struct work_struct *work) + mutex_unlock(&ir->lock); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + ir->rc = NULL; + return; + } +@@ -972,6 +973,7 @@ static void ir_remove(struct i2c_client *client) + i2c_unregister_device(ir->tx_c); + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + } + + static const struct i2c_device_id ir_kbd_id[] = { +diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c +index 373b6c6817d76..f704476506e07 100644 +--- a/drivers/media/pci/bt8xx/bttv-input.c ++++ b/drivers/media/pci/bt8xx/bttv-input.c +@@ -572,8 +572,9 @@ void bttv_input_fini(struct bttv *btv) + if (btv->remote == NULL) + return; + +- bttv_ir_stop(btv); + rc_unregister_device(btv->remote->dev); ++ bttv_ir_stop(btv); ++ rc_free_device(btv->remote->dev); + kfree(btv->remote); + btv->remote = NULL; + } +diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c +index ffbbeca8a8e5f..554767b8ef2bf 100644 +--- a/drivers/media/pci/cx23885/cx23885-input.c ++++ b/drivers/media/pci/cx23885/cx23885-input.c +@@ -402,6 +402,7 @@ void cx23885_input_fini(struct cx23885_dev *dev) + if (dev->kernel_ir == NULL) + return; + rc_unregister_device(dev->kernel_ir->rc); ++ rc_free_device(dev->kernel_ir->rc); + kfree(dev->kernel_ir->phys); + kfree(dev->kernel_ir->name); + kfree(dev->kernel_ir); +diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c +index e958eecb29c5c..5d9ce4f9af011 100644 +--- a/drivers/media/pci/cx88/cx88-input.c ++++ b/drivers/media/pci/cx88/cx88-input.c +@@ -509,8 +509,9 @@ int cx88_ir_fini(struct cx88_core *core) + if (!ir) + return 0; + +- cx88_ir_stop(core); + rc_unregister_device(ir->dev); ++ cx88_ir_stop(core); ++ rc_free_device(ir->dev); + kfree(ir); + + /* done */ +diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c +index de05d8b0f9dc5..bbd24769ae56b 100644 +--- a/drivers/media/pci/dm1105/dm1105.c ++++ b/drivers/media/pci/dm1105/dm1105.c +@@ -763,6 +763,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105) + static void dm1105_ir_exit(struct dm1105_dev *dm1105) + { + rc_unregister_device(dm1105->ir.dev); ++ rc_free_device(dm1105->ir.dev); + } + + static int dm1105_hw_init(struct dm1105_dev *dev) +diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c +index 34c0d979240fd..edb4cacf55d22 100644 +--- a/drivers/media/pci/mantis/mantis_input.c ++++ b/drivers/media/pci/mantis/mantis_input.c +@@ -72,5 +72,6 @@ EXPORT_SYMBOL_GPL(mantis_input_init); + void mantis_input_exit(struct mantis_pci *mantis) + { + rc_unregister_device(mantis->rc); ++ rc_free_device(mantis->rc); + } + EXPORT_SYMBOL_GPL(mantis_input_exit); +diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c +index 5b71014157808..7f6680de31564 100644 +--- a/drivers/media/pci/saa7134/saa7134-input.c ++++ b/drivers/media/pci/saa7134/saa7134-input.c +@@ -834,6 +834,7 @@ void saa7134_input_fini(struct saa7134_dev *dev) + return; + + rc_unregister_device(dev->remote->dev); ++ rc_free_device(dev->remote->dev); + kfree(dev->remote); + dev->remote = NULL; + } +diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c +index c0604d9c70119..0bbe4fa2d5a84 100644 +--- a/drivers/media/pci/smipcie/smipcie-ir.c ++++ b/drivers/media/pci/smipcie/smipcie-ir.c +@@ -181,5 +181,6 @@ void smi_ir_exit(struct smi_dev *dev) + + rc_unregister_device(rc_dev); + smi_ir_stop(ir); ++ rc_free_device(rc_dev); + ir->rc_dev = NULL; + } +diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c +index 3709c0fb23b07..8b496b959d7ea 100644 +--- a/drivers/media/pci/ttpci/budget-ci.c ++++ b/drivers/media/pci/ttpci/budget-ci.c +@@ -249,6 +249,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) + cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work); + + rc_unregister_device(budget_ci->ir.dev); ++ rc_free_device(budget_ci->ir.dev); + } + + static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c +index 78abe810a88e7..51d85de24fae3 100644 +--- a/drivers/media/rc/ati_remote.c ++++ b/drivers/media/rc/ati_remote.c +@@ -921,7 +921,6 @@ static int ati_remote_probe(struct usb_interface *interface, + input_free_device(input_dev); + exit_unregister_device: + rc_unregister_device(rc_dev); +- rc_dev = NULL; + exit_kill_urbs: + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); +@@ -941,18 +940,19 @@ static void ati_remote_disconnect(struct usb_interface *interface) + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); +- usb_set_intfdata(interface, NULL); + if (!ati_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + ++ rc_unregister_device(ati_remote->rdev); ++ usb_set_intfdata(interface, NULL); + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + if (ati_remote->idev) + input_unregister_device(ati_remote->idev); +- rc_unregister_device(ati_remote->rdev); + ati_remote_free_buffers(ati_remote); ++ rc_free_device(ati_remote->rdev); + kfree(ati_remote); + } + +diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c +index f8120605501ab..6f7dccc965e7f 100644 +--- a/drivers/media/rc/ene_ir.c ++++ b/drivers/media/rc/ene_ir.c +@@ -1090,7 +1090,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) + release_region(dev->hw_io, ENE_IO_SIZE); + exit_unregister_device: + rc_unregister_device(rdev); +- rdev = NULL; + exit_free_dev_rdev: + rc_free_device(rdev); + kfree(dev); +@@ -1110,6 +1109,7 @@ static void ene_remove(struct pnp_dev *pnp_dev) + ene_rx_restore_hw_buffer(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + ++ rc_free_device(dev->rdev); + free_irq(dev->irq, dev); + release_region(dev->hw_io, ENE_IO_SIZE); + kfree(dev); +diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c +index f7cfa8a073ebc..5055dfc3f4651 100644 +--- a/drivers/media/rc/fintek-cir.c ++++ b/drivers/media/rc/fintek-cir.c +@@ -568,6 +568,7 @@ static void fintek_remove(struct pnp_dev *pdev) + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + unsigned long flags; + ++ rc_unregister_device(fintek->rdev); + spin_lock_irqsave(&fintek->fintek_lock, flags); + /* disable CIR */ + fintek_disable_cir(fintek); +@@ -580,7 +581,7 @@ static void fintek_remove(struct pnp_dev *pdev) + free_irq(fintek->cir_irq, fintek); + release_region(fintek->cir_addr, fintek->cir_port_len); + +- rc_unregister_device(fintek->rdev); ++ rc_free_device(fintek->rdev); + + kfree(fintek); + } +diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c +index 6938d9a90c58a..3e10f6fe89f83 100644 +--- a/drivers/media/rc/igorplugusb.c ++++ b/drivers/media/rc/igorplugusb.c +@@ -247,6 +247,7 @@ static void igorplugusb_disconnect(struct usb_interface *intf) + usb_set_intfdata(intf, NULL); + usb_unpoison_urb(ir->urb); + usb_free_urb(ir->urb); ++ rc_free_device(ir->rc); + kfree(ir->buf_in); + kfree(ir->request); + } +diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c +index c508f2536243e..0c5b8befb0af3 100644 +--- a/drivers/media/rc/iguanair.c ++++ b/drivers/media/rc/iguanair.c +@@ -500,6 +500,7 @@ static void iguanair_disconnect(struct usb_interface *intf) + usb_set_intfdata(intf, NULL); + usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); ++ rc_free_device(ir->rc); + usb_free_urb(ir->urb_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); +diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c +index 63f6f5b36838d..f30adf4d8444d 100644 +--- a/drivers/media/rc/img-ir/img-ir-hw.c ++++ b/drivers/media/rc/img-ir/img-ir-hw.c +@@ -1118,9 +1118,10 @@ void img_ir_remove_hw(struct img_ir_priv *priv) + struct rc_dev *rdev = hw->rdev; + if (!rdev) + return; ++ rc_unregister_device(rdev); + img_ir_set_decoder(priv, NULL, 0); + hw->rdev = NULL; +- rc_unregister_device(rdev); ++ rc_free_device(rdev); + #ifdef CONFIG_COMMON_CLK + if (!IS_ERR(priv->clk)) + clk_notifier_unregister(priv->clk, &hw->clk_nb); +diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c +index 92fb7b555a0f6..f1460d4acf3e8 100644 +--- a/drivers/media/rc/img-ir/img-ir-raw.c ++++ b/drivers/media/rc/img-ir/img-ir-raw.c +@@ -136,6 +136,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv) + if (!rdev) + return; + ++ rc_unregister_device(rdev); + /* switch off and disable raw (edge) interrupts */ + spin_lock_irq(&priv->lock); + raw->rdev = NULL; +@@ -145,7 +146,7 @@ void img_ir_remove_raw(struct img_ir_priv *priv) + img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE); + spin_unlock_irq(&priv->lock); + +- rc_unregister_device(rdev); ++ rc_free_device(rdev); + + timer_delete_sync(&raw->timer); + } +diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c +index 7e92161105d53..310c9fc9ae91c 100644 +--- a/drivers/media/rc/imon.c ++++ b/drivers/media/rc/imon.c +@@ -2541,9 +2541,10 @@ static void imon_disconnect(struct usb_interface *interface) + + if (ifnum == 0) { + ictx->dev_present_intf0 = false; ++ rc_unregister_device(ictx->rdev); + usb_kill_urb(ictx->rx_urb_intf0); + input_unregister_device(ictx->idev); +- rc_unregister_device(ictx->rdev); ++ rc_free_device(ictx->rdev); + if (ictx->display_supported) { + if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) + usb_deregister_dev(interface, &imon_lcd_class); +diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c +index edc46828509c8..1b061e4a3dcfa 100644 +--- a/drivers/media/rc/ir-hix5hd2.c ++++ b/drivers/media/rc/ir-hix5hd2.c +@@ -331,7 +331,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) + + regerr: + rc_unregister_device(rdev); +- rdev = NULL; + clkerr: + clk_disable_unprepare(priv->clock); + err: +@@ -346,6 +345,7 @@ static void hix5hd2_ir_remove(struct platform_device *pdev) + + clk_disable_unprepare(priv->clock); + rc_unregister_device(priv->rdev); ++ rc_free_device(priv->rdev); + } + + #ifdef CONFIG_PM_SLEEP +diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c +index d6472de5da87d..089833e411786 100644 +--- a/drivers/media/rc/ir_toy.c ++++ b/drivers/media/rc/ir_toy.c +@@ -536,6 +536,7 @@ static void irtoy_disconnect(struct usb_interface *intf) + usb_free_urb(ir->urb_out); + usb_kill_urb(ir->urb_in); + usb_free_urb(ir->urb_in); ++ rc_free_device(ir->rc); + kfree(ir->in); + kfree(ir->out); + kfree(ir); +diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c +index bf544517c67a9..bde2a70512310 100644 +--- a/drivers/media/rc/ite-cir.c ++++ b/drivers/media/rc/ite-cir.c +@@ -1414,7 +1414,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id + release_region(itdev->cir_addr, itdev->params->io_region_size); + exit_unregister_device: + rc_unregister_device(rdev); +- rdev = NULL; + exit_free_dev_rdev: + rc_free_device(rdev); + kfree(itdev); +@@ -1439,6 +1438,7 @@ static void ite_remove(struct pnp_dev *pdev) + release_region(dev->cir_addr, dev->params->io_region_size); + + rc_unregister_device(dev->rdev); ++ rc_free_device(dev->rdev); + + kfree(dev); + } +diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c +index ed55e9ec3c570..06222eee17540 100644 +--- a/drivers/media/rc/mceusb.c ++++ b/drivers/media/rc/mceusb.c +@@ -1850,6 +1850,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf) + usb_free_urb(ir->urb_in); + usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + usb_put_dev(dev); ++ rc_free_device(ir->rc); + + kfree(ir); + } +diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c +index 2e269ef5e26be..ba24c2f22d39f 100644 +--- a/drivers/media/rc/rc-ir-raw.c ++++ b/drivers/media/rc/rc-ir-raw.c +@@ -648,9 +648,6 @@ int ir_raw_event_register(struct rc_dev *dev) + + void ir_raw_event_free(struct rc_dev *dev) + { +- if (!dev) +- return; +- + kfree(dev->raw); + dev->raw = NULL; + } +@@ -674,8 +671,6 @@ void ir_raw_event_unregister(struct rc_dev *dev) + + lirc_bpf_free(dev); + +- ir_raw_event_free(dev); +- + /* + * A user can be calling bpf(BPF_PROG_{QUERY|ATTACH|DETACH}), so + * ensure that the raw member is null on unlock; this is how +diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c +index 78ac09b3cbd34..53d0540717b36 100644 +--- a/drivers/media/rc/rc-loopback.c ++++ b/drivers/media/rc/rc-loopback.c +@@ -263,6 +263,7 @@ static int __init loop_init(void) + static void __exit loop_exit(void) + { + rc_unregister_device(loopdev.dev); ++ rc_free_device(loopdev.dev); + } + + module_init(loop_init); +diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c +index 821607504008a..dda3479ea3add 100644 +--- a/drivers/media/rc/rc-main.c ++++ b/drivers/media/rc/rc-main.c +@@ -1611,6 +1611,7 @@ static void rc_dev_release(struct device *device) + { + struct rc_dev *dev = to_rc_dev(device); + ++ ir_raw_event_free(dev); + kfree(dev); + } + +@@ -1773,7 +1774,6 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev, + } + + rc->dev.parent = dev; +- rc->managed_alloc = true; + *dr = rc; + devres_add(dev, dr); + +@@ -2042,11 +2042,7 @@ void rc_unregister_device(struct rc_dev *dev) + device_del(&dev->dev); + + ida_free(&rc_ida, dev->minor); +- +- if (!dev->managed_alloc) +- rc_free_device(dev); + } +- + EXPORT_SYMBOL_GPL(rc_unregister_device); + + /* +diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c +index 3b917a2a89188..3f828a564e192 100644 +--- a/drivers/media/rc/redrat3.c ++++ b/drivers/media/rc/redrat3.c +@@ -1131,11 +1131,13 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) + { + struct usb_device *udev = interface_to_usbdev(intf); + struct redrat3_dev *rr3 = usb_get_intfdata(intf); ++ struct rc_dev *rc = rr3->rc; + + usb_set_intfdata(intf, NULL); +- rc_unregister_device(rr3->rc); ++ rc_unregister_device(rc); + led_classdev_unregister(&rr3->led); + redrat3_delete(rr3, udev); ++ rc_free_device(rc); + } + + static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) +diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c +index 6b70bac5f45d6..0ba06bfc9e14b 100644 +--- a/drivers/media/rc/st_rc.c ++++ b/drivers/media/rc/st_rc.c +@@ -203,6 +203,7 @@ static void st_rc_remove(struct platform_device *pdev) + device_init_wakeup(&pdev->dev, false); + clk_disable_unprepare(rc_dev->sys_clock); + rc_unregister_device(rc_dev->rdev); ++ rc_free_device(rc_dev->rdev); + } + + static int st_rc_open(struct rc_dev *rdev) +@@ -334,7 +335,6 @@ static int st_rc_probe(struct platform_device *pdev) + return ret; + rcerr: + rc_unregister_device(rdev); +- rdev = NULL; + clkerr: + clk_disable_unprepare(rc_dev->sys_clock); + err: +diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c +index 6587c64a9d93a..307985d74fe8a 100644 +--- a/drivers/media/rc/streamzap.c ++++ b/drivers/media/rc/streamzap.c +@@ -392,15 +392,16 @@ static void streamzap_disconnect(struct usb_interface *interface) + struct streamzap_ir *sz = usb_get_intfdata(interface); + struct usb_device *usbdev = interface_to_usbdev(interface); + +- usb_set_intfdata(interface, NULL); +- + if (!sz) + return; + +- usb_kill_urb(sz->urb_in); + rc_unregister_device(sz->rdev); ++ usb_set_intfdata(interface, NULL); ++ ++ usb_kill_urb(sz->urb_in); + usb_free_urb(sz->urb_in); + usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ rc_free_device(sz->rdev); + + kfree(sz); + } +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 92ef4e7c6f69f..cb4c56bf0752a 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -371,6 +371,7 @@ static void sunxi_ir_remove(struct platform_device *pdev) + struct sunxi_ir *ir = platform_get_drvdata(pdev); + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + sunxi_ir_hw_exit(&pdev->dev); + } + +diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c +index 110a469001146..a2a64a860264b 100644 +--- a/drivers/media/rc/ttusbir.c ++++ b/drivers/media/rc/ttusbir.c +@@ -333,7 +333,6 @@ static int ttusbir_probe(struct usb_interface *intf, + return 0; + out3: + rc_unregister_device(rc); +- rc = NULL; + out2: + led_classdev_unregister(&tt->led); + out: +@@ -373,6 +372,7 @@ static void ttusbir_disconnect(struct usb_interface *intf) + } + usb_kill_urb(tt->bulk_urb); + usb_free_urb(tt->bulk_urb); ++ rc_free_device(tt->rc); + usb_set_intfdata(intf, NULL); + kfree(tt); + } +diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c +index 515469dd82d4c..8e804661a6215 100644 +--- a/drivers/media/rc/winbond-cir.c ++++ b/drivers/media/rc/winbond-cir.c +@@ -1132,7 +1132,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) + release_region(data->wbase, WAKEUP_IOMEM_LEN); + exit_unregister_device: + rc_unregister_device(data->dev); +- data->dev = NULL; + exit_free_rc: + rc_free_device(data->dev); + exit_unregister_led: +@@ -1163,6 +1162,7 @@ wbcir_remove(struct pnp_dev *device) + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); + + rc_unregister_device(data->dev); ++ rc_free_device(data->dev); + + led_classdev_unregister(&data->led); + +diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c +index e2ed2e2c2723e..d2cb88b8f1ca8 100644 +--- a/drivers/media/rc/xbox_remote.c ++++ b/drivers/media/rc/xbox_remote.c +@@ -283,14 +283,15 @@ static void xbox_remote_disconnect(struct usb_interface *interface) + struct xbox_remote *xbox_remote; + + xbox_remote = usb_get_intfdata(interface); +- usb_set_intfdata(interface, NULL); + if (!xbox_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + +- usb_kill_urb(xbox_remote->irq_urb); + rc_unregister_device(xbox_remote->rdev); ++ usb_set_intfdata(interface, NULL); ++ usb_kill_urb(xbox_remote->irq_urb); ++ rc_free_device(xbox_remote->rdev); + usb_free_urb(xbox_remote->irq_urb); + kfree(xbox_remote->inbuf); + kfree(xbox_remote); +diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c +index 7dec1a360da6a..81d0165a3064d 100644 +--- a/drivers/media/usb/au0828/au0828-input.c ++++ b/drivers/media/usb/au0828/au0828-input.c +@@ -357,6 +357,7 @@ void au0828_rc_unregister(struct au0828_dev *dev) + return; + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + + /* done */ + kfree(ir); +diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +index 600cff8a4abdc..bd86d250433df 100644 +--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c ++++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +@@ -187,6 +187,7 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) + if (d->rc_dev) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); ++ rc_free_device(d->rc_dev); + d->rc_dev = NULL; + } + +diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c +index 65e2c9e2cdc99..6dc11718dfb98 100644 +--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c ++++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c +@@ -347,10 +347,12 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) + { + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); +- if (d->props.rc.mode == DVB_RC_LEGACY) ++ if (d->props.rc.mode == DVB_RC_LEGACY) { + input_unregister_device(d->input_dev); +- else ++ } else { + rc_unregister_device(d->rc_dev); ++ rc_free_device(d->rc_dev); ++ } + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c +index 20fdd59b55185..ab61d9a29b10e 100644 +--- a/drivers/media/usb/em28xx/em28xx-input.c ++++ b/drivers/media/usb/em28xx/em28xx-input.c +@@ -853,6 +853,7 @@ static int em28xx_ir_fini(struct em28xx *dev) + goto ref_put; + + rc_unregister_device(ir->rc); ++ rc_free_device(ir->rc); + + kfree(ir->i2c_client); + +diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c +index 68b3979ba5f20..fdae467fd7ab8 100644 +--- a/drivers/staging/media/av7110/av7110_ir.c ++++ b/drivers/staging/media/av7110/av7110_ir.c +@@ -151,6 +151,7 @@ int av7110_ir_init(struct av7110 *av7110) + void av7110_ir_exit(struct av7110 *av7110) + { + rc_unregister_device(av7110->ir.rcdev); ++ rc_free_device(av7110->ir.rcdev); + } + + //MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); +diff --git a/include/media/rc-core.h b/include/media/rc-core.h +index 35c7a0546f02e..7c964b5ad7926 100644 +--- a/include/media/rc-core.h ++++ b/include/media/rc-core.h +@@ -81,7 +81,6 @@ struct lirc_fh { + /** + * struct rc_dev - represents a remote control device + * @dev: driver model's view of this device +- * @managed_alloc: devm_rc_allocate_device was used to create rc_dev + * @registered: set to true by rc_register_device(), false by + * rc_unregister_device + * @idle: used to keep track of RX state +@@ -156,7 +155,6 @@ struct lirc_fh { + */ + struct rc_dev { + struct device dev; +- bool managed_alloc; + bool registered; + bool idle; + bool encode_wakeup; +-- +2.53.0 + diff --git a/queue-7.0/media-renesas-vsp1-histo-fix-code-enumeration.patch b/queue-7.0/media-renesas-vsp1-histo-fix-code-enumeration.patch new file mode 100644 index 0000000000..c302bfdd95 --- /dev/null +++ b/queue-7.0/media-renesas-vsp1-histo-fix-code-enumeration.patch @@ -0,0 +1,42 @@ +From 9067f7e33635fd1f07fbe003151455288481da83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:03 +0200 +Subject: media: renesas: vsp1: histo: Fix code enumeration + +From: Laurent Pinchart + +[ Upstream commit a7985d28b3b13cd5e23f4271d702a46532f80424 ] + +The histogram media bus code enumeration does not check the index when +operating on the source pad, resulting in an infinite loop if userspace +keeps enumerating code without any loop boundary. Fix it by returning an +error for indices larger than 0 as the pad supports a single format. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-10-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_histo.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +index 390ea50f1595a..30e5f5ac09371 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c +@@ -170,7 +170,10 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev, + struct vsp1_histogram *histo = subdev_to_histo(subdev); + + if (code->pad == HISTO_PAD_SOURCE) { +- code->code = MEDIA_BUS_FMT_FIXED; ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/media-renesas-vsp1-initialize-format-on-all-pads.patch b/queue-7.0/media-renesas-vsp1-initialize-format-on-all-pads.patch new file mode 100644 index 0000000000..d61fb9e141 --- /dev/null +++ b/queue-7.0/media-renesas-vsp1-initialize-format-on-all-pads.patch @@ -0,0 +1,38 @@ +From 931f39e47260c3e4d053184d18c76ebb33351fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:59:07 +0200 +Subject: media: renesas: vsp1: Initialize format on all pads + +From: Laurent Pinchart + +[ Upstream commit 133ac42af0a1b389e8b7b3dc7c1cc8c30ff162b6 ] + +The state initialization function vsp1_entity_init_state() incorrectly +leaves the last entity pad out when initializing formats due to an off +by one error. Fix it. + +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-14-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/platform/renesas/vsp1/vsp1_entity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +index a6680d531872a..e8e65eb19a7d8 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c +@@ -386,7 +386,7 @@ static int vsp1_entity_init_state(struct v4l2_subdev *subdev, + unsigned int pad; + + /* Initialize all pad formats with default values. */ +- for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { ++ for (pad = 0; pad < subdev->entity.num_pads; ++pad) { + struct v4l2_subdev_format format = { + .pad = pad, + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY +-- +2.53.0 + diff --git a/queue-7.0/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch b/queue-7.0/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch new file mode 100644 index 0000000000..526e8d5099 --- /dev/null +++ b/queue-7.0/media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch @@ -0,0 +1,96 @@ +From 25f90f038453fb97178135b640ded56c91dadd2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 01:58:58 +0200 +Subject: media: renesas: vsp1: rpf: Fix crop left and top clamping +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Laurent Pinchart + +[ Upstream commit 55823379e61511d534b099949608677d703f709b ] + +The RPF doesn't enforces the alignment constraint on the sink pad +format, which could have an odd size, possibly down to 1x1. In that +case, the upper bounds for the left and top coordinates clamping would +become negative, cast to a very large positive value. Incorrect crop +rectangle coordinates would then be incorrectly accepted. + +A second issue can occur when the requested left and top coordinates are +negative. They are cast to a large unsigned value, clamped to the +maximum. While the calculation will produce valid values for the +hardware, this is not compliant with the V4L2 specification that +requires values to be adjusted to the closest valid value. + +Fix both issues by switching to signed clamping, with an explicit +minimum to adjust negative values, and adjusting the clamp bounds to +avoid negative upper bounds. + +Tested-by: Niklas Söderlund +Reviewed-by: Jacopo Mondi +Tested-by: Lad Prabhakar # HiHope RZ/G2M +Link: https://patch.msgid.link/20260318235907.831556-5-laurent.pinchart+renesas@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + .../media/platform/renesas/vsp1/vsp1_rwpf.c | 28 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +index 9c8085d5d3060..7c7bfb946b779 100644 +--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +@@ -216,6 +216,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) + { ++ unsigned int min_width = RWPF_MIN_WIDTH; ++ unsigned int min_height = RWPF_MIN_HEIGHT; + struct vsp1_rwpf *rwpf = to_rwpf(subdev); + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *format; +@@ -244,18 +246,36 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, + format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK); + + /* +- * Restrict the crop rectangle coordinates to multiples of 2 to avoid +- * shifting the color plane. ++ * For YUV formats, restrict the crop rectangle coordinates to multiples ++ * of 2 to avoid shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); ++ ++ /* ++ * The RPF doesn't enforces the alignment constraint on the sink ++ * pad format, which could have an odd size, possibly down to ++ * 1x1. In that case, the minimum width and height would be ++ * smaller than the sink pad format, leading to a negative upper ++ * bound in the left and top clamping. Clamp the minimum width ++ * and height to the format width and height to avoid this. ++ * ++ * In such a situation, odd values for the crop rectangle size ++ * would be accepted when clamping the width and height below. ++ * While that would create an invalid hardware configuration, ++ * the video device enforces proper alignment of the pixel ++ * format, and the mismatch will then result in link validation ++ * failure. Incorrect operation of the hardware is not possible. ++ */ ++ min_width = min(ALIGN(min_width, 2), format->width); ++ min_height = min(ALIGN(min_height, 2), format->height); + } + +- sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); +- sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); ++ sel->r.left = clamp_t(int, sel->r.left, 0, format->width - min_width); ++ sel->r.top = clamp_t(int, sel->r.top, 0, format->height - min_height); + sel->r.width = min_t(unsigned int, sel->r.width, + format->width - sel->r.left); + sel->r.height = min_t(unsigned int, sel->r.height, +-- +2.53.0 + diff --git a/queue-7.0/media-saa7164-fix-rev2-firmware-filename.patch b/queue-7.0/media-saa7164-fix-rev2-firmware-filename.patch new file mode 100644 index 0000000000..222ed77c1e --- /dev/null +++ b/queue-7.0/media-saa7164-fix-rev2-firmware-filename.patch @@ -0,0 +1,37 @@ +From 02d28c134672092be437e7a56f9f8eb7fad7682e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:29 -0500 +Subject: media: saa7164: Fix REV2 firmware filename + +From: Bradford Love + +[ Upstream commit ca3e8eaaa44e236413fd8d142231b5f03aefe55c ] + +The wrong firmware file is listed, leading to non functional devices +on REV2 models. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/pci/saa7164/saa7164-fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c +index cc9f384f7f1e9..341cef62452f1 100644 +--- a/drivers/media/pci/saa7164/saa7164-fw.c ++++ b/drivers/media/pci/saa7164/saa7164-fw.c +@@ -10,8 +10,8 @@ + + #include "saa7164.h" + +-#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" +-#define SAA7164_REV2_FIRMWARE_SIZE 4019072 ++#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2-3.fw" ++#define SAA7164_REV2_FIRMWARE_SIZE 4038864 + + #define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" + #define SAA7164_REV3_FIRMWARE_SIZE 4019072 +-- +2.53.0 + diff --git a/queue-7.0/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch b/queue-7.0/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch new file mode 100644 index 0000000000..2da0aff960 --- /dev/null +++ b/queue-7.0/media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch @@ -0,0 +1,46 @@ +From 3147d139cb13778f3a089091613a6a86f87c8c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:27 -0500 +Subject: media: si2168: Fix i2c command timeout on embedded platforms + +From: Bradford Love + +[ Upstream commit 3c414622fe4bcedc48305bfe2170ae13119fc331 ] + +On many embedded platforms i2c responses through USB are not returned +as quickly, plus constantly banging on the i2c master receive essentially +deadlocks the driver. Inserting a 3ms delay between i2c receive calls +and extending the timeout fixes all tested platforms. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index 6647e17611734..9c5bac8cda477 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -40,7 +40,7 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + + if (cmd->rlen) { + /* wait cmd execution terminate */ +- #define TIMEOUT 70 ++ #define TIMEOUT 140 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = i2c_master_recv(client, cmd->args, cmd->rlen); +@@ -54,6 +54,8 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) + /* firmware ready? */ + if ((cmd->args[0] >> 7) & 0x01) + break; ++ ++ usleep_range(2500, 3500); + } + + dev_dbg(&client->dev, "cmd execution took %d ms\n", +-- +2.53.0 + diff --git a/queue-7.0/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch b/queue-7.0/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch new file mode 100644 index 0000000000..317f8d2b47 --- /dev/null +++ b/queue-7.0/media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch @@ -0,0 +1,38 @@ +From b506ff4f318698330557537ef2d524cabd4bf353 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:35:28 -0500 +Subject: media: si2168: fw 4.0-11 loses warm state during sleep + +From: Bradford Love + +[ Upstream commit 57c3c67fce95ab0d449d3f6ae339621fcb61080e ] + +Ignoring version 4.0-11 firmware leads to non functional devices +after sleep on all Hauppauge DVB devices containing the si2168 and +firmware version 4.0-11. + +Signed-off-by: Bradford Love +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + drivers/media/dvb-frontends/si2168.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c +index c4bbcd127caca..6647e17611734 100644 +--- a/drivers/media/dvb-frontends/si2168.c ++++ b/drivers/media/dvb-frontends/si2168.c +@@ -572,8 +572,8 @@ static int si2168_sleep(struct dvb_frontend *fe) + if (ret) + goto err; + +- /* Firmware later than B 4.0-11 loses warm state during sleep */ +- if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) ++ /* Firmware B 4.0-11 and later lose warm state during sleep */ ++ if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + dev->warm = false; + + cmd_init(&cmd, "\x13", 1, 0); +-- +2.53.0 + diff --git a/queue-7.0/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch b/queue-7.0/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch new file mode 100644 index 0000000000..0a8497f7f6 --- /dev/null +++ b/queue-7.0/media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch @@ -0,0 +1,50 @@ +From 9b7bcd63d6986837ef6f54ac607b48008bd68469 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 12:34:32 +0100 +Subject: media: stm32: dcmi: stop the dma transfer on overrun + +From: Alain Volmat + +[ Upstream commit 4847286b87ccda7bdec8245f35c07203ce9eb0ed ] + +Ensure to stop the dma transfer whenever receiving a overrun +to avoid having a buffer partially filled with a frame and +partially with the next frame. + +Signed-off-by: Alain Volmat +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index 13762861b7694..496e0781a957b 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -447,9 +447,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->misr & IT_OVR) { ++ /* Disable capture */ ++ reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE); ++ + dcmi->overrun_count++; ++ + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; ++ ++ spin_unlock_irq(&dcmi->irqlock); ++ dmaengine_terminate_sync(dcmi->dma_chan); ++ ++ if (dcmi_restart_capture(dcmi)) ++ dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__); ++ ++ return IRQ_HANDLED; + } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; +-- +2.53.0 + diff --git a/queue-7.0/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch b/queue-7.0/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch new file mode 100644 index 0000000000..e078000056 --- /dev/null +++ b/queue-7.0/media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch @@ -0,0 +1,67 @@ +From e4dffb72ec8be6e3d3dd842ba0daedf164332877 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:32:18 +0000 +Subject: media: synopsys: hdmirx: support use with sleeping GPIOs + +From: Mark Brown + +[ Upstream commit 2fb0481fe0d7891420c1a3df2e4f9a70b1f77dbd ] + +The recent change in commit 20cf2aed89ac ("gpio: rockchip: mark the GPIO +controller as sleeping") to mark the rockchip GPIO driver as sleeping +has started triggering the warning at drivers/gpio/gpiolib.c:3523 +indicating that a sleepable GPIO was called via the non-sleeping APIs on +the Rock 5B: + +<4>[ 14.699308] Call trace: +<4>[ 14.699545] gpiod_get_value+0x90/0x98 (P) +<4>[ 14.699928] tx_5v_power_present+0x44/0xd0 [synopsys_hdmirx] +<4>[ 14.700446] hdmirx_delayed_work_hotplug+0x34/0x128 [synopsys_hdmirx] +<4>[ 14.701031] process_one_work+0x14c/0x28c +<4>[ 14.701405] worker_thread+0x184/0x300 +<4>[ 14.701756] kthread+0x11c/0x128 +<4>[ 14.702065] ret_from_fork+0x10/0x20 + +Currently the active use of the GPIO is all done from process context so +can be simply converted to use gpiod_get_value_cansleep(). There is one use +of the GPIO from hard interrupt context but this is only done so the status +can be displayed in a debug print so can simply be deleted without any +functional effect. + +Reviewed-by: Heiko Stuebner +Acked-by: Dmitry Osipenko +Signed-off-by: Mark Brown +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +index 9cceffa4ce250..61ad20b18b8d6 100644 +--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c ++++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +@@ -232,7 +232,7 @@ static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) + + for (i = 0; i < 10; i++) { + usleep_range(1000, 1100); +- val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); ++ val = gpiod_get_value_cansleep(hdmirx_dev->detect_5v_gpio); + if (val > 0) + cnt++; + if (cnt >= detection_threshold) +@@ -2252,10 +2252,6 @@ static void hdmirx_delayed_work_res_change(struct work_struct *work) + static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id) + { + struct snps_hdmirx_dev *hdmirx_dev = dev_id; +- u32 val; +- +- val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); +- v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: 5v:%d\n", __func__, val); + + queue_delayed_work(system_unbound_wq, + &hdmirx_dev->delayed_work_hotplug, +-- +2.53.0 + diff --git a/queue-7.0/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch b/queue-7.0/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch new file mode 100644 index 0000000000..d73fa6a5d0 --- /dev/null +++ b/queue-7.0/memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch @@ -0,0 +1,62 @@ +From 95986fd947300920a44cbfd891b8610926f54d5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 16:35:00 -0800 +Subject: memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5 + +From: Florian Fainelli + +[ Upstream commit a969a0835152984a0f556434eafdee0b84213670 ] + +The same limitations that apply to LPDDR4 also apply to LPDDR5. Expand +the check and rename accordingly. + +Signed-off-by: Florian Fainelli +Link: https://patch.msgid.link/20260122003501.1191059-1-florian.fainelli@broadcom.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/brcmstb_memc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c +index ba73470b1b134..c28fe90936168 100644 +--- a/drivers/memory/brcmstb_memc.c ++++ b/drivers/memory/brcmstb_memc.c +@@ -14,6 +14,7 @@ + + #define REG_MEMC_CNTRLR_CONFIG 0x00 + #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 ++#define CNTRLR_CONFIG_LPDDR5_SHIFT 6 + #define CNTRLR_CONFIG_MASK 0xf + #define REG_MEMC_SRPD_CFG_21 0x20 + #define REG_MEMC_SRPD_CFG_20 0x34 +@@ -34,14 +35,15 @@ struct brcmstb_memc { + u32 srpd_offset; + }; + +-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc) ++static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc) + { + void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG; + u32 reg; + + reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK; + +- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT; ++ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT || ++ reg == CNTRLR_CONFIG_LPDDR5_SHIFT; + } + + static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc, +@@ -95,7 +97,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr, + * dynamic tuning process will also get affected by the inactivity + * timeout, thus making it non functional. + */ +- if (brcmstb_memc_uses_lpddr4(memc)) ++ if (brcmstb_memc_uses_lpddr45(memc)) + return -EOPNOTSUPP; + + ret = kstrtouint(buf, 10, &val); +-- +2.53.0 + diff --git a/queue-7.0/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch b/queue-7.0/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch new file mode 100644 index 0000000000..1cb7383618 --- /dev/null +++ b/queue-7.0/mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch @@ -0,0 +1,52 @@ +From 8d7bc6b4721dbfbfcfc1eb917a683c87e8b59243 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 12:03:37 +0200 +Subject: mfd: intel-lpss: Add Intel Nova Lake-H PCI IDs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Saranya Gopal + +[ Upstream commit d6e0ef44688249009dfa24f1cd619d41637de060 ] + +Add Intel Nova Lake-H LPSS PCI IDs. + +Signed-off-by: Saranya Gopal +Co-developed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260313100337.3471-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/intel-lpss-pci.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c +index 713a5bfb1a3c2..a9452ac92fb2d 100644 +--- a/drivers/mfd/intel-lpss-pci.c ++++ b/drivers/mfd/intel-lpss-pci.c +@@ -633,6 +633,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0xa879), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87a), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa87b), (kernel_ulong_t)&ehl_i2c_info }, ++ /* NVL-H */ ++ { PCI_VDEVICE(INTEL, 0xd325), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd326), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd327), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd330), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd347), (kernel_ulong_t)&tgl_spi_info }, ++ { PCI_VDEVICE(INTEL, 0xd350), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd351), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd352), (kernel_ulong_t)&bxt_uart_info }, ++ { PCI_VDEVICE(INTEL, 0xd378), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd379), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37a), (kernel_ulong_t)&ehl_i2c_info }, ++ { PCI_VDEVICE(INTEL, 0xd37b), (kernel_ulong_t)&ehl_i2c_info }, + /* PTL-H */ + { PCI_VDEVICE(INTEL, 0xe325), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe326), (kernel_ulong_t)&bxt_uart_info }, +-- +2.53.0 + diff --git a/queue-7.0/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch b/queue-7.0/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch new file mode 100644 index 0000000000..b0835783fc --- /dev/null +++ b/queue-7.0/mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch @@ -0,0 +1,94 @@ +From 1d49205217e4e6c0f6ed9a18e601fb34f0022d46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 23:00:45 +0900 +Subject: mfd: mt6397: Properly fix CID of MT6328, MT6331 and MT6332 + +From: Akari Tsuyukusa + +[ Upstream commit a09506820afa391e0a8ecc4b05c954f21e50b1de ] + +CIDs set for MT6328, MT6331 and MT6332 are not appropriate. +Many Android downstream kernels define CID as below, + +MT6328: + + #define PMIC6328_E1_CID_CODE 0x2810 + #define PMIC6328_E2_CID_CODE 0x2820 + #define PMIC6328_E3_CID_CODE 0x2830 + +MT6331/MT6332: + + #define PMIC6331_E1_CID_CODE 0x3110 + #define PMIC6331_E2_CID_CODE 0x3120 + #define PMIC6331_E3_CID_CODE 0x3130 + + #define PMIC6332_E1_CID_CODE 0x3210 + #define PMIC6332_E2_CID_CODE 0x3220 + #define PMIC6332_E3_CID_CODE 0x3230 + +The current configuration incorrectly uses the revision code as the CID. +Therefore, the driver cannot detect the same PMIC of different revisions. +(E1/E2 for MT6328, E1/E3 for MT6331/MT6332) +Based on these, the CID of MT6328, MT6331 and MT6332 should be corrected. + +Additionally, the incorrect MT6331/MT6332 CID overlaps with the MT6320's +actual CID: + + #define PMIC6320_E1_CID_CODE 0x1020 + #define PMIC6320_E2_CID_CODE 0x2020 + +This causes a conflict in the switch-case statement of mt6397-irq.c, +this prevents adding support for MT6320. + +Signed-off-by: Akari Tsuyukusa +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20260302140045.651727-1-akkun11.open@gmail.com +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mt6397-core.c | 4 ++-- + include/linux/mfd/mt6397/core.h | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c +index 3e58d0764c7e0..1bdacda9a933f 100644 +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -297,7 +297,7 @@ static const struct chip_data mt6323_core = { + + static const struct chip_data mt6328_core = { + .cid_addr = MT6328_HWCID, +- .cid_shift = 0, ++ .cid_shift = 8, + .cells = mt6328_devs, + .cell_size = ARRAY_SIZE(mt6328_devs), + .irq_init = mt6397_irq_init, +@@ -313,7 +313,7 @@ static const struct chip_data mt6357_core = { + + static const struct chip_data mt6331_mt6332_core = { + .cid_addr = MT6331_HWCID, +- .cid_shift = 0, ++ .cid_shift = 8, + .cells = mt6331_mt6332_devs, + .cell_size = ARRAY_SIZE(mt6331_mt6332_devs), + .irq_init = mt6397_irq_init, +diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h +index b774c3a4bb62e..340fc72e22aa6 100644 +--- a/include/linux/mfd/mt6397/core.h ++++ b/include/linux/mfd/mt6397/core.h +@@ -12,9 +12,9 @@ + + enum chip_id { + MT6323_CHIP_ID = 0x23, +- MT6328_CHIP_ID = 0x30, +- MT6331_CHIP_ID = 0x20, +- MT6332_CHIP_ID = 0x20, ++ MT6328_CHIP_ID = 0x28, ++ MT6331_CHIP_ID = 0x31, ++ MT6332_CHIP_ID = 0x32, + MT6357_CHIP_ID = 0x57, + MT6358_CHIP_ID = 0x58, + MT6359_CHIP_ID = 0x59, +-- +2.53.0 + diff --git a/queue-7.0/mm-memfd_luo-report-error-when-restoring-a-folio-fai.patch b/queue-7.0/mm-memfd_luo-report-error-when-restoring-a-folio-fai.patch new file mode 100644 index 0000000000..d8d3d6f7ea --- /dev/null +++ b/queue-7.0/mm-memfd_luo-report-error-when-restoring-a-folio-fai.patch @@ -0,0 +1,48 @@ +From 6ce2d20aeed1891ff5ecac7f6f0b65b299c67716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 06:23:00 +0100 +Subject: mm/memfd_luo: report error when restoring a folio fails mid-loop + +From: David Carlier + +[ Upstream commit 0fb1daf0b78d0e23b63b6b65de56d4a3fd83bc14 ] + +memfd_luo_retrieve_folios() initialises err to -EIO, but the per-iteration +calls to mem_cgroup_charge(), shmem_add_to_page_cache() and +shmem_inode_acct_blocks() reuse and overwrite err. Once any iteration +completes successfully, err becomes zero. + +If a later iteration's kho_restore_folio() returns NULL, the failure path +jumps to put_folios without resetting err, so the function returns 0. +The caller memfd_luo_retrieve() then takes the success path, sets +args->file and reports the restore as successful, leaving userspace with +a partially populated memfd and no indication that anything went wrong. + +Set err to -EIO in the kho_restore_folio() failure branch so the error +is propagated to the caller. + +Signed-off-by: David Carlier +Reviewed-by: Pratyush Yadav +Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd") +Link: https://patch.msgid.link/20260415052300.362539-1-devnexen@gmail.com +Signed-off-by: Mike Rapoport (Microsoft) +Signed-off-by: Sasha Levin +--- + mm/memfd_luo.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c +index cfd665a5b7874..bb5f601418032 100644 +--- a/mm/memfd_luo.c ++++ b/mm/memfd_luo.c +@@ -412,6 +412,7 @@ static int memfd_luo_retrieve_folios(struct file *file, + if (!folio) { + pr_err("Unable to restore folio at physical address: %llx\n", + phys); ++ err = -EIO; + goto put_folios; + } + index = pfolio->index; +-- +2.53.0 + diff --git a/queue-7.0/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch b/queue-7.0/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch new file mode 100644 index 0000000000..63f7db507a --- /dev/null +++ b/queue-7.0/mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch @@ -0,0 +1,64 @@ +From a98c1ea00497769a952e0cb9e423a6b8bb47c3fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 09:35:52 +0800 +Subject: mmc: core: Validate UHS/DDR/HS200 timing selection for 1-bit bus + width + +From: Luke Wang + +[ Upstream commit e98f926e5a2d8023a74ec2ba7a973b5d76610f4e ] + +UHS/DDR/HS200 modes require at least 4-bit bus support. Host controllers +that lack relevant capability registers rely on paring properties provided +by firmware, which may incorrectly set these modes. Now that mmc_validate_host_caps() +has been introduced to validate such configuration violations, let's also +add checks for UHS/DDR/HS200 modes. + +This fixes an issue where, if the HS200/HS400 property is set while only +a 1-bit bus width is used, mmc_select_hs200() returns 0 without actually +performing the mode switch. Consequently, mmc_select_timing() proceeds +without falling back to mmc_select_hs(), leaving the eMMC device operating +in legacy mode (26 MHz) instead of switching to High Speed mode (52 MHz). + +Signed-off-by: Luke Wang +[Shawn: reword the commit msg and rework the code] +Signed-off-by: Shawn Lin +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/core/host.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 88c95dbfd9cfd..a457c88fdcbc7 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -624,12 +624,24 @@ static int mmc_validate_host_caps(struct mmc_host *host) + return -EINVAL; + } + ++ /* UHS/DDR/HS200 modes require at least 4-bit bus */ ++ if (!(caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) && ++ ((caps & (MMC_CAP_UHS | MMC_CAP_DDR)) || (caps2 & MMC_CAP2_HS200))) { ++ dev_warn(dev, "drop UHS/DDR/HS200 support since 1-bit bus only\n"); ++ caps &= ~(MMC_CAP_UHS | MMC_CAP_DDR); ++ caps2 &= ~MMC_CAP2_HS200; ++ } ++ ++ /* HS400 and HS400ES modes require 8-bit bus */ + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); +- host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; ++ caps2 &= ~(MMC_CAP2_HS400_ES | MMC_CAP2_HS400); + } + ++ host->caps = caps; ++ host->caps2 = caps2; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch b/queue-7.0/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch new file mode 100644 index 0000000000..abd275cfa8 --- /dev/null +++ b/queue-7.0/mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch @@ -0,0 +1,69 @@ +From 757a1ed1a167f16198524debcc00acd2f47232f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 15:56:03 +0800 +Subject: mmc: sdhci-esdhc-imx: wait for data transfer completion before reset + +From: Luke Wang + +[ Upstream commit 8ceb70c9f970bfbdceb1e51578850a60b9de2236 ] + +On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) +cause system hangs and reboots during manual tuning. These cards exhibit +large gaps (~16us) between tuning command response and data transmission. +When cmd CRC errors occur during tuning, the code assumes data errors even +tuning data hasn't been fully received and then reset host data circuit. + +Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to +make sure no active data transfers. Previously, resetting while data was +in-flight would clear data circuit, including ADMA/SDMA address, causing +data to be transmitted to incorrect memory address. This patch adds +polling for data transfer completion before executing resets. + +Signed-off-by: Luke Wang +Reviewed-by: Bough Chen +Acked-by: Adrian Hunter +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/sdhci-esdhc-imx.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c +index a7a5df673b0f6..97461e20425d8 100644 +--- a/drivers/mmc/host/sdhci-esdhc-imx.c ++++ b/drivers/mmc/host/sdhci-esdhc-imx.c +@@ -216,6 +216,8 @@ + #define ESDHC_FLAG_DUMMY_PAD BIT(19) + + #define ESDHC_AUTO_TUNING_WINDOW 3 ++/* 100ms timeout for data inhibit */ ++#define ESDHC_DATA_INHIBIT_WAIT_US 100000 + + enum wp_types { + ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ +@@ -1453,6 +1455,22 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) + + static void esdhc_reset(struct sdhci_host *host, u8 mask) + { ++ u32 present_state; ++ int ret; ++ ++ /* ++ * For data or full reset, ensure any active data transfer completes ++ * before resetting to avoid system hang. ++ */ ++ if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) { ++ ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT, present_state, ++ !(present_state & SDHCI_DATA_INHIBIT), 2, ++ ESDHC_DATA_INHIBIT_WAIT_US); ++ if (ret == -ETIMEDOUT) ++ dev_warn(mmc_dev(host->mmc), ++ "timeout waiting for data transfer completion\n"); ++ } ++ + sdhci_and_cqhci_reset(host, mask); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); +-- +2.53.0 + diff --git a/queue-7.0/module-override-eexist-module-return.patch b/queue-7.0/module-override-eexist-module-return.patch new file mode 100644 index 0000000000..1a2833cb89 --- /dev/null +++ b/queue-7.0/module-override-eexist-module-return.patch @@ -0,0 +1,55 @@ +From 3ba02a45f8497aa0f3cc1e0ab52636b7b916ba45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:13:51 -0500 +Subject: module: Override -EEXIST module return + +From: Lucas De Marchi + +[ Upstream commit 743f8cae549affe8eafb021b8c0e78a9f3bc23fa ] + +The -EEXIST errno is reserved by the module loading functionality. When +userspace calls [f]init_module(), it expects a -EEXIST to mean that the +module is already loaded in the kernel. If module_init() returns it, +that is not true anymore. + +Override the error when returning to userspace: it doesn't make sense to +change potentially long error propagation call chains just because it's +will end up as the return of module_init(). + +Closes: https://lore.kernel.org/all/aKLzsAX14ybEjHfJ@orbyte.nwl.cc/ +Cc: Greg Kroah-Hartman +Cc: Aaron Tomlin +Cc: Petr Pavlu +Cc: Daniel Gomez +Cc: Phil Sutter +Cc: Christophe Leroy +Signed-off-by: Lucas De Marchi +[Sami: Fixed a typo.] +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + kernel/module/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/module/main.c b/kernel/module/main.c +index ef2e2130972fe..e94494a241ecd 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -3045,6 +3045,14 @@ static noinline int do_init_module(struct module *mod) + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { ++ /* ++ * -EEXIST is reserved by [f]init_module() to signal to userspace that ++ * a module with this name is already loaded. Use something else if the ++ * module itself is returning that. ++ */ ++ if (ret == -EEXIST) ++ ret = -EBUSY; ++ + goto fail_free_freeinit; + } + if (ret > 0) { +-- +2.53.0 + diff --git a/queue-7.0/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch b/queue-7.0/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch new file mode 100644 index 0000000000..0844504d07 --- /dev/null +++ b/queue-7.0/net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch @@ -0,0 +1,67 @@ +From 6e043a1392cb6c5ff3842ca597f837cf27ddc1ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:09:17 +0000 +Subject: net: core: allow netdev_upper_get_next_dev_rcu from bh context + +From: Kohei Enju + +[ Upstream commit 39feb171f361f887dad8504dc5822b852871ac21 ] + +Since XDP programs are called from a NAPI poll context, the RCU +reference liveness is ensured by local_bh_disable(). + +Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master +device") started to call netdev_upper_get_next_dev_rcu() from this +context, but missed adding rcu_read_lock_bh_held() as a condition to the +RCU checks. +While both bh_disabled and rcu_read_lock() provide RCU protection, +lockdep complains since the check condition is insufficient [1]. + +Add rcu_read_lock_bh_held() as condition to help lockdep to understand +the dereference is safe, in the same way as commit 694cea395fde ("bpf: +Allow RCU-protected lookups to happen from bh context"). + +[1] + WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0 + ... + RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0 + ... + + dev_map_enqueue_multi+0x411/0x970 + xdp_do_redirect+0xdf2/0x1030 + __igc_xdp_run_prog+0x6a0/0xc80 + igc_poll+0x34b0/0x70b0 + __napi_poll.constprop.0+0x98/0x490 + net_rx_action+0x8f2/0xfa0 + handle_softirqs+0x1c7/0x710 + __irq_exit_rcu+0xb1/0xf0 + irq_exit_rcu+0x9/0x20 + common_interrupt+0x7f/0x90 + + +Signed-off-by: Kohei Enju +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index fab5a0bebd924..b0f8e66a0da6a 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -8149,7 +8149,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, + { + struct netdev_adjacent *upper; + +- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); ++ WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && ++ !lockdep_rtnl_is_held()); + + upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); + +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-cortina-carry-over-frag-counter.patch b/queue-7.0/net-ethernet-cortina-carry-over-frag-counter.patch new file mode 100644 index 0000000000..a7524a6795 --- /dev/null +++ b/queue-7.0/net-ethernet-cortina-carry-over-frag-counter.patch @@ -0,0 +1,118 @@ +From 8c45be0a5ca3af9d0b44ade24f494582a011e272 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:38 +0200 +Subject: net: ethernet: cortina: Carry over frag counter + +From: Linus Walleij + +[ Upstream commit ebd8ec2b309e3a447851b456ccaf8fb39f3661e7 ] + +The gmac_rx() NAPI poll function assembles packets in an +SKB from a ring buffer. + +If the ring buffer gets completely emptied during a poll cycle, +we exit gmac_rx(), but the packet is not yet completely +assembled in the SKB, yet the fragment counter frag_nr is +reset to zero on the next invocation. + +Solve this by making the RX fragment counter a part of the +port struct, and carry it over between invocations. + +Reset the fragment counter only right after calling +napi_gro_frags(), on error (after calling napi_free_frags()) +or if stopping the port. + +Reset it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-3-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index e8d973b8fb0c3..ccd14a386e3b9 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -123,6 +123,7 @@ struct gemini_ethernet_port { + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; + struct sk_buff *rx_skb; ++ unsigned int rx_frag_nr; + + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; +@@ -1444,6 +1445,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ unsigned int frag_nr = port->rx_frag_nr; + struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; +@@ -1457,7 +1459,6 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short r, w; + union dma_rwptr rw; + dma_addr_t mapping; +- int frag_nr = 0; + + spin_lock_irqsave(&geth->irq_lock, flags); + rw.bits32 = readl(ptr_reg); +@@ -1497,6 +1498,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + continue; + } +@@ -1507,6 +1509,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + napi_free_frags(&port->napi); + port->stats.rx_dropped++; + skb = NULL; ++ frag_nr = 0; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1541,6 +1544,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (word3.bits32 & EOF_BIT) { + napi_gro_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + --budget; + } + continue; +@@ -1549,6 +1553,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + skb = NULL; ++ frag_nr = 0; + } + + if (mapping) +@@ -1558,6 +1563,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + } + + port->rx_skb = skb; ++ port->rx_frag_nr = frag_nr; + writew(r, ptr_reg); + return budget; + } +@@ -1886,6 +1892,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_stop_dma(port); + napi_disable(&port->napi); + port->rx_skb = NULL; ++ port->rx_frag_nr = 0; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-cortina-drop-half-assembled-skb.patch b/queue-7.0/net-ethernet-cortina-drop-half-assembled-skb.patch new file mode 100644 index 0000000000..8061b4192a --- /dev/null +++ b/queue-7.0/net-ethernet-cortina-drop-half-assembled-skb.patch @@ -0,0 +1,54 @@ +From f535f93a47570da525c40d8feba1c98494ff6fc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 23:52:17 +0200 +Subject: net: ethernet: cortina: Drop half-assembled SKB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Andreas Haarmann-Thiemann + +[ Upstream commit b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 ] + +In gmac_rx() (drivers/net/ethernet/cortina/gemini.c), when +gmac_get_queue_page() returns NULL for the second page of a multi-page +fragment, the driver logs an error and continues — but does not free the +partially assembled skb that was being assembled via napi_build_skb() / +napi_get_frags(). + +Free the in-progress partially assembled skb via napi_free_frags() +and increase the number of dropped frames appropriately +and assign the skb pointer NULL to make sure it is not lingering +around, matching the pattern already used elsewhere in the driver. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Signed-off-by: Andreas Haarmann-Thiemann +Signed-off-by: Linus Walleij +Reviewed-by: Alexander Lobakin +Link: https://patch.msgid.link/20260505-gemini-ethernet-fix-v2-1-997c31d06079@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebd8ec2b309e ("net: ethernet: cortina: Carry over frag counter") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 57a25030f883c..e8d973b8fb0c3 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -1493,6 +1493,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE); + if (!gpage) { + dev_err(geth->dev, "could not find mapping\n"); ++ if (skb) { ++ napi_free_frags(&port->napi); ++ port->stats.rx_dropped++; ++ skb = NULL; ++ } + continue; + } + page = gpage->page; +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-cortina-make-rx-skb-per-port.patch b/queue-7.0/net-ethernet-cortina-make-rx-skb-per-port.patch new file mode 100644 index 0000000000..0309cf7b1e --- /dev/null +++ b/queue-7.0/net-ethernet-cortina-make-rx-skb-per-port.patch @@ -0,0 +1,87 @@ +From 9b36b8f5029564d6e8cbcffe02ff105c3b328b25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 9 May 2026 00:13:37 +0200 +Subject: net: ethernet: cortina: Make RX SKB per-port + +From: Linus Walleij + +[ Upstream commit 06937db21ee311ed07eba47954447245041a982d ] + +The SKB used to assemble packets from fragments in gmac_rx() +is static local, but the Gemini has two ethernet ports, meaning +there can be races between the ports on a bad day if a device +is using both. + +Make the RX SKB a per-port variable and carry it over between +invocations in the port struct instead. + +Zero the pointer once we call napi_gro_frags(), on error (after +calling napi_free_frags()) or if the port is stopped. + +Zero it in some place where not strictly necessary just to +emphasize what is going on. + +This was found by Sashiko during normal patch review. + +Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") +Link: https://sashiko.dev/#/patchset/20260505-gemini-ethernet-fix-v2-1-997c31d06079%40kernel.org +Signed-off-by: Linus Walleij +Link: https://patch.msgid.link/20260509-gemini-ethernet-fixes-v1-2-6c5d20ddc35b@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cortina/gemini.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c +index 4824232f48907..57a25030f883c 100644 +--- a/drivers/net/ethernet/cortina/gemini.c ++++ b/drivers/net/ethernet/cortina/gemini.c +@@ -122,6 +122,8 @@ struct gemini_ethernet_port { + struct napi_struct napi; + struct hrtimer rx_coalesce_timer; + unsigned int rx_coalesce_nsecs; ++ struct sk_buff *rx_skb; ++ + unsigned int freeq_refill; + struct gmac_txq txq[TX_QUEUE_NUM]; + unsigned int txq_order; +@@ -1442,10 +1444,10 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + unsigned short m = (1 << port->rxq_order) - 1; + struct gemini_ethernet *geth = port->geth; + void __iomem *ptr_reg = port->rxq_rwptr; ++ struct sk_buff *skb = port->rx_skb; + unsigned int frame_len, frag_len; + struct gmac_rxdesc *rx = NULL; + struct gmac_queue_page *gpage; +- static struct sk_buff *skb; + union gmac_rxdesc_0 word0; + union gmac_rxdesc_1 word1; + union gmac_rxdesc_3 word3; +@@ -1499,6 +1501,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + if (skb) { + napi_free_frags(&port->napi); + port->stats.rx_dropped++; ++ skb = NULL; + } + + skb = gmac_skb_if_good_frame(port, word0, frame_len); +@@ -1549,6 +1552,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) + port->stats.rx_dropped++; + } + ++ port->rx_skb = skb; + writew(r, ptr_reg); + return budget; + } +@@ -1876,6 +1880,7 @@ static int gmac_stop(struct net_device *netdev) + gmac_disable_tx_rx(netdev); + gmac_stop_dma(port); + napi_disable(&port->napi); ++ port->rx_skb = NULL; + + gmac_enable_irq(netdev, 0); + gmac_cleanup_rxq(netdev); +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch b/queue-7.0/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch new file mode 100644 index 0000000000..1bdd46e80d --- /dev/null +++ b/queue-7.0/net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch @@ -0,0 +1,45 @@ +From 349965697f58ba1178a2611af32f19b727f9dbb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 19:37:28 -0700 +Subject: net: ethernet: cs89x0: remove stale CONFIG_MACH_MX31ADS reference + +From: Ethan Nelson-Moore + +[ Upstream commit 36a8d04a8293afcb9304cf0cd3741f67698f2a1a ] + +The legacy ARM board file for MACH_MX31ADS was removed in commit +c93197b0041d ("ARM: imx: Remove i.MX31 board files"), but a reference +to it remained in the cs89x0 driver. Drop this unused code. + +Signed-off-by: Ethan Nelson-Moore +Fixes: c93197b0041d ("ARM: imx: Remove i.MX31 board files") +Link: https://patch.msgid.link/20260509023732.42256-1-enelsonmoore@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cirrus/cs89x0.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c +index fa5857923db4c..b4bfd6c174e78 100644 +--- a/drivers/net/ethernet/cirrus/cs89x0.c ++++ b/drivers/net/ethernet/cirrus/cs89x0.c +@@ -1271,7 +1271,6 @@ static const struct net_device_ops net_ops = { + + static void __init reset_chip(struct net_device *dev) + { +-#if !defined(CONFIG_MACH_MX31ADS) + struct net_local *lp = netdev_priv(dev); + unsigned long reset_start_time; + +@@ -1298,7 +1297,6 @@ static void __init reset_chip(struct net_device *dev) + while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 && + time_before(jiffies, reset_start_time + 2)) + ; +-#endif /* !CONFIG_MACH_MX31ADS */ + } + + /* This is the real probe routine. +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch b/queue-7.0/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch new file mode 100644 index 0000000000..701f304a53 --- /dev/null +++ b/queue-7.0/net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch @@ -0,0 +1,101 @@ +From 96e428b8e207f28e6df15cc41001484c70434502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:45:18 +0000 +Subject: net: ethernet: mtk_eth_soc: avoid writing to ESW registers on MT7628 + +From: Joris Vaisvila + +[ Upstream commit 9a04d3b2f0708a9e5e1f731bafb69b040bb934a0 ] + +The MT7628 has a fixed-link PHY and does not expose MAC control +registers. Writes to these registers only corrupt the ESW VLAN +configuration. + +This patch explicitly registers no-op phylink_mac_ops for MT7628, as +after removing the invalid register accesses, the existing +phylink_mac_ops effectively become no-ops. + +This code was introduced by commit 296c9120752b +("net: ethernet: mediatek: Add MT7628/88 SoC support") + +Signed-off-by: Joris Vaisvila +Reviewed-by: Daniel Golle +Reviewed-by: Stefan Roese +Link: https://patch.msgid.link/20260226154547.68553-1-joey@tinyisr.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 ++++++++++++++++++--- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 796f79088f366..8d225bc9f0636 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -562,9 +562,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + int val, ge_mode, err = 0; + u32 i; + +- /* MT76x8 has no hardware settings between for the MAC */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +- mac->interface != state->interface) { ++ if (mac->interface != state->interface) { + /* Setup soc pin functions */ + switch (state->interface) { + case PHY_INTERFACE_MODE_TRGMII: +@@ -956,6 +954,30 @@ static const struct phylink_mac_ops mtk_phylink_ops = { + .mac_enable_tx_lpi = mtk_mac_enable_tx_lpi, + }; + ++static void rt5350_mac_config(struct phylink_config *config, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++} ++ ++static void rt5350_mac_link_down(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++} ++ ++static void rt5350_mac_link_up(struct phylink_config *config, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++} ++ ++/* MT76x8 (rt5350-eth) does not expose any MAC control registers */ ++static const struct phylink_mac_ops rt5350_phylink_ops = { ++ .mac_config = rt5350_mac_config, ++ .mac_link_down = rt5350_mac_link_down, ++ .mac_link_up = rt5350_mac_link_up, ++}; ++ + static void mtk_mdio_config(struct mtk_eth *eth) + { + u32 val; +@@ -4800,6 +4822,7 @@ static const struct net_device_ops mtk_netdev_ops = { + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + { ++ const struct phylink_mac_ops *mac_ops = &mtk_phylink_ops; + const __be32 *_id = of_get_property(np, "reg", NULL); + phy_interface_t phy_mode; + struct phylink *phylink; +@@ -4934,9 +4957,12 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ mac_ops = &rt5350_phylink_ops; ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), +- phy_mode, &mtk_phylink_ops); ++ phy_mode, mac_ops); + if (IS_ERR(phylink)) { + err = PTR_ERR(phylink); + goto free_netdev; +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-ravb-disable-interrupts-when-closing-de.patch b/queue-7.0/net-ethernet-ravb-disable-interrupts-when-closing-de.patch new file mode 100644 index 0000000000..cc25134fd9 --- /dev/null +++ b/queue-7.0/net-ethernet-ravb-disable-interrupts-when-closing-de.patch @@ -0,0 +1,39 @@ +From 0a415708c6d88d658ef48256e60442d594101108 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 10:55:32 +0100 +Subject: net: ethernet: ravb: Disable interrupts when closing device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yoshihiro Shimoda + +[ Upstream commit 9278b888920ee8f3cea06622f04da681536b6601 ] + +Disable E-MAC interrupts when closing the device. + +Signed-off-by: Yoshihiro Shimoda +[Niklas: Rebase from BSP and reword commit message] +Signed-off-by: Niklas Söderlund +Link: https://patch.msgid.link/20260307095532.2118495-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 84b657fc2e158..2c725824b3488 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2367,6 +2367,7 @@ static int ravb_close(struct net_device *ndev) + ravb_write(ndev, 0, RIC0); + ravb_write(ndev, 0, RIC2); + ravb_write(ndev, 0, TIC); ++ ravb_write(ndev, 0, ECSIPR); + + /* PHY disconnect */ + if (ndev->phydev) { +-- +2.53.0 + diff --git a/queue-7.0/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch b/queue-7.0/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch new file mode 100644 index 0000000000..9b404673a5 --- /dev/null +++ b/queue-7.0/net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch @@ -0,0 +1,106 @@ +From d9d58a693c41eb6f09897a56c7a96f5de4bf5464 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 21:17:38 +0800 +Subject: net: ethtool: fix NULL pointer dereference in phy_reply_size + +From: Quan Sun <2022090917019@std.uestc.edu.cn> + +[ Upstream commit 4908f1395fb1b832ceec11584af649874a2732ea ] + +In phy_prepare_data(), several strings such as 'name', 'drvname', +'upstream_sfp_name', and 'downstream_sfp_name' are allocated using +kstrdup(). However, these allocations were not checked for failure. + +If kstrdup() fails for 'name', it returns NULL while the function +continues. This leads to a kernel NULL pointer dereference and panic +later in phy_reply_size() when it unconditionally calls strlen() on +the NULL pointer. + +While other strings like 'upstream_sfp_name' might be checked before +access in certain code paths, failing to handle these allocations +consistently can lead to incomplete data reporting or hidden bugs. + +Fix this by adding proper NULL checks for all kstrdup() calls in +phy_prepare_data() and implement a centralized error handling path +using goto labels to ensure all previously allocated resources are +freed on failure. + +Fixes: 9dd2ad5e92b9 ("net: ethtool: phy: Convert the PHY_GET command to generic phy dump") +Signed-off-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260507131738.1173835-1-2022090917019@std.uestc.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/phy.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/net/ethtool/phy.c b/net/ethtool/phy.c +index 68372bef4b2fe..cb1e0aea450f9 100644 +--- a/net/ethtool/phy.c ++++ b/net/ethtool/phy.c +@@ -76,6 +76,7 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + struct nlattr **tb = info->attrs; + struct phy_device_node *pdn; + struct phy_device *phydev; ++ int ret; + + /* RTNL is held by the caller */ + phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PHY_HEADER, +@@ -88,8 +89,17 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + return -EOPNOTSUPP; + + rep_data->phyindex = phydev->phyindex; ++ + rep_data->name = kstrdup(dev_name(&phydev->mdio.dev), GFP_KERNEL); ++ if (!rep_data->name) ++ return -ENOMEM; ++ + rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL); ++ if (!rep_data->drvname) { ++ ret = -ENOMEM; ++ goto err_free_name; ++ } ++ + rep_data->upstream_type = pdn->upstream_type; + + if (pdn->upstream_type == PHY_UPSTREAM_PHY) { +@@ -97,15 +107,33 @@ static int phy_prepare_data(const struct ethnl_req_info *req_info, + rep_data->upstream_index = upstream->phyindex; + } + +- if (pdn->parent_sfp_bus) ++ if (pdn->parent_sfp_bus) { + rep_data->upstream_sfp_name = kstrdup(sfp_get_name(pdn->parent_sfp_bus), + GFP_KERNEL); ++ if (!rep_data->upstream_sfp_name) { ++ ret = -ENOMEM; ++ goto err_free_drvname; ++ } ++ } + +- if (phydev->sfp_bus) ++ if (phydev->sfp_bus) { + rep_data->downstream_sfp_name = kstrdup(sfp_get_name(phydev->sfp_bus), + GFP_KERNEL); ++ if (!rep_data->downstream_sfp_name) { ++ ret = -ENOMEM; ++ goto err_free_upstream_sfp; ++ } ++ } + + return 0; ++ ++err_free_upstream_sfp: ++ kfree(rep_data->upstream_sfp_name); ++err_free_drvname: ++ kfree(rep_data->drvname); ++err_free_name: ++ kfree(rep_data->name); ++ return ret; + } + + static int phy_fill_reply(struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-7.0/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch b/queue-7.0/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch new file mode 100644 index 0000000000..bbb1af1cb7 --- /dev/null +++ b/queue-7.0/net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch @@ -0,0 +1,52 @@ +From cc3344ad185fc6d00e3ed887daf95750811c14b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:26 +0800 +Subject: net: hamradio: bpqether: validate frame length in bpq_rcv() + +From: Mashiro Chen + +[ Upstream commit 6183bd8723a3eecd2d89cbc506fe938bc6288345 ] + +The BPQ length field is decoded as: + + len = skb->data[0] + skb->data[1] * 256 - 5; + +If the sender sets bytes [0..1] to values whose combined value is +less than 5, len becomes negative. Passing a negative int to +skb_trim() silently converts to a huge unsigned value, causing the +function to be a no-op. The frame is then passed up to AX.25 with +its original (untrimmed) payload, delivering garbage beyond the +declared frame boundary. + +Additionally, a negative len corrupts the 64-bit rx_bytes counter +through implicit sign-extension. + +Add a bounds check before pulling the length bytes: reject frames +where len is negative or exceeds the remaining skb data. + +Acked-by: Joerg Reuter +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260409024927.24397-2-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/bpqether.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c +index 045c5177262ea..214fd1f819a1b 100644 +--- a/drivers/net/hamradio/bpqether.c ++++ b/drivers/net/hamradio/bpqether.c +@@ -187,6 +187,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty + + len = skb->data[0] + skb->data[1] * 256 - 5; + ++ if (len < 0 || len > skb->len - 2) ++ goto drop_unlock; ++ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ + +-- +2.53.0 + diff --git a/queue-7.0/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch b/queue-7.0/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch new file mode 100644 index 0000000000..00c2380b79 --- /dev/null +++ b/queue-7.0/net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch @@ -0,0 +1,48 @@ +From 85e8328de8e1f538c96e7a7332d4180a7b5ca6ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:49:27 +0800 +Subject: net: hamradio: scc: validate bufsize in SIOCSCCSMEM ioctl + +From: Mashiro Chen + +[ Upstream commit 8263e484d6622464ec72a5ad563f62492d84fa54 ] + +The SIOCSCCSMEM ioctl copies a scc_mem_config from user space and +assigns its bufsize field directly to scc->stat.bufsize without any +range validation: + + scc->stat.bufsize = memcfg.bufsize; + +If a privileged user (CAP_SYS_RAWIO) sets bufsize to 0, the receive +interrupt handler later calls dev_alloc_skb(0) and immediately writes +a KISS type byte via skb_put_u8() into a zero-capacity socket buffer, +corrupting the adjacent skb_shared_info region. + +Reject bufsize values smaller than 16; this is large enough to hold +at least one KISS header byte plus useful data. + +Signed-off-by: Mashiro Chen +Acked-by: Joerg Reuter +Link: https://patch.msgid.link/20260409024927.24397-3-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/scc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c +index ae5048efde686..8569db4a71401 100644 +--- a/drivers/net/hamradio/scc.c ++++ b/drivers/net/hamradio/scc.c +@@ -1909,6 +1909,8 @@ static int scc_net_siocdevprivate(struct net_device *dev, + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg))) + return -EINVAL; ++ if (memcfg.bufsize < 16) ++ return -EINVAL; + scc->stat.bufsize = memcfg.bufsize; + return 0; + +-- +2.53.0 + diff --git a/queue-7.0/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch b/queue-7.0/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch new file mode 100644 index 0000000000..71bb8723cd --- /dev/null +++ b/queue-7.0/net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch @@ -0,0 +1,49 @@ +From 145a87793394192da0c2be2ed124cf62b72eefc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 14:39:29 +0200 +Subject: net: hsr: emit notification for PRP slave2 changed hw addr on port + deletion + +From: Fernando Fernandez Mancera + +[ Upstream commit 2ce8a41113eda1adddc1e6dc43cf89383ec6dc22 ] + +On PRP protocol, when deleting the port the MAC address change +notification was missing. In addition to that, make sure to only perform +the MAC address change on slave2 deletion and PRP protocol as the +operation isn't necessary for HSR nor slave1. + +Note that the eth_hw_addr_set() is correct on PRP context as the slaves +are either in promiscuous mode or forward offload enabled. + +Reported-by: Luka Gejak +Closes: https://lore.kernel.org/netdev/DHFCZEM93FTT.1RWFBIE32K7OT@linux.dev/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Felix Maurer +Link: https://patch.msgid.link/20260403123928.4249-2-fmancera@suse.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_slave.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c +index 44f83c8c56a79..d9af9e65f72f0 100644 +--- a/net/hsr/hsr_slave.c ++++ b/net/hsr/hsr_slave.c +@@ -243,7 +243,11 @@ void hsr_del_port(struct hsr_port *port) + if (!port->hsr->fwd_offloaded) + dev_set_promiscuity(port->dev, -1); + netdev_upper_dev_unlink(port->dev, master->dev); +- eth_hw_addr_set(port->dev, port->original_macaddress); ++ if (hsr->prot_version == PRP_V1 && ++ port->type == HSR_PT_SLAVE_B) { ++ eth_hw_addr_set(port->dev, port->original_macaddress); ++ call_netdevice_notifiers(NETDEV_CHANGEADDR, port->dev); ++ } + } + + kfree_rcu(port, rcu); +-- +2.53.0 + diff --git a/queue-7.0/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch b/queue-7.0/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch new file mode 100644 index 0000000000..e90d02d076 --- /dev/null +++ b/queue-7.0/net-initialize-sk_rx_queue_mapping-in-sk_clone.patch @@ -0,0 +1,92 @@ +From 5afd7d5dcaf801ac84c1988068b4acd810f489b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:42:18 +0800 +Subject: net: initialize sk_rx_queue_mapping in sk_clone() + +From: Jiayuan Chen + +[ Upstream commit 1a6b3965385a935ffd70275d162f68139bd86898 ] + +sk_clone() initializes sk_tx_queue_mapping via sk_tx_queue_clear() +but does not initialize sk_rx_queue_mapping. Since this field is in +the sk_dontcopy region, it is neither copied from the parent socket +by sock_copy() nor zeroed by sk_prot_alloc() (called without +__GFP_ZERO from sk_clone). + +Commit 03cfda4fa6ea ("tcp: fix another uninit-value +(sk_rx_queue_mapping)") attempted to fix this by introducing +sk_mark_napi_id_set() with force_set=true in tcp_child_process(). +However, sk_mark_napi_id_set() -> sk_rx_queue_set() only writes +when skb_rx_queue_recorded(skb) is true. If the 3-way handshake +ACK arrives through a device that does not record rx_queue (e.g. +loopback or veth), sk_rx_queue_mapping remains uninitialized. + +When a subsequent data packet arrives with a recorded rx_queue, +sk_mark_napi_id() -> sk_rx_queue_update() reads the uninitialized +field for comparison (force_set=false path), triggering KMSAN. + +This was reproduced by establishing a TCP connection over loopback +(which does not call skb_record_rx_queue), then attaching a BPF TC +program on lo ingress to set skb->queue_mapping on data packets: + +BUG: KMSAN: uninit-value in tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1875) + tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2287) + ip_protocol_deliver_rcu (net/ipv4/ip_input.c:207) + ip_local_deliver_finish (net/ipv4/ip_input.c:242) + ip_local_deliver (net/ipv4/ip_input.c:262) + ip_rcv (net/ipv4/ip_input.c:573) + __netif_receive_skb (net/core/dev.c:6294) + process_backlog (net/core/dev.c:6646) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7929) + handle_softirqs (kernel/softirq.c:623) + do_softirq (kernel/softirq.c:523) + __local_bh_enable_ip (kernel/softirq.c:?) + __dev_queue_xmit (net/core/dev.c:?) + ip_finish_output2 (net/ipv4/ip_output.c:237) + ip_output (net/ipv4/ip_output.c:438) + __ip_queue_xmit (net/ipv4/ip_output.c:534) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1693) + tcp_write_xmit (net/ipv4/tcp_output.c:3064) + tcp_sendmsg_locked (net/ipv4/tcp.c:?) + tcp_sendmsg (net/ipv4/tcp.c:1465) + inet_sendmsg (net/ipv4/af_inet.c:865) + sock_write_iter (net/socket.c:1195) + vfs_write (fs/read_write.c:688) + ... +Uninit was created at: + kmem_cache_alloc_noprof (mm/slub.c:4873) + sk_prot_alloc (net/core/sock.c:2239) + sk_alloc (net/core/sock.c:2301) + inet_create (net/ipv4/af_inet.c:334) + __sock_create (net/socket.c:1605) + __sys_socket (net/socket.c:1747) + +Fix this at the root by adding sk_rx_queue_clear() alongside +sk_tx_queue_clear() in sk_clone(). + +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260407084219.95718-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 5976100a9d55a..a12c5eca88f2c 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2583,6 +2583,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority, + + sk_set_socket(newsk, NULL); + sk_tx_queue_clear(newsk); ++ sk_rx_queue_clear(newsk); + RCU_INIT_POINTER(newsk->sk_wq, NULL); + + if (newsk->sk_prot->sockets_allocated) +-- +2.53.0 + diff --git a/queue-7.0/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch b/queue-7.0/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch new file mode 100644 index 0000000000..4e51199c72 --- /dev/null +++ b/queue-7.0/net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch @@ -0,0 +1,82 @@ +From 1167f170eae11db84d191f758410ae40c99bdf0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 12:02:28 +0530 +Subject: net: lan743x: fix SGMII detection on PCI1xxxx B0+ during warm reset + +From: Thangaraj Samynathan + +[ Upstream commit e783e40fb689381caca31e03d28c39e10c82e722 ] + +A warm reset on boards using an EEPROM-only strap configuration (where +no MAC address is set in the image) can cause the driver to incorrectly +revert to RGMII mode. This occurs because the ENET_CONFIG_LOAD_STARTED +bit may not persist or behave as expected. + +Update pci11x1x_strap_get_status() to use revision-specific validation: + +- For PCI11x1x A0: Continue using the legacy check (config load started + or reset protection) to validate the SGMII strap. +- For PCI11x1x B0 and later: Use the newly available + STRAP_READ_USE_SGMII_EN_ bit in the upper strap register to validate + the lower SGMII_EN bit. + +This ensures the SGMII interface is correctly identified even after a +warm reboot. + +Signed-off-by: Thangaraj Samynathan +Link: https://patch.msgid.link/20260318063228.17110-1-thangaraj.s@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 15 +++++++++++---- + drivers/net/ethernet/microchip/lan743x_main.h | 1 + + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index f0b5dd752f084..b4cabde6625a2 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -28,6 +28,12 @@ + + #define RFE_RD_FIFO_TH_3_DWORDS 0x3 + ++static bool pci11x1x_is_a0(struct lan743x_adapter *adapter) ++{ ++ u32 dev_rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_; ++ return dev_rev == ID_REV_CHIP_REV_PCI11X1X_A0_; ++} ++ + static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + { + u32 chip_rev; +@@ -47,10 +53,11 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter) + cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG); + lan743x_hs_syslock_release(adapter); + hw_cfg = lan743x_csr_read(adapter, HW_CFG); +- +- if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || +- hw_cfg & HW_CFG_RST_PROTECT_) { +- strap = lan743x_csr_read(adapter, STRAP_READ); ++ strap = lan743x_csr_read(adapter, STRAP_READ); ++ if ((pci11x1x_is_a0(adapter) && ++ (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ || ++ hw_cfg & HW_CFG_RST_PROTECT_)) || ++ (strap & STRAP_READ_USE_SGMII_EN_)) { + if (strap & STRAP_READ_SGMII_EN_) + adapter->is_sgmii_en = true; + else +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index 02a28b7091630..160d94a7cee66 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -27,6 +27,7 @@ + #define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) + #define ID_REV_CHIP_REV_A0_ (0x00000000) + #define ID_REV_CHIP_REV_B0_ (0x00000010) ++#define ID_REV_CHIP_REV_PCI11X1X_A0_ (0x000000A0) + #define ID_REV_CHIP_REV_PCI11X1X_B0_ (0x000000B0) + + #define FPGA_REV (0x04) +-- +2.53.0 + diff --git a/queue-7.0/net-lan966x-avoid-unregistering-netdev-on-register-f.patch b/queue-7.0/net-lan966x-avoid-unregistering-netdev-on-register-f.patch new file mode 100644 index 0000000000..886e75cadf --- /dev/null +++ b/queue-7.0/net-lan966x-avoid-unregistering-netdev-on-register-f.patch @@ -0,0 +1,65 @@ +From c66a9d10f7fc51de29b0d8e16ecc27dc78520c5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 21:43:11 +0900 +Subject: net: lan966x: avoid unregistering netdev on register failure + +From: Myeonghun Pak + +[ Upstream commit c4f3d6eb1fcf6cd9ce4644f604d5aad1ce594dfc ] + +lan966x_probe_port() stores the newly allocated net_device in the +port before calling register_netdev(). If register_netdev() fails, +the probe error path calls lan966x_cleanup_ports(), which sees +port->dev and calls unregister_netdev() for a device that was never +registered. + +Destroy the phylink instance created for this port and clear port->dev +before returning the registration error. The common cleanup path now skips +ports without port->dev before reaching the registered netdev cleanup, so +it only handles ports that reached the registered-netdev lifetime. + +This also avoids treating an uninitialized FDMA netdev and the failed port +as a NULL == NULL match in the common cleanup path. + +Fixes: d28d6d2e37d1 ("net: lan966x: add port module support") +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260506124331.31945-1-mhun512@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +index 47752d3fde0b1..1179a6e127c52 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +@@ -749,11 +749,10 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) + + for (p = 0; p < lan966x->num_phys_ports; p++) { + port = lan966x->ports[p]; +- if (!port) ++ if (!port || !port->dev) + continue; + +- if (port->dev) +- unregister_netdev(port->dev); ++ unregister_netdev(port->dev); + + lan966x_xdp_port_deinit(port); + if (lan966x->fdma && lan966x->fdma_ndev == port->dev) +@@ -873,6 +872,9 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, + err = register_netdev(dev); + if (err) { + dev_err(lan966x->dev, "register_netdev failed\n"); ++ phylink_destroy(phylink); ++ port->phylink = NULL; ++ port->dev = NULL; + return err; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch b/queue-7.0/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch new file mode 100644 index 0000000000..9a6652dec7 --- /dev/null +++ b/queue-7.0/net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch @@ -0,0 +1,55 @@ +From bf253bfbf5c5436405d67c7150ede3fc8318666c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 10:30:56 -0700 +Subject: net: mana: hardening: Validate adapter_mtu from MANA_QUERY_DEV_CONFIG + +From: Erni Sri Satya Vennela + +[ Upstream commit d7709812e13d06132ddae3d21540472ea5cb11c5 ] + +As a part of MANA hardening for CVM, validate the adapter_mtu value +returned from the MANA_QUERY_DEV_CONFIG HWC command. + +The adapter_mtu value is used to compute ndev->max_mtu via: +gc->adapter_mtu - ETH_HLEN. If hardware returns a bogus adapter_mtu +smaller than ETH_HLEN (e.g. 0), the unsigned subtraction wraps to a +huge value, silently allowing oversized MTU settings. + +Add a validation check to reject adapter_mtu values below +ETH_MIN_MTU + ETH_HLEN, returning -EPROTO to fail the device +configuration early with a clear error message. + +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260326173101.2010514-1-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 14d6f68eaa695..9c26b3e841c0e 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -1214,10 +1214,16 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, + + *max_num_vports = resp.max_num_vports; + +- if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) ++ if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) { ++ if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { ++ dev_err(dev, "Adapter MTU too small: %u\n", ++ resp.adapter_mtu); ++ return -EPROTO; ++ } + gc->adapter_mtu = resp.adapter_mtu; +- else ++ } else { + gc->adapter_mtu = ETH_FRAME_LEN; ++ } + + if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V3) + *bm_hostmode = resp.bm_hostmode; +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch b/queue-7.0/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch new file mode 100644 index 0000000000..d82800be06 --- /dev/null +++ b/queue-7.0/net-mlx5e-xsk-increase-size-for-chunk_size-param.patch @@ -0,0 +1,41 @@ +From 2fcf7513781b7cb733e0609dc600ab6a1a6bf238 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 12:09:23 +0300 +Subject: net/mlx5e: XSK, Increase size for chunk_size param + +From: Dragos Tatulea + +[ Upstream commit 1047e14b44edecbbab02a86514a083b8db9fde4d ] + +When 64K pages are used, chunk_size can take the 64K value +which doesn't fit in u16. This results in overflows that +are detected in mlx5e_mpwrq_log_wqe_sz(). + +Increase the type to u32 to fix this. + +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260403090927.139042-2-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/params.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +index 00617c65fe3cd..c5aaaa4ac3648 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h +@@ -8,7 +8,7 @@ + + struct mlx5e_xsk_param { + u16 headroom; +- u16 chunk_size; ++ u32 chunk_size; + bool unaligned; + }; + +-- +2.53.0 + diff --git a/queue-7.0/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch b/queue-7.0/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch new file mode 100644 index 0000000000..85915a2e05 --- /dev/null +++ b/queue-7.0/net-mvneta-support-eprobe_defer-when-reading-mac-add.patch @@ -0,0 +1,49 @@ +From 71479ffe38361c07de578c4497c1d2c69ffdcb5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 19:17:09 -0800 +Subject: net: mvneta: support EPROBE_DEFER when reading MAC address + +From: Rosen Penev + +[ Upstream commit 73a864352570fd30d942652f05bfe9340d7a2055 ] + +If nvmem loads after the ethernet driver, mac address assignments will +not take effect. of_get_ethdev_address returns EPROBE_DEFER in such a +case so we need to handle that to avoid eth_hw_addr_random. + +Add extra goto section to just free stats as they are allocated right +above. + +Signed-off-by: Rosen Penev +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260307031709.640141-1-rosenp@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvneta.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index 9ba4aef7080c0..0c061fb0ed072 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5620,6 +5620,8 @@ static int mvneta_probe(struct platform_device *pdev) + } + + err = of_get_ethdev_address(dn, dev); ++ if (err == -EPROBE_DEFER) ++ goto err_free_stats; + if (!err) { + mac_from = "device tree"; + } else { +@@ -5755,6 +5757,7 @@ static int mvneta_probe(struct platform_device *pdev) + 1 << pp->id); + mvneta_bm_put(pp->bm_priv); + } ++err_free_stats: + free_percpu(pp->stats); + err_free_ports: + free_percpu(pp->ports); +-- +2.53.0 + diff --git a/queue-7.0/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch b/queue-7.0/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch new file mode 100644 index 0000000000..cf91b5ec8f --- /dev/null +++ b/queue-7.0/net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch @@ -0,0 +1,95 @@ +From ab3c662c94a4f67a52b6c4678ae981c242be0f32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 09:08:08 +0000 +Subject: net: napi: Avoid gro timer misfiring at end of busypoll + +From: Dragos Tatulea + +[ Upstream commit 58e2330bd45572a6e3d46ea94cf7a9641f43591a ] + +When in irq deferral mode (defer-hard-irqs > 0), a short enough +gro-flush timeout can trigger before NAPI_STATE_SCHED is cleared if the +last poll in busy_poll_stop() takes too long. This can have the effect +of leaving the queue stuck with interrupts disabled and no timer armed +which results in a tx timeout if there is no subsequent busypoll cycle. + +To prevent this, defer the gro-flush timer arm after the last poll. + +Fixes: 7fd3253a7de6 ("net: Introduce preferred busy-polling") +Co-developed-by: Martin Karsten +Signed-off-by: Martin Karsten +Signed-off-by: Dragos Tatulea +Reviewed-by: Tariq Toukan +Reviewed-by: Cosmin Ratiu +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260506090808.820559-2-dtatulea@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index e4fcf09ba2beb..fab5a0bebd924 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6855,9 +6855,9 @@ static void skb_defer_free_flush(void) + + #if defined(CONFIG_NET_RX_BUSY_POLL) + +-static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule) ++static void __busy_poll_stop(struct napi_struct *napi, unsigned long timeout) + { +- if (!skip_schedule) { ++ if (!timeout) { + gro_normal_list(&napi->gro); + __napi_schedule(napi); + return; +@@ -6867,6 +6867,8 @@ static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule) + gro_flush_normal(&napi->gro, HZ >= 1000); + + clear_bit(NAPI_STATE_SCHED, &napi->state); ++ hrtimer_start(&napi->timer, ns_to_ktime(timeout), ++ HRTIMER_MODE_REL_PINNED); + } + + enum { +@@ -6878,8 +6880,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + unsigned flags, u16 budget) + { + struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx; +- bool skip_schedule = false; +- unsigned long timeout; ++ unsigned long timeout = 0; + int rc; + + /* Busy polling means there is a high chance device driver hard irq +@@ -6899,10 +6900,12 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + + if (flags & NAPI_F_PREFER_BUSY_POLL) { + napi->defer_hard_irqs_count = napi_get_defer_hard_irqs(napi); +- timeout = napi_get_gro_flush_timeout(napi); +- if (napi->defer_hard_irqs_count && timeout) { +- hrtimer_start(&napi->timer, ns_to_ktime(timeout), HRTIMER_MODE_REL_PINNED); +- skip_schedule = true; ++ if (napi->defer_hard_irqs_count) { ++ /* A short enough gro flush timeout and long enough ++ * poll can result in timer firing too early. ++ * Timer will be armed later if necessary. ++ */ ++ timeout = napi_get_gro_flush_timeout(napi); + } + } + +@@ -6917,7 +6920,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, + trace_napi_poll(napi, rc, budget); + netpoll_poll_unlock(have_poll_lock); + if (rc == budget) +- __busy_poll_stop(napi, skip_schedule); ++ __busy_poll_stop(napi, timeout); + bpf_net_ctx_clear(bpf_net_ctx); + local_bh_enable(); + } +-- +2.53.0 + diff --git a/queue-7.0/net-phy-dp83tc811-add-reading-of-abilities.patch b/queue-7.0/net-phy-dp83tc811-add-reading-of-abilities.patch new file mode 100644 index 0000000000..ecdf9b9249 --- /dev/null +++ b/queue-7.0/net-phy-dp83tc811-add-reading-of-abilities.patch @@ -0,0 +1,40 @@ +From 1ded8341bc771dbebd203fc9a74ab25835d48ea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 09:19:47 +0200 +Subject: net: phy: DP83TC811: add reading of abilities + +From: Sven Schuchmann + +[ Upstream commit c78bdba7b9666020c0832150a4fc4c0aebc7c6ac ] + +At this time the driver is not listing any speeds +it supports. This should be ETHTOOL_LINK_MODE_100baseT1_Full_BIT +for DP83TC811. Add the missing call for phylib to read the abilities. + +Fixes: b753a9faaf9a ("net: phy: DP83TC811: Introduce support for the DP83TC811 phy") +Suggested-by: Andrew Lunn +Signed-off-by: Sven Schuchmann +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260512071949.6218-1-schuchmann@schleissheimer.de +[pabeni@redhat.com: dropped revision history] +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83tc811.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c +index e480c2a074505..252fb12b3e68e 100644 +--- a/drivers/net/phy/dp83tc811.c ++++ b/drivers/net/phy/dp83tc811.c +@@ -393,6 +393,7 @@ static struct phy_driver dp83811_driver[] = { + .config_init = dp83811_config_init, + .config_aneg = dp83811_config_aneg, + .soft_reset = dp83811_phy_reset, ++ .get_features = genphy_c45_pma_read_ext_abilities, + .get_wol = dp83811_get_wol, + .set_wol = dp83811_set_wol, + .config_intr = dp83811_config_intr, +-- +2.53.0 + diff --git a/queue-7.0/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch b/queue-7.0/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch new file mode 100644 index 0000000000..e9cf8cedbf --- /dev/null +++ b/queue-7.0/net-qrtr-fix-endian-handling-of-confirm_rx-field.patch @@ -0,0 +1,55 @@ +From 3c008a05ab92a57a0642529aa1142a882d01a549 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 08:17:52 +0100 +Subject: net: qrtr: fix endian handling of confirm_rx field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alexander Wilhelm + +[ Upstream commit e4cf6087cab382c7031e6b436ec55202fa9f2d7b ] + +Convert confirm_rx to little endian when enqueueing and convert it back on +receive. This fixes control flow on big endian hosts, little endian is +unaffected. + +On transmit, store confirm_rx as __le32 using cpu_to_le32(). On receive, +apply le32_to_cpu() before using the value. !! ensures the value is 0 or 1 +in native endianness, so the conversion isn’t strictly required here, but +it is kept for consistency and clarity. + +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Alexander Wilhelm +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index d77e9c8212da5..7cec6a7859b03 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -361,7 +361,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, + } + + hdr->size = cpu_to_le32(len); +- hdr->confirm_rx = !!confirm_rx; ++ hdr->confirm_rx = cpu_to_le32(!!confirm_rx); + + rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); + +@@ -462,7 +462,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) + cb->type = le32_to_cpu(v1->type); + cb->src_node = le32_to_cpu(v1->src_node_id); + cb->src_port = le32_to_cpu(v1->src_port_id); +- cb->confirm_rx = !!v1->confirm_rx; ++ cb->confirm_rx = !!le32_to_cpu(v1->confirm_rx); + cb->dst_node = le32_to_cpu(v1->dst_node_id); + cb->dst_port = le32_to_cpu(v1->dst_port_id); + +-- +2.53.0 + diff --git a/queue-7.0/net-rose-reject-truncated-clear_request-frames-in-st.patch b/queue-7.0/net-rose-reject-truncated-clear_request-frames-in-st.patch new file mode 100644 index 0000000000..7ac190ad41 --- /dev/null +++ b/queue-7.0/net-rose-reject-truncated-clear_request-frames-in-st.patch @@ -0,0 +1,57 @@ +From 7ca78ae0ff398721f433e7ef2adbe5b576724a1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 01:25:51 +0800 +Subject: net: rose: reject truncated CLEAR_REQUEST frames in state machines + +From: Mashiro Chen + +[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ] + +All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST +by reading the cause and diagnostic bytes directly from skb->data[3] +and skb->data[4] without verifying that the frame is long enough: + + rose_disconnect(sk, ..., skb->data[3], skb->data[4]); + +The entry-point check in rose_route_frame() only enforces +ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can +send a syntactically valid but truncated CLEAR_REQUEST (3 or 4 +bytes) while a connection is open in any state. Processing such a +frame causes a one- or two-byte out-of-bounds read past the skb +data, leaking uninitialized heap content as the cause/diagnostic +values returned to user space via getsockopt(ROSE_GETCAUSE). + +Add a single length check at the rose_process_rx_frame() dispatch +point, before any state machine is entered, to drop frames that +carry the CLEAR_REQUEST type code but are too short to contain the +required cause and diagnostic fields. + +Signed-off-by: Mashiro Chen +Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rose/rose_in.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 0276b393f0e53..e268005819627 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -271,6 +271,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) + + frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); + ++ /* ++ * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4. ++ * Reject a malformed frame that is too short to contain them. ++ */ ++ if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5) ++ return 0; ++ + switch (rose->state) { + case ROSE_STATE_1: + queued = rose_state1_machine(sk, skb, frametype); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch b/queue-7.0/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch new file mode 100644 index 0000000000..12bedde081 --- /dev/null +++ b/queue-7.0/net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch @@ -0,0 +1,58 @@ +From f5404dd65c814dc8528e5d9f5329cc67c3bf1333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 20:39:16 +0800 +Subject: net: sched: cls_u32: Avoid memcpy() false-positive warning in + u32_init_knode() + +From: Jiayuan Chen + +[ Upstream commit 34bd3c6b0bd383a76d987c8c45c4f309b681b255 ] + +Syzbot reported a warning in u32_init_knode() [1]. + +Similar to commit 7cba18332e36 ("net: sched: cls_u32: Avoid memcpy() +false-positive warning") which addressed the same issue in u32_change(), +use unsafe_memcpy() in u32_init_knode() to work around the compiler's +inability to see into composite flexible array structs. + +This silences the false-positive reported by syzbot: + + memcpy: detected field-spanning write (size 32) of single field + "&new->sel" at net/sched/cls_u32.c:855 (size 16) + +Since the memory is correctly allocated with kzalloc_flex() using +s->nkeys, this is purely a false positive and does not need a Fixes tag. + +[1] https://syzkaller.appspot.com/bug?extid=d5ace703ed883df56e42 + +Reported-by: syzbot+d5ace703ed883df56e42@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69a811b9.a70a0220.b118c.0019.GAE@google.com/T/ +Reviewed-by: Simon Horman +Acked-by: Gustavo A. R. Silva +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260309123917.402183-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_u32.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 9241c025aa741..8f30cc82181d9 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -852,7 +852,10 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp, + /* Similarly success statistics must be moved as pointers */ + new->pcpu_success = n->pcpu_success; + #endif +- memcpy(&new->sel, s, struct_size(s, keys, s->nkeys)); ++ unsafe_memcpy(&new->sel, s, struct_size(s, keys, s->nkeys), ++ /* A composite flex-array structure destination, ++ * which was correctly sized with kzalloc_flex(), ++ * above. */); + + if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) { + kfree(new); +-- +2.53.0 + diff --git a/queue-7.0/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch b/queue-7.0/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch new file mode 100644 index 0000000000..89608d8239 --- /dev/null +++ b/queue-7.0/net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch @@ -0,0 +1,57 @@ +From 92db9e17b9837a5a067c2226b7f621f931759801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:11:11 +0200 +Subject: net: sfp: add quirk for ZOERAX SFP-2.5G-T + +From: Jan Hoffmann + +[ Upstream commit 911e2c050963ccf239faec6ae9dee0f5e8f1cc5c ] + +This is a 2.5G copper module which appears to be based on a Motorcomm +YT8821 PHY. There doesn't seem to be a usable way to to access the PHY +(I2C address 0x56 provides only read-only C22 access, and Rollball is +also not working). + +The module does not report the correct extended compliance code for +2.5GBase-T, and instead claims to support SONET OC-48 and Fibre Channel: + + Identifier : 0x03 (SFP) + Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID) + Connector : 0x07 (LC) + Transceiver codes : 0x00 0x01 0x00 0x00 0x40 0x40 0x04 0x00 0x00 + Transceiver type : FC: Multimode, 50um (M5) + Encoding : 0x05 (SONET Scrambled) + BR Nominal : 2500MBd + +Despite this, the kernel still enables the correct 2500Base-X interface +mode. However, for the module to actually work, it is also necessary to +disable inband auto-negotiation. + +Enable the existing "sfp_quirk_oem_2_5g" for this module, which handles +that and also sets the bit for 2500Base-T link mode. + +Signed-off-by: Jan Hoffmann +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260329191304.720160-1-jan@3e8.eu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/sfp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index 6b7b8ae15d106..bd970f753beb6 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -588,6 +588,8 @@ static const struct sfp_quirk sfp_quirks[] = { + SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), + SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball), ++ ++ SFP_QUIRK_S("ZOERAX", "SFP-2.5G-T", sfp_quirk_oem_2_5g), + }; + + static size_t sfp_strlen(const char *str, size_t maxlen) +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch b/queue-7.0/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch new file mode 100644 index 0000000000..1927e63aae --- /dev/null +++ b/queue-7.0/net-shaper-enforce-singleton-netdev-scope-with-id-0.patch @@ -0,0 +1,46 @@ +From 1c9ea2a1e96faa9ca124fd8f0760d42777a5f3dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:03 -0700 +Subject: net: shaper: enforce singleton NETDEV scope with id 0 + +From: Jakub Kicinski + +[ Upstream commit b62b29e6de6711f5918940aa6ff2bbab6d6af502 ] + +The NETDEV scope represents a singleton root shaper in the per-device +hierarchy. All code assumes NETDEV shapers have id 0: +net_shaper_default_parent() hardcodes parent->id = 0 when returning +the NETDEV parent for QUEUE/NODE children, and the UAPI documentation +describes NETDEV scope as "the main shaper" (singular, not plural). + +Make sure we reject non-0 IDs. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-10-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index eb049847fed65..4ae3ee6764a0a 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -482,6 +482,12 @@ static int net_shaper_parse_handle(const struct nlattr *attr, + else if (handle->scope == NET_SHAPER_SCOPE_NODE) + id = NET_SHAPER_ID_UNSPEC; + ++ if (id && handle->scope == NET_SHAPER_SCOPE_NETDEV) { ++ NL_SET_ERR_MSG_ATTR(info->extack, id_attr, ++ "Netdev scope is a singleton, must use ID 0"); ++ return -EINVAL; ++ } ++ + handle->id = id; + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch b/queue-7.0/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch new file mode 100644 index 0000000000..1b104a497e --- /dev/null +++ b/queue-7.0/net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch @@ -0,0 +1,60 @@ +From 57c8412c5e007d6feb3f5a405e7a98c7ac1b1197 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:56 -0700 +Subject: net: shaper: fix trivial ordering issue in net_shaper_commit() + +From: Jakub Kicinski + +[ Upstream commit 235fb5376139c3419f2218349f1fa2f06f24f7ad ] + +We should update the entry before we mark it as valid. + +Fixes: 93954b40f6a4 ("net-shapers: implement NL set and delete operations") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index d2b8f1f951b19..86319ddbf2905 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -295,6 +295,10 @@ net_shaper_lookup(struct net_shaper_binding *binding, + NET_SHAPER_VALID)) + return NULL; + ++ /* Pairs with smp_wmb() in net_shaper_commit(): if the entry is ++ * valid, its contents must be visible too. ++ */ ++ smp_rmb(); + return xa_load(&hierarchy->shapers, index); + } + +@@ -412,8 +416,9 @@ static void net_shaper_commit(struct net_shaper_binding *binding, + /* Successful update: drop the tentative mark + * and update the hierarchy container. + */ +- __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + *cur = shapers[i]; ++ smp_wmb(); ++ __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + } + xa_unlock(&hierarchy->shapers); + } +@@ -837,6 +842,10 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb, + for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, + U32_MAX, NET_SHAPER_VALID)); + ctx->start_index++) { ++ /* Pairs with smp_wmb() in net_shaper_commit(): the entry ++ * is marked VALID, so its contents must be visible too. ++ */ ++ smp_rmb(); + ret = net_shaper_fill_one(skb, binding, shaper, info); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch b/queue-7.0/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch new file mode 100644 index 0000000000..a5ba8056b7 --- /dev/null +++ b/queue-7.0/net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch @@ -0,0 +1,72 @@ +From 543be1f170b5279b95cd5f119430bd896ca9ecd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:00 -0700 +Subject: net: shaper: fix undersized reply skb allocation in GROUP command + +From: Jakub Kicinski + +[ Upstream commit 0f9a857e34d0f8c018a3e4435c6f0e92e8d2f38c ] + +net_shaper_group_send_reply() writes both the NET_SHAPER_A_IFINDEX +attribute (via net_shaper_fill_binding()) and the nested +NET_SHAPER_A_HANDLE attribute (via net_shaper_fill_handle()), but +the reply skb at the call site in net_shaper_nl_group_doit() is +allocated using net_shaper_handle_size(), which only accounts for +the nested handle. + +The allocation is therefore short by nla_total_size(sizeof(u32)) +(8 bytes) for the IFINDEX attribute. In practice the slab allocator +rounds up the small allocation so the bug is latent, but the size +accounting is wrong and could bite if the reply grew further. + +Introduce net_shaper_group_reply_size() that accounts for the full +reply payload and use it both at the genlmsg_new() call site and in +the defensive WARN_ONCE message. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-7-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 12e5e0c18643b..08fde2d9e8aa8 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -90,6 +90,12 @@ static int net_shaper_handle_size(void) + nla_total_size(sizeof(u32))); + } + ++static int net_shaper_group_reply_size(void) ++{ ++ return nla_total_size(sizeof(u32)) + /* NET_SHAPER_A_IFINDEX */ ++ net_shaper_handle_size(); /* NET_SHAPER_A_HANDLE */ ++} ++ + static int net_shaper_fill_binding(struct sk_buff *msg, + const struct net_shaper_binding *binding, + u32 type) +@@ -1227,7 +1233,7 @@ static int net_shaper_group_send_reply(struct net_shaper_binding *binding, + free_msg: + /* Should never happen as msg is pre-allocated with enough space. */ + WARN_ONCE(true, "calculated message payload length (%d)", +- net_shaper_handle_size()); ++ net_shaper_group_reply_size()); + nlmsg_free(msg); + return -EMSGSIZE; + } +@@ -1275,7 +1281,7 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + /* Prepare the msg reply in advance, to avoid device operation + * rollback on allocation failure. + */ +- msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL); ++ msg = genlmsg_new(net_shaper_group_reply_size(), GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto free_leaves; +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-flip-the-polarity-of-the-valid-flag.patch b/queue-7.0/net-shaper-flip-the-polarity-of-the-valid-flag.patch new file mode 100644 index 0000000000..e74a586d49 --- /dev/null +++ b/queue-7.0/net-shaper-flip-the-polarity-of-the-valid-flag.patch @@ -0,0 +1,112 @@ +From fc4a8218180fa4f538354e8a0a178891634ae452 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:55 -0700 +Subject: net: shaper: flip the polarity of the valid flag + +From: Jakub Kicinski + +[ Upstream commit 7cee43fcb0c3f71441d2faaa8c2202b6a88b6bef ] + +The usual way of inserting entries which are not yet fully ready +into XArray is to have a VALID flag. The shaper code has a NOT_VALID +flag. Since XArray code does not let us create entries with marks +already set - the creation of entries is currently not atomic. + +Flip the polarity of the VALID flag. This closes the tiny race +in net_shaper_pre_insert() of entries being created without +the NOT_VALID flag. + +Fixes: 93954b40f6a4 ("net-shapers: implement NL set and delete operations") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 1069fa4eb9f60..d2b8f1f951b19 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -275,11 +275,13 @@ static void net_shaper_default_parent(const struct net_shaper_handle *handle, + parent->id = 0; + } + +-/* +- * MARK_0 is already in use due to XA_FLAGS_ALLOC, can't reuse such flag as +- * it's cleared by xa_store(). ++/* MARK_0 is already in use due to XA_FLAGS_ALLOC. The VALID mark is set on ++ * an entry only after the device-side configuration has completed ++ * successfully (see net_shaper_commit()). Lookups and dumps must filter on ++ * this mark to avoid exposing tentative entries inserted by ++ * net_shaper_pre_insert() while the driver call is still in flight. + */ +-#define NET_SHAPER_NOT_VALID XA_MARK_1 ++#define NET_SHAPER_VALID XA_MARK_1 + + static struct net_shaper * + net_shaper_lookup(struct net_shaper_binding *binding, +@@ -289,8 +291,8 @@ net_shaper_lookup(struct net_shaper_binding *binding, + struct net_shaper_hierarchy *hierarchy; + + hierarchy = net_shaper_hierarchy_rcu(binding); +- if (!hierarchy || xa_get_mark(&hierarchy->shapers, index, +- NET_SHAPER_NOT_VALID)) ++ if (!hierarchy || !xa_get_mark(&hierarchy->shapers, index, ++ NET_SHAPER_VALID)) + return NULL; + + return xa_load(&hierarchy->shapers, index); +@@ -370,13 +372,10 @@ static int net_shaper_pre_insert(struct net_shaper_binding *binding, + goto free_id; + } + +- /* Mark 'tentative' shaper inside the hierarchy container. +- * xa_set_mark is a no-op if the previous store fails. ++ /* Insert as 'tentative' (no VALID mark). The mark will be set by ++ * net_shaper_commit() once the driver-side configuration succeeds. + */ +- xa_lock(&hierarchy->shapers); +- prev = __xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL); +- __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_NOT_VALID); +- xa_unlock(&hierarchy->shapers); ++ prev = xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL); + if (xa_err(prev)) { + NL_SET_ERR_MSG(extack, "Can't insert shaper into device store"); + kfree_rcu(cur, rcu); +@@ -413,8 +412,7 @@ static void net_shaper_commit(struct net_shaper_binding *binding, + /* Successful update: drop the tentative mark + * and update the hierarchy container. + */ +- __xa_clear_mark(&hierarchy->shapers, index, +- NET_SHAPER_NOT_VALID); ++ __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID); + *cur = shapers[i]; + } + xa_unlock(&hierarchy->shapers); +@@ -431,8 +429,9 @@ static void net_shaper_rollback(struct net_shaper_binding *binding) + return; + + xa_lock(&hierarchy->shapers); +- xa_for_each_marked(&hierarchy->shapers, index, cur, +- NET_SHAPER_NOT_VALID) { ++ xa_for_each(&hierarchy->shapers, index, cur) { ++ if (xa_get_mark(&hierarchy->shapers, index, NET_SHAPER_VALID)) ++ continue; + __xa_erase(&hierarchy->shapers, index); + kfree(cur); + } +@@ -836,7 +835,8 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb, + goto out_unlock; + + for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, +- U32_MAX, XA_PRESENT)); ctx->start_index++) { ++ U32_MAX, NET_SHAPER_VALID)); ++ ctx->start_index++) { + ret = net_shaper_fill_one(skb, binding, shaper, info); + if (ret) + break; +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-reject-duplicate-leaves-in-group-request.patch b/queue-7.0/net-shaper-reject-duplicate-leaves-in-group-request.patch new file mode 100644 index 0000000000..f1de5c1979 --- /dev/null +++ b/queue-7.0/net-shaper-reject-duplicate-leaves-in-group-request.patch @@ -0,0 +1,117 @@ +From b003d43c2a04a47d1a5f1acd2954b4f4296e49a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:57 -0700 +Subject: net: shaper: reject duplicate leaves in GROUP request + +From: Jakub Kicinski + +[ Upstream commit a9a2fa1da619f276580b0d4c5d12efac89e8642b ] + +net_shaper_nl_group_doit() does not deduplicate NET_SHAPER_A_LEAVES +entries. When userspace supplies the same leaf handle twice, the same +old-parent pointer lands twice in old_nodes[]. The cleanup loop double +frees the parent. Of course the same parent may still be in old_nodes[] +twice if we are moving multiple of its leaves. + +Note that this patch also implicitly fixes the fact that the +i >= leaves_count path forgets to set ret. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-4-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 60 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 45 insertions(+), 15 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 86319ddbf2905..c8960821cf236 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -941,6 +941,46 @@ static int net_shaper_handle_cmp(const struct net_shaper_handle *a, + return memcmp(a, b, sizeof(*a)); + } + ++static int net_shaper_parse_leaves(struct net_shaper_binding *binding, ++ struct genl_info *info, ++ const struct net_shaper *node, ++ struct net_shaper *leaves, ++ int leaves_count) ++{ ++ struct nlattr *attr; ++ int i, j, ret, rem; ++ ++ i = 0; ++ nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES, ++ genlmsg_data(info->genlhdr), ++ genlmsg_len(info->genlhdr), rem) { ++ if (WARN_ON_ONCE(i >= leaves_count)) ++ return -EINVAL; ++ ++ ret = net_shaper_parse_leaf(binding, attr, info, ++ node, &leaves[i]); ++ if (ret) ++ return ret; ++ ++ /* Reject duplicates */ ++ for (j = 0; j < i; j++) { ++ if (net_shaper_handle_cmp(&leaves[i].handle, ++ &leaves[j].handle)) ++ continue; ++ ++ NL_SET_ERR_MSG_ATTR_FMT(info->extack, attr, ++ "Duplicate leaf shaper %d:%d", ++ leaves[i].handle.scope, ++ leaves[i].handle.id); ++ return -EINVAL; ++ } ++ ++ i++; ++ } ++ ++ return 0; ++} ++ + static int net_shaper_parent_from_leaves(int leaves_count, + const struct net_shaper *leaves, + struct net_shaper *node, +@@ -1197,10 +1237,9 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + struct net_shaper **old_nodes, *leaves, node = {}; + struct net_shaper_hierarchy *hierarchy; + struct net_shaper_binding *binding; +- int i, ret, rem, leaves_count; ++ int i, ret, leaves_count; + int old_nodes_count = 0; + struct sk_buff *msg; +- struct nlattr *attr; + + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_LEAVES)) + return -EINVAL; +@@ -1228,19 +1267,10 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + if (ret) + goto free_leaves; + +- i = 0; +- nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES, +- genlmsg_data(info->genlhdr), +- genlmsg_len(info->genlhdr), rem) { +- if (WARN_ON_ONCE(i >= leaves_count)) +- goto free_leaves; +- +- ret = net_shaper_parse_leaf(binding, attr, info, +- &node, &leaves[i]); +- if (ret) +- goto free_leaves; +- i++; +- } ++ ret = net_shaper_parse_leaves(binding, info, &node, ++ leaves, leaves_count); ++ if (ret) ++ goto free_leaves; + + /* Prepare the msg reply in advance, to avoid device operation + * rollback on allocation failure. +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch b/queue-7.0/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch new file mode 100644 index 0000000000..f2dcb7b9a0 --- /dev/null +++ b/queue-7.0/net-shaper-reject-handle-ids-exceeding-internal-bit-.patch @@ -0,0 +1,121 @@ +From cbf21fafc1f92f2c96a75d2234965cd893b66f8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:02 -0700 +Subject: net: shaper: reject handle IDs exceeding internal bit-width + +From: Jakub Kicinski + +[ Upstream commit 8d5806c600fddb907ebe378f9c366d4b52ac3a39 ] + +net_shaper_parse_handle() reads the user-supplied handle ID via +nla_get_u32(), accepting the full u32 range. However, the xarray key +is built by net_shaper_handle_to_index() using +FIELD_PREP(NET_SHAPER_ID_MASK, handle->id), where NET_SHAPER_ID_MASK +is GENMASK(25, 0) - only 26 bits wide. FIELD_PREP silently masks off +the upper bits at runtime. A user-supplied NODE id like 0x04000123 +becomes id 0x123. + +Additionally, a user-supplied id equal to NET_SHAPER_ID_UNSPEC +(0x03FFFFFF, which is NET_SHAPER_ID_MASK itself) would collide with +the sentinel used internally by the group operation to signal +"allocate a new NODE id". + +Reject user-supplied IDs >= NET_SHAPER_ID_MASK (i.e., >= 0x03FFFFFF) +in the policy. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-9-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/net_shaper.yaml | 7 +++++++ + net/shaper/shaper.c | 4 +++- + net/shaper/shaper_nl_gen.c | 7 ++++++- + net/shaper/shaper_nl_gen.h | 2 ++ + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/Documentation/netlink/specs/net_shaper.yaml b/Documentation/netlink/specs/net_shaper.yaml +index 3f2ad772b64b1..de01f922040a5 100644 +--- a/Documentation/netlink/specs/net_shaper.yaml ++++ b/Documentation/netlink/specs/net_shaper.yaml +@@ -33,6 +33,11 @@ doc: | + @cap-get operation. + + definitions: ++ - ++ type: const ++ name: max-handle-id ++ value: 0x3fffffe ++ scope: kernel + - + type: enum + name: scope +@@ -140,6 +145,8 @@ attribute-sets: + - + name: id + type: u32 ++ checks: ++ max: max-handle-id + doc: | + Numeric identifier of a shaper. The id semantic depends on + the scope. For @queue scope it's the queue id and for @node +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 08fde2d9e8aa8..eb049847fed65 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -21,6 +21,8 @@ + + #define NET_SHAPER_ID_UNSPEC NET_SHAPER_ID_MASK + ++static_assert(NET_SHAPER_ID_UNSPEC == NET_SHAPER_MAX_HANDLE_ID + 1); ++ + struct net_shaper_hierarchy { + struct xarray shapers; + }; +@@ -360,7 +362,7 @@ static int net_shaper_pre_insert(struct net_shaper_binding *binding, + handle->id == NET_SHAPER_ID_UNSPEC) { + u32 min, max; + +- handle->id = NET_SHAPER_ID_MASK - 1; ++ handle->id = NET_SHAPER_MAX_HANDLE_ID; + max = net_shaper_handle_to_index(handle); + handle->id = 0; + min = net_shaper_handle_to_index(handle); +diff --git a/net/shaper/shaper_nl_gen.c b/net/shaper/shaper_nl_gen.c +index 9b29be3ef19a8..76eff85ec66df 100644 +--- a/net/shaper/shaper_nl_gen.c ++++ b/net/shaper/shaper_nl_gen.c +@@ -11,10 +11,15 @@ + + #include + ++/* Integer value ranges */ ++static const struct netlink_range_validation net_shaper_a_handle_id_range = { ++ .max = NET_SHAPER_MAX_HANDLE_ID, ++}; ++ + /* Common nested types */ + const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1] = { + [NET_SHAPER_A_HANDLE_SCOPE] = NLA_POLICY_MAX(NLA_U32, 3), +- [NET_SHAPER_A_HANDLE_ID] = { .type = NLA_U32, }, ++ [NET_SHAPER_A_HANDLE_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &net_shaper_a_handle_id_range), + }; + + const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1] = { +diff --git a/net/shaper/shaper_nl_gen.h b/net/shaper/shaper_nl_gen.h +index 42c46c52c7751..2406652a9014a 100644 +--- a/net/shaper/shaper_nl_gen.h ++++ b/net/shaper/shaper_nl_gen.h +@@ -12,6 +12,8 @@ + + #include + ++#define NET_SHAPER_MAX_HANDLE_ID 67108862 ++ + /* Common nested types */ + extern const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1]; + extern const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1]; +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-reject-queue-scope-handle-with-missing-id.patch b/queue-7.0/net-shaper-reject-queue-scope-handle-with-missing-id.patch new file mode 100644 index 0000000000..35b1581cd3 --- /dev/null +++ b/queue-7.0/net-shaper-reject-queue-scope-handle-with-missing-id.patch @@ -0,0 +1,55 @@ +From 5e40077ffd74c632883efb90848ca897645e1fe6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:29:04 -0700 +Subject: net: shaper: reject QUEUE scope handle with missing id + +From: Jakub Kicinski + +[ Upstream commit ce372e869f9f492f3d5aa9a0ae75ed52c61d2d6f ] + +net_shaper_parse_handle() does not enforce that the user provides +the handle ID. For NODE the ID defaults to UNSPEC for all other +cases it defaults to 0. + +For NETDEV 0 is the only option. For QUEUE defaulting to 0 makes +less intuitive sense. Specifically because the behavior should +(IMHO) be the same for all cases where there may be more than +one ID (QUEUE and NODE). + +We should either document this as intentional or reject. +I picked the latter with no strong conviction. + +Fixes: 4b623f9f0f59 ("net-shapers: implement NL get operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-11-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 4ae3ee6764a0a..b1c65110f04d3 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -477,10 +477,15 @@ static int net_shaper_parse_handle(const struct nlattr *attr, + * shaper (any other value). + */ + id_attr = tb[NET_SHAPER_A_HANDLE_ID]; +- if (id_attr) ++ if (id_attr) { + id = nla_get_u32(id_attr); +- else if (handle->scope == NET_SHAPER_SCOPE_NODE) ++ } else if (handle->scope == NET_SHAPER_SCOPE_NODE) { + id = NET_SHAPER_ID_UNSPEC; ++ } else if (handle->scope == NET_SHAPER_SCOPE_QUEUE) { ++ NL_SET_ERR_ATTR_MISS(info->extack, attr, ++ NET_SHAPER_A_HANDLE_ID); ++ return -EINVAL; ++ } + + if (id && handle->scope == NET_SHAPER_SCOPE_NETDEV) { + NL_SET_ERR_MSG_ATTR(info->extack, id_attr, +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-reject-reparenting-of-existing-nodes.patch b/queue-7.0/net-shaper-reject-reparenting-of-existing-nodes.patch new file mode 100644 index 0000000000..aad722a63f --- /dev/null +++ b/queue-7.0/net-shaper-reject-reparenting-of-existing-nodes.patch @@ -0,0 +1,90 @@ +From 7de5e28ea1e311740fdd44cb3a08d2ea4a4a6505 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 16:37:45 -0700 +Subject: net: shaper: Reject reparenting of existing nodes + +From: Mohsin Bashir + +[ Upstream commit a77d5a069d959dc45f5f472d48cba37d8cba0f1c ] + +When an existing node-scope shaper is moved to a different parent +via the group operation, the framework fails to update the leaves +count on both the old and new parent shapers. Only newly created +nodes (handle.id == NET_SHAPER_ID_UNSPEC) trigger the parent +leaves increment at line 1039. + +This causes the parent's leaves counter to diverge from the +actual number of children in the xarray. When the node is later +deleted, pre_del_node() allocates an array sized by the stale +leaves count, but the xarray iteration finds more children than +expected, hitting the WARN_ON_ONCE guard and returning -EINVAL. + +Rather than adding reparenting support with complex leaves count +bookkeeping, reject group calls that attempt to change an existing +node's parent. Updates to an existing node's rate or leaves under +the same parent remain permitted. We expect that for any modification +of the topology user should always create new groups and let the +kernel garbage collect the leaf-less nodes. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Mohsin Bashir +Link: https://patch.msgid.link/20260506233745.111895-1-mohsin.bashr@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index 94bc9c7382ea6..1069fa4eb9f60 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -964,15 +964,22 @@ static int __net_shaper_group(struct net_shaper_binding *binding, + int i, ret; + + if (node->handle.scope == NET_SHAPER_SCOPE_NODE) { ++ struct net_shaper *cur = NULL; ++ + new_node = node->handle.id == NET_SHAPER_ID_UNSPEC; + +- if (!new_node && !net_shaper_lookup(binding, &node->handle)) { +- /* The related attribute is not available when +- * reaching here from the delete() op. +- */ +- NL_SET_ERR_MSG_FMT(extack, "Node shaper %d:%d does not exists", +- node->handle.scope, node->handle.id); +- return -ENOENT; ++ if (!new_node) { ++ cur = net_shaper_lookup(binding, &node->handle); ++ if (!cur) { ++ /* The related attribute is not available ++ * when reaching here from the delete() op. ++ */ ++ NL_SET_ERR_MSG_FMT(extack, ++ "Node shaper %d:%d does not exist", ++ node->handle.scope, ++ node->handle.id); ++ return -ENOENT; ++ } + } + + /* When unspecified, the node parent scope is inherited from +@@ -986,6 +993,15 @@ static int __net_shaper_group(struct net_shaper_binding *binding, + return ret; + } + ++ if (cur && net_shaper_handle_cmp(&cur->parent, ++ &node->parent)) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "Cannot reparent node shaper %d:%d", ++ node->handle.scope, ++ node->handle.id); ++ return -EOPNOTSUPP; ++ } ++ + } else { + net_shaper_default_parent(&node->handle, &node->parent); + } +-- +2.53.0 + diff --git a/queue-7.0/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch b/queue-7.0/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch new file mode 100644 index 0000000000..ee283cc54f --- /dev/null +++ b/queue-7.0/net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch @@ -0,0 +1,41 @@ +From 6dd9e75607e0ffe66a91f90d16ebf5d0ede40089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 12:28:59 -0700 +Subject: net: shaper: set ret to -ENOMEM when genlmsg_new() fails in + group_doit + +From: Jakub Kicinski + +[ Upstream commit 8054f85b83f42a37d482fc77ea7c9ff06a9407d9 ] + +genlmsg_new() alloc failure path in net_shaper_nl_group_doit() forgets +to set ret before jumping to error handling. + +Fixes: 5d5d4700e75d ("net-shapers: implement NL group operation") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260510192904.3987113-6-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/shaper/shaper.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c +index c8960821cf236..12e5e0c18643b 100644 +--- a/net/shaper/shaper.c ++++ b/net/shaper/shaper.c +@@ -1276,8 +1276,10 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) + * rollback on allocation failure. + */ + msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL); +- if (!msg) ++ if (!msg) { ++ ret = -ENOMEM; + goto free_leaves; ++ } + + hierarchy = net_shaper_hierarchy_setup(binding); + if (!hierarchy) { +-- +2.53.0 + diff --git a/queue-7.0/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch b/queue-7.0/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch new file mode 100644 index 0000000000..8d4268526b --- /dev/null +++ b/queue-7.0/net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch @@ -0,0 +1,65 @@ +From d4828115301d46b28c180e4e781998e746d66bf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 15:26:40 -0700 +Subject: net/smc: avoid NULL deref of conn->lnk in smc_msg_event tracepoint + +From: Xiang Mei + +[ Upstream commit 7bf563badd37cb796df5477d2b78bb64148a1268 ] + +The smc_msg_event tracepoint class, shared by smc_tx_sendmsg and +smc_rx_recvmsg, unconditionally dereferences smc->conn.lnk: + + __string(name, smc->conn.lnk->ibname) + +conn->lnk is only set for SMC-R; for SMC-D it is NULL. Other code on +these paths already handles this (e.g. !conn->lnk in +SMC_STAT_RMB_TX_SIZE_SMALL()). With the tracepoint enabled, the first +sendmsg()/recvmsg() on an SMC-D socket crashes: + + Oops: general protection fault, probably for non-canonical address + KASAN: null-ptr-deref in range [...] + RIP: 0010:strlen+0x1e/0xa0 + Call Trace: + trace_event_raw_event_smc_msg_event (net/smc/smc_tracepoint.h:44) + smc_rx_recvmsg (net/smc/smc_rx.c:515) + smc_recvmsg (net/smc/af_smc.c:2859) + __sys_recvfrom (net/socket.c:2315) + __x64_sys_recvfrom (net/socket.c:2326) + do_syscall_64 + +The faulting address 0x3e0 is offsetof(struct smc_link, ibname), +confirming the NULL ->lnk deref. Enabling the tracepoint requires +root, but the trigger itself is unprivileged: socket(AF_SMC, ...) has +no capability check, and SMC-D negotiation needs no admin step on +s390 or on x86 with the loopback ISM device loaded. + +Log an empty device name for SMC-D instead of dereferencing NULL. + +Fixes: aff3083f10bf ("net/smc: Introduce tracepoints for tx and rx msg") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Dust Li +Reviewed-by: Sidraya Jayagond +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/smc/smc_tracepoint.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/smc/smc_tracepoint.h b/net/smc/smc_tracepoint.h +index a9a6e3c1113aa..53da84f57fd6f 100644 +--- a/net/smc/smc_tracepoint.h ++++ b/net/smc/smc_tracepoint.h +@@ -51,7 +51,7 @@ DECLARE_EVENT_CLASS(smc_msg_event, + __field(const void *, smc) + __field(u64, net_cookie) + __field(size_t, len) +- __string(name, smc->conn.lnk->ibname) ++ __string(name, smc->conn.lnk ? smc->conn.lnk->ibname : "") + ), + + TP_fast_assign( +-- +2.53.0 + diff --git a/queue-7.0/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch b/queue-7.0/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch new file mode 100644 index 0000000000..2ea29245cb --- /dev/null +++ b/queue-7.0/net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch @@ -0,0 +1,63 @@ +From 4cf6180902623557fd2ae84e94e95fc4aa944e30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 23:21:38 -0700 +Subject: net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot + +From: Xiang Mei + +[ Upstream commit 277740023def559a4a2ddc3e8e784ee37a0f16a9 ] + +On the SMC-D client, slot 0 of ini->ism_dev[]/ini->ism_chid[] is +reserved for an SMC-Dv1 device. smc_find_ism_v2_device_clnt() +populates V2 entries starting at index 1, so when no V1 device is +selected slot 0 is left in its kzalloc()'ed state with ism_dev[0] == +NULL and ism_chid[0] == 0. + +smc_v2_determine_accepted_chid() then matches the peer's CHID against +the array starting from index 0 using the CHID alone. A malicious +peer replying to a SMC-Dv2-only proposal with d1.chid == 0 matches +the empty slot, ini->ism_selected becomes 0, and the subsequent +ism_dev[0]->lgr_lock dereference in smc_conn_create() faults at +offsetof(struct smcd_dev, lgr_lock) == 0x68: + + BUG: KASAN: null-ptr-deref in _raw_spin_lock_bh+0x79/0xe0 + Write of size 4 at addr 0000000000000068 by task exploit/144 + Call Trace: + _raw_spin_lock_bh + smc_conn_create (net/smc/smc_core.c:1997) + __smc_connect (net/smc/af_smc.c:1447) + smc_connect (net/smc/af_smc.c:1720) + __sys_connect + __x64_sys_connect + do_syscall_64 + +Require ism_dev[i] to be non-NULL before accepting a CHID match. + +Fixes: a7c9c5f4af7f ("net/smc: CLC accept / confirm V2") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260511062138.2839584-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 1a565095376aa..f744f79112177 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1400,7 +1400,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc, + int i; + + for (i = 0; i < ini->ism_offered_cnt + 1; i++) { +- if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) { ++ if (ini->ism_dev[i] && ++ ini->ism_chid[i] == ntohs(aclc->d1.chid)) { + ini->ism_selected = i; + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch b/queue-7.0/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch new file mode 100644 index 0000000000..5f664e01f5 --- /dev/null +++ b/queue-7.0/net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch @@ -0,0 +1,39 @@ +From 80310b9a9233682ab053dcb00f3e5df277465c35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 01:28:13 +0530 +Subject: net: ti: icssm-prueth: fix eth_ports_node leak in probe + +From: Shitalkumar Gandhi + +[ Upstream commit 6635fa84403c3a59455b66007c019a7cc632db30 ] + +The error path on of_property_read_u32() failure inside +icssm_prueth_probe() returns without putting eth_ports_node, +which was acquired before the for_each_child_of_node() loop. + +Drop it before returning. + +Fixes: 511f6c1ae093 ("net: ti: icssm-prueth: Adds ICSSM Ethernet driver") +Signed-off-by: Shitalkumar Gandhi +Link: https://patch.msgid.link/20260506195813.641610-1-shitalkumar.gandhi@cambiumnetworks.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/icssm/icssm_prueth.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c +index 53bbd92909042..b7e94244355a3 100644 +--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c ++++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c +@@ -1825,6 +1825,7 @@ static int icssm_prueth_probe(struct platform_device *pdev) + dev_err(dev, "%pOF error reading port_id %d\n", + eth_node, ret); + of_node_put(eth_node); ++ of_node_put(eth_ports_node); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch b/queue-7.0/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch new file mode 100644 index 0000000000..b8f4e07925 --- /dev/null +++ b/queue-7.0/net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch @@ -0,0 +1,80 @@ +From 86833b047364ee8549fa62a2a33c9aa946c28456 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:17 -0700 +Subject: net: tls: fix off-by-one in sg_chain entry count for wrapped sk_msg + ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jakub Kicinski + +[ Upstream commit 285943c6e7ca309bbea84b253745154241d9788a ] + +When an sk_msg scatterlist ring wraps (sg.end < sg.start), +tls_push_record() chains the tail portion of the ring to the head +using sg_chain(). An extra entry in the sg array is reserved for +this: + + struct sk_msg_sg { + [...] + /* The extra two elements: + * 1) used for chaining the front and sections when the list becomes + * partitioned (e.g. end < start). The crypto APIs require the + * chaining; + * 2) to chain tailer SG entries after the message. + */ + struct scatterlist data[MAX_MSG_FRAGS + 2]; + +The current code uses MAX_SKB_FRAGS + 1 as the ring size: + + sg_chain(&msg_pl->sg.data[msg_pl->sg.start], + MAX_SKB_FRAGS - msg_pl->sg.start + 1, + msg_pl->sg.data); + +This places the chain pointer at + + sg_chain(data[start], (MAX_SKB_FRAGS - msg_start + 1) .. = + &data[start] + (MAX_SKB_FRAGS - msg_start + 1) - 1 = + data[start + (MAX_SKB_FRAGS - start + 1) - 1] = + data[MAX_SKB_FRAGS] + +instead of the true last entry. This is likely due to a "race" of +the commit under Fixes landing close to +commit 031097d9e079 ("bpf: sk_msg, zap ingress queue on psock down") + +Convert to ARRAY_SIZE and drop the data[start] / - start (as suggested +by Sabrina). + +Reported-by: 钱一铭 +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260511174920.433155-2-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 23a31646d0387..fe73c6da73392 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -800,11 +800,9 @@ static int tls_push_record(struct sock *sk, int flags, + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) { +- sg_chain(&msg_pl->sg.data[msg_pl->sg.start], +- MAX_SKB_FRAGS - msg_pl->sg.start + 1, ++ if (msg_pl->sg.end < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), + msg_pl->sg.data); +- } + + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); +-- +2.53.0 + diff --git a/queue-7.0/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch b/queue-7.0/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch new file mode 100644 index 0000000000..12539c949d --- /dev/null +++ b/queue-7.0/net-tls-prevent-chain-after-chain-in-plain-text-sg.patch @@ -0,0 +1,93 @@ +From fc4c7777002e7370dc02e6191d21ab8cbd821a61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 10:49:18 -0700 +Subject: net: tls: prevent chain-after-chain in plain text SG + +From: Jakub Kicinski + +[ Upstream commit ff26a0e8377dec07e4a7230db7675bed1b9a6d03 ] + +Sashiko points out that if end = 0 (start != 0) the current +code will create a chain link to content type right after +the wrap link: + + This would create a chain where the wrap link points directly + to another chain link. The scatterlist API sg_next iterator + does not recursively resolve consecutive chain links. + +meaning this is illegal input to crypto. + +The wrapping link is unnecessary if end = 0. end is the entry after +the last one used so end = 0 means there's nothing pushed after +the wrap: + + end start i + v v v + [ ]...[ ][ d ][ d ][ d ][ d ][rsv for wrap] + +Skip the wrapping in this case. + +TLS 1.3 can use the "wrapping slot" for it's chaining if end = 0. +This avoids the chain-after-chain. + +Move the wrap chaining before marking END and chaining off content +type, that feels like more logical ordering to me, but should not +matter from functional perspective. + +Reported-by: Sashiko +Fixes: 9aaaa56845a0 ("bpf: Sockmap/tls, skmsg can have wrapped skmsg that needs extra chaining") +Signed-off-by: Jakub Kicinski +Link: https://patch.msgid.link/20260511174920.433155-3-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls_sw.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index fe73c6da73392..97e02ac7f0086 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -789,21 +789,33 @@ static int tls_push_record(struct sock *sk, int flags, + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + ++ /* msg_pl->sg.data is a ring; data[MAX+1] is reserved for the wrap ++ * link (frags won't use it). 'i' is now the last filled entry: ++ * ++ * i end start ++ * v v v [ rsv ] ++ * [ d ][ d ][ ][ ]...[ ][ d ][ d ][ d ][chain] ++ * ^ END v ++ * `-----------------------------------------' ++ * ++ * Note that SGL does not allow chain-after-chain, so for TLS 1.3, ++ * we must make sure we don't create the wrap entry and then chain ++ * link to content_type immediately at index 0. ++ */ ++ if (i < msg_pl->sg.start) ++ sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), ++ msg_pl->sg.data); ++ + rec->content_type = record_type; + if (prot->version == TLS_1_3_VERSION) { + /* Add content type to end of message. No padding added */ + sg_set_buf(&rec->sg_content_type, &rec->content_type, 1); + sg_mark_end(&rec->sg_content_type); +- sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1, +- &rec->sg_content_type); ++ sg_chain(msg_pl->sg.data, i + 2, &rec->sg_content_type); + } else { + sg_mark_end(sk_msg_elem(msg_pl, i)); + } + +- if (msg_pl->sg.end < msg_pl->sg.start) +- sg_chain(msg_pl->sg.data, ARRAY_SIZE(msg_pl->sg.data), +- msg_pl->sg.data); +- + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, &msg_pl->sg.data[i]); + +-- +2.53.0 + diff --git a/queue-7.0/net-wangxun-reorder-timer-and-work-sync-cancellation.patch b/queue-7.0/net-wangxun-reorder-timer-and-work-sync-cancellation.patch new file mode 100644 index 0000000000..1b611e2f51 --- /dev/null +++ b/queue-7.0/net-wangxun-reorder-timer-and-work-sync-cancellation.patch @@ -0,0 +1,64 @@ +From 0e9e4f2ed5864f36bf9d3f92000d8f8f1e2bc581 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:56:13 +0800 +Subject: net: wangxun: reorder timer and work sync cancellations + +From: Jiawen Wu + +[ Upstream commit 58f6303572ec66e7c2967ac168125f444c9e880d ] + +When removing the device, timer_delete_sync(&wx->service_timer) is +called in .ndo_stop() after cancel_work_sync(&wx->service_task). This +may cause new work to be queued after device down. + +Move unregister_netdev() before cancel_work_sync(), and use +timer_shutdown_sync() to prevent the timer from being re-armed. + +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260407025616.33652-7-jiawenwu@trustnetic.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/libwx/wx_vf_common.c | 3 ++- + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c +index 5478f2fdfce88..df8b4a3727c34 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c ++++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c +@@ -48,9 +48,10 @@ void wxvf_remove(struct pci_dev *pdev) + struct wx *wx = pci_get_drvdata(pdev); + struct net_device *netdev; + +- cancel_work_sync(&wx->service_task); + netdev = wx->netdev; + unregister_netdev(netdev); ++ timer_shutdown_sync(&wx->service_timer); ++ cancel_work_sync(&wx->service_task); + kfree(wx->vfinfo); + kfree(wx->rss_key); + kfree(wx->mac_table); +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +index 54fa456fc66a7..38bfc119e58c6 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +@@ -951,12 +951,13 @@ static void txgbe_remove(struct pci_dev *pdev) + struct txgbe *txgbe = wx->priv; + struct net_device *netdev; + +- cancel_work_sync(&wx->service_task); +- + netdev = wx->netdev; + wx_disable_sriov(wx); + unregister_netdev(netdev); + ++ timer_shutdown_sync(&wx->service_timer); ++ cancel_work_sync(&wx->service_task); ++ + txgbe_remove_phy(txgbe); + wx_free_isb_resources(wx); + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-bridge-eb_tables-close-module-init-race.patch b/queue-7.0/netfilter-bridge-eb_tables-close-module-init-race.patch new file mode 100644 index 0000000000..dbe51fe8c8 --- /dev/null +++ b/queue-7.0/netfilter-bridge-eb_tables-close-module-init-race.patch @@ -0,0 +1,56 @@ +From 95dc5a017c4e22379e385bc2ee6778db068b01de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 11:19:22 +0200 +Subject: netfilter: bridge: eb_tables: close module init race + +From: Florian Westphal + +[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ] + +sashiko reports for unrelated patch: + Does the core ebtables initialization in ebtables.c suffer from a similar race? + Once nf_register_sockopt() completes, the sockopts are exposed globally. + +sockopt has to be registered last, just like in ip/ip6/arptables. + +Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtables.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 3578ffbc14aee..b9f4daac09af3 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2583,19 +2583,20 @@ static int __init ebtables_init(void) + { + int ret; + +- ret = xt_register_target(&ebt_standard_target); ++ ret = register_pernet_subsys(&ebt_net_ops); + if (ret < 0) + return ret; +- ret = nf_register_sockopt(&ebt_sockopts); ++ ++ ret = xt_register_target(&ebt_standard_target); + if (ret < 0) { +- xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +- ret = register_pernet_subsys(&ebt_net_ops); ++ ret = nf_register_sockopt(&ebt_sockopts); + if (ret < 0) { +- nf_unregister_sockopt(&ebt_sockopts); + xt_unregister_target(&ebt_standard_target); ++ unregister_pernet_subsys(&ebt_net_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-ebtables-close-dangling-table-module-init-.patch b/queue-7.0/netfilter-ebtables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..71dd9a2f62 --- /dev/null +++ b/queue-7.0/netfilter-ebtables-close-dangling-table-module-init-.patch @@ -0,0 +1,116 @@ +From 9a4381fcf6610333e1e3070ec988f4d51a9d989f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:19 +0200 +Subject: netfilter: ebtables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 92c603fa07bc0d6a17345de3ad7954730b8de44b ] + +sashiko reported for a related patch: + In modules like iptable_raw.c, [..], if register_pernet_subsys() fails, + the rollback might call kfree(rawtable_ops) before [..] + During this window, could a concurrent userspace process find the globally + visible template, trigger table_init(), [..] + +The table init functions must always register the template last. + +Otherwise, set/getsockopt can instantiate a table in a namespace +while the required pernet ops (contain the destructor) isn't available. +This change is also required in x_tables, handled in followup change. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 12 +++++------- + net/bridge/netfilter/ebtable_filter.c | 12 +++++------- + net/bridge/netfilter/ebtable_nat.c | 10 ++++------ + 3 files changed, 14 insertions(+), 20 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index e6f9e343b41f1..f05c79f215ea0 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -112,18 +112,16 @@ static struct pernet_operations broute_net_ops = { + + static int __init ebtable_broute_init(void) + { +- int ret = ebt_register_template(&broute_table, broute_table_init); ++ int ret = register_pernet_subsys(&broute_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&broute_net_ops); +- if (ret) { +- ebt_unregister_template(&broute_table); +- return ret; +- } ++ ret = ebt_register_template(&broute_table, broute_table_init); ++ if (ret) ++ unregister_pernet_subsys(&broute_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_broute_fini(void) +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index 02b6501c15a5e..0fc03b07e62ae 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -93,18 +93,16 @@ static struct pernet_operations frame_filter_net_ops = { + + static int __init ebtable_filter_init(void) + { +- int ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ int ret = register_pernet_subsys(&frame_filter_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_filter_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_filter); +- return ret; +- } ++ ret = ebt_register_template(&frame_filter, frame_filter_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_filter_net_ops); + +- return 0; ++ return ret; + } + + static void __exit ebtable_filter_fini(void) +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 9985a82555c41..8a10375d89099 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -93,16 +93,14 @@ static struct pernet_operations frame_nat_net_ops = { + + static int __init ebtable_nat_init(void) + { +- int ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ int ret = register_pernet_subsys(&frame_nat_net_ops); + + if (ret) + return ret; + +- ret = register_pernet_subsys(&frame_nat_net_ops); +- if (ret) { +- ebt_unregister_template(&frame_nat); +- return ret; +- } ++ ret = ebt_register_template(&frame_nat, frame_nat_table_init); ++ if (ret) ++ unregister_pernet_subsys(&frame_nat_net_ops); + + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/netfilter-ebtables-move-to-two-stage-removal-scheme.patch b/queue-7.0/netfilter-ebtables-move-to-two-stage-removal-scheme.patch new file mode 100644 index 0000000000..7ef857340f --- /dev/null +++ b/queue-7.0/netfilter-ebtables-move-to-two-stage-removal-scheme.patch @@ -0,0 +1,197 @@ +From 805757820f8623e6b126a4cebdb65ee64231639d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:18 +0200 +Subject: netfilter: ebtables: move to two-stage removal scheme + +From: Florian Westphal + +[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ] + +Like previous patches for x_tables, follow same pattern in ebtables. +We can't reuse xt helpers: ebt_table struct layout is incompatible. + +table->ops assignment is now done while still holding the ebt mutex +to make sure we never expose partially-filled table struct. + +Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default") +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebtable_broute.c | 2 +- + net/bridge/netfilter/ebtable_filter.c | 2 +- + net/bridge/netfilter/ebtable_nat.c | 2 +- + net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++---------- + 4 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c +index 7413602195525..e6f9e343b41f1 100644 +--- a/net/bridge/netfilter/ebtable_broute.c ++++ b/net/bridge/netfilter/ebtable_broute.c +@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void) + + static void __exit ebtable_broute_fini(void) + { +- unregister_pernet_subsys(&broute_net_ops); + ebt_unregister_template(&broute_table); ++ unregister_pernet_subsys(&broute_net_ops); + } + + module_init(ebtable_broute_init); +diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c +index dacd81b12e626..02b6501c15a5e 100644 +--- a/net/bridge/netfilter/ebtable_filter.c ++++ b/net/bridge/netfilter/ebtable_filter.c +@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void) + + static void __exit ebtable_filter_fini(void) + { +- unregister_pernet_subsys(&frame_filter_net_ops); + ebt_unregister_template(&frame_filter); ++ unregister_pernet_subsys(&frame_filter_net_ops); + } + + module_init(ebtable_filter_init); +diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c +index 0f2a8c6118d42..9985a82555c41 100644 +--- a/net/bridge/netfilter/ebtable_nat.c ++++ b/net/bridge/netfilter/ebtable_nat.c +@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void) + + static void __exit ebtable_nat_fini(void) + { +- unregister_pernet_subsys(&frame_nat_net_ops); + ebt_unregister_template(&frame_nat); ++ unregister_pernet_subsys(&frame_nat_net_ops); + } + + module_init(ebtable_nat_init); +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index aea3e19875c69..3578ffbc14aee 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -42,6 +42,7 @@ + + struct ebt_pernet { + struct list_head tables; ++ struct list_head dead_tables; + }; + + struct ebt_template { +@@ -1162,11 +1163,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len) + + static void __ebt_unregister_table(struct net *net, struct ebt_table *table) + { +- mutex_lock(&ebt_mutex); +- list_del(&table->list); +- mutex_unlock(&ebt_mutex); +- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, net, NULL); + if (table->private->nentries) +@@ -1267,13 +1263,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, + for (i = 0; i < num_ops; i++) + ops[i].priv = table; + +- list_add(&table->list, &ebt_net->tables); +- mutex_unlock(&ebt_mutex); +- + table->ops = ops; + ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret) ++ if (ret) { ++ synchronize_rcu(); + __ebt_unregister_table(net, table); ++ } else { ++ list_add(&table->list, &ebt_net->tables); ++ } ++ mutex_unlock(&ebt_mutex); + + audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, + AUDIT_XT_OP_REGISTER, GFP_KERNEL); +@@ -1339,7 +1337,7 @@ void ebt_unregister_template(const struct ebt_table *t) + } + EXPORT_SYMBOL(ebt_unregister_template); + +-static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ++void ebt_unregister_table_pre_exit(struct net *net, const char *name) + { + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + struct ebt_table *t; +@@ -1348,30 +1346,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) + + list_for_each_entry(t, &ebt_net->tables, list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &ebt_net->dead_tables); + mutex_unlock(&ebt_mutex); +- return t; ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; + } + } + + mutex_unlock(&ebt_mutex); +- return NULL; +-} +- +-void ebt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct ebt_table *table = __ebt_find_table(net, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); + } + EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + + void ebt_unregister_table(struct net *net, const char *name) + { +- struct ebt_table *table = __ebt_find_table(net, name); ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ struct ebt_table *t; + +- if (table) +- __ebt_unregister_table(net, table); ++ mutex_lock(&ebt_mutex); ++ ++ list_for_each_entry(t, &ebt_net->dead_tables, list) { ++ if (strcmp(t->name, name) == 0) { ++ list_del(&t->list); ++ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ __ebt_unregister_table(net, t); ++ mutex_unlock(&ebt_mutex); ++ return; ++ } ++ } ++ ++ mutex_unlock(&ebt_mutex); + } + + /* userspace just supplied us with counters */ +@@ -2556,11 +2560,21 @@ static int __net_init ebt_pernet_init(struct net *net) + struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); + + INIT_LIST_HEAD(&ebt_net->tables); ++ INIT_LIST_HEAD(&ebt_net->dead_tables); + return 0; + } + ++static void __net_exit ebt_pernet_exit(struct net *net) ++{ ++ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); ++ ++ WARN_ON_ONCE(!list_empty(&ebt_net->tables)); ++ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables)); ++} ++ + static struct pernet_operations ebt_net_ops = { + .init = ebt_pernet_init, ++ .exit = ebt_pernet_exit, + .id = &ebt_pernet_id, + .size = sizeof(struct ebt_pernet), + }; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_conntrack_expect-restore-helper-propaga.patch b/queue-7.0/netfilter-nf_conntrack_expect-restore-helper-propaga.patch new file mode 100644 index 0000000000..04fc24921b --- /dev/null +++ b/queue-7.0/netfilter-nf_conntrack_expect-restore-helper-propaga.patch @@ -0,0 +1,267 @@ +From e118ecf222e52ecfd995294a3ea0c614623f1d54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 13:00:28 +0200 +Subject: netfilter: nf_conntrack_expect: restore helper propagation via + expectation + +From: Pablo Neira Ayuso + +[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ] + +A recent series to fix expectations broke helper propagation via +expectation, this mechanism is used by the sip and h323 helper. This +also propagates the conntrack helper to expected connections. I changed +semantics of exp->helper which now tells us the actual helper that +created the expectation. + +Add an explicit assign_helper field to expectations for this purpose +and update helpers to use it. + +Restore this feature for userspace conntrack helper via ctnetlink +nfqueue integration so it is again possible to attach a helper to an +expectation, where it makes sense. This is not restored via ctnetlink +expectation creation as there is no client for such feature. Use the +expectation layer 4 protocol number for the helper lookup for +consistency. + +Make sure the expectation using this helper propagation mechanism also +go away when the helper is unregistered. + +Fixes: 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field") +Fixes: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Reported-by: Ilya Maximets +Tested-by: Ilya Maximets +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_expect.h | 5 ++++- + net/netfilter/nf_conntrack_broadcast.c | 1 + + net/netfilter/nf_conntrack_core.c | 7 +++++-- + net/netfilter/nf_conntrack_expect.c | 1 + + net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------ + net/netfilter/nf_conntrack_helper.c | 5 +++++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++-- + net/netfilter/nf_conntrack_sip.c | 2 +- + 8 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h +index e9a8350e7ccfb..80f50fd0f7ad2 100644 +--- a/include/net/netfilter/nf_conntrack_expect.h ++++ b/include/net/netfilter/nf_conntrack_expect.h +@@ -45,9 +45,12 @@ struct nf_conntrack_expect { + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + +- /* Helper to assign to new connection */ ++ /* Helper that created this expectation */ + struct nf_conntrack_helper __rcu *helper; + ++ /* Helper to assign to new connection */ ++ struct nf_conntrack_helper __rcu *assign_helper; ++ + /* The conntrack of the master connection */ + struct nf_conn *master; + +diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c +index 4f39bf7c843f2..75e53fde6b297 100644 +--- a/net/netfilter/nf_conntrack_broadcast.c ++++ b/net/netfilter/nf_conntrack_broadcast.c +@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 27ce5fda89937..b5ee274be7739 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1814,14 +1814,17 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl)); + if (exp) { ++ struct nf_conntrack_helper *assign_helper; ++ + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; +- if (exp->helper) { ++ assign_helper = rcu_dereference(exp->assign_helper); ++ if (assign_helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- rcu_assign_pointer(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, assign_helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 24d0576d84b7f..8e943efbdf0a5 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + helper = rcu_dereference(help->helper); + + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c +index 3f5c50455b716..b2fe6554b9cf4 100644 +--- a/net/netfilter/nf_conntrack_h323_main.c ++++ b/net/netfilter/nf_conntrack_h323_main.c +@@ -643,7 +643,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245); ++ rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -767,7 +767,7 @@ static int expect_callforwarding(struct sk_buff *skb, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -1234,7 +1234,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3 : NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nathook = rcu_dereference(nfct_h323_nat_hook); +@@ -1306,7 +1306,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect RAS "); +@@ -1523,7 +1523,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +@@ -1577,7 +1577,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index a715304a53d8c..b594cd244fe1d 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -400,6 +400,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data) + + this = rcu_dereference_protected(exp->helper, + lockdep_is_held(&nf_conntrack_expect_lock)); ++ if (this == me) ++ return true; ++ ++ this = rcu_dereference_protected(exp->assign_helper, ++ lockdep_is_held(&nf_conntrack_expect_lock)); + return this == me; + } + +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index a20cd82446c54..e2f149aabbe82 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -2636,6 +2636,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask); + +@@ -2862,6 +2863,7 @@ static int + ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + u32 portid, u32 report) + { ++ struct nf_conntrack_helper *assign_helper = NULL; + struct nlattr *cda[CTA_EXPECT_MAX+1]; + struct nf_conntrack_tuple tuple, mask; + struct nf_conntrack_expect *exp; +@@ -2877,8 +2879,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + if (err < 0) + return err; + ++ if (cda[CTA_EXPECT_HELP_NAME]) { ++ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); ++ ++ assign_helper = __nf_conntrack_helper_find(helpname, ++ nf_ct_l3num(ct), ++ tuple.dst.protonum); ++ if (!assign_helper) ++ return -EOPNOTSUPP; ++ } ++ + exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct, +- &tuple, &mask); ++ assign_helper, &tuple, &mask); + if (IS_ERR(exp)) + return PTR_ERR(exp); + +@@ -3517,6 +3529,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr, + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask) + { +@@ -3570,6 +3583,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, + exp->zone = ct->zone; + #endif + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, assign_helper); + exp->tuple = *tuple; + exp->mask.src.u3 = mask->src.u3; + exp->mask.src.u.all = mask->src.u.all; +@@ -3625,7 +3639,7 @@ ctnetlink_create_expect(struct net *net, + ct = nf_ct_tuplehash_to_ctrack(h); + + rcu_read_lock(); +- exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask); ++ exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto err_rcu; +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index 81534213f00f3..fd4326ee1aca8 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1384,7 +1384,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, proto, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; +- rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, helper); + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + hooks = rcu_dereference(nf_nat_sip_hooks); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-require-ethernet-mac-header-before-using-e.patch b/queue-7.0/netfilter-require-ethernet-mac-header-before-using-e.patch new file mode 100644 index 0000000000..936f452160 --- /dev/null +++ b/queue-7.0/netfilter-require-ethernet-mac-header-before-using-e.patch @@ -0,0 +1,183 @@ +From 921dc4d8647a12d9e04c7860d4bac66bd1e131f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 17:39:48 +0800 +Subject: netfilter: require Ethernet MAC header before using eth_hdr() + +From: Zhengchuan Liang + +[ Upstream commit 62443dc21114c0bbc476fa62973db89743f2f137 ] + +`ip6t_eui64`, `xt_mac`, the `bitmap:ip,mac`, `hash:ip,mac`, and +`hash:mac` ipset types, and `nf_log_syslog` access `eth_hdr(skb)` +after either assuming that the skb is associated with an Ethernet +device or checking only that the `ETH_HLEN` bytes at +`skb_mac_header(skb)` lie between `skb->head` and `skb->data`. + +Make these paths first verify that the skb is associated with an +Ethernet device, that the MAC header was set, and that it spans at +least a full Ethernet header before accessing `eth_hdr(skb)`. + +Suggested-by: Florian Westphal +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/ipv6/netfilter/ip6t_eui64.c | 7 +++++-- + net/netfilter/ipset/ip_set_bitmap_ipmac.c | 5 +++-- + net/netfilter/ipset/ip_set_hash_ipmac.c | 9 +++++---- + net/netfilter/ipset/ip_set_hash_mac.c | 5 +++-- + net/netfilter/nf_log_syslog.c | 8 +++++++- + net/netfilter/xt_mac.c | 4 +--- + 6 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c +index da69a27e8332c..bbb684f9964c0 100644 +--- a/net/ipv6/netfilter/ip6t_eui64.c ++++ b/net/ipv6/netfilter/ip6t_eui64.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,8 +22,10 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) + { + unsigned char eui64[8]; + +- if (!(skb_mac_header(skb) >= skb->head && +- skb_mac_header(skb) + ETH_HLEN <= skb->data)) { ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER) ++ return false; ++ ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) { + par->hotdrop = true; + return false; + } +diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +index 2c625e0f49ec0..752f59ef87442 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c ++++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -220,8 +221,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, + return -IPSET_ERR_BITMAP_RANGE; + + /* Backward compatibility: we don't check the second flag */ +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + e.id = ip_to_id(map, ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmac.c b/net/netfilter/ipset/ip_set_hash_ipmac.c +index 467c59a83c0ab..b9a2681e24888 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmac.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmac.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,8 +90,8 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +@@ -205,8 +206,8 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, + }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_TWO_SRC) +diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c +index 718814730acf6..41a122591fe24 100644 +--- a/net/netfilter/ipset/ip_set_hash_mac.c ++++ b/net/netfilter/ipset/ip_set_hash_mac.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -77,8 +78,8 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, + struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; + struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +- if (skb_mac_header(skb) < skb->head || +- (skb_mac_header(skb) + ETH_HLEN) > skb->data) ++ if (!skb->dev || skb->dev->type != ARPHRD_ETHER || ++ !skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return -EINVAL; + + if (opt->flags & IPSET_DIM_ONE_SRC) +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 41503847d9d7f..98d2b9db16efe 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -78,7 +78,10 @@ dump_arp_packet(struct nf_log_buf *m, + else + logflags = NF_LOG_DEFAULT_MASK; + +- if (logflags & NF_LOG_MACDECODE) { ++ if ((logflags & NF_LOG_MACDECODE) && ++ skb->dev && skb->dev->type == ARPHRD_ETHER && ++ skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) >= ETH_HLEN) { + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +@@ -789,6 +792,9 @@ static void dump_mac_header(struct nf_log_buf *m, + + switch (dev->type) { + case ARPHRD_ETHER: ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) ++ return; ++ + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); + nf_log_dump_vlan(m, skb); +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index bd2354760895d..7fc5156825e49 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -29,9 +29,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; +- if (skb_mac_header(skb) < skb->head) +- return false; +- if (skb_mac_header(skb) + ETH_HLEN > skb->data) ++ if (!skb_mac_header_was_set(skb) || skb_mac_header_len(skb) < ETH_HLEN) + return false; + ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr); + ret ^= info->invert; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch b/queue-7.0/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch new file mode 100644 index 0000000000..c04b1d7c79 --- /dev/null +++ b/queue-7.0/netfilter-x_tables-add-and-use-xt_unregister_table_p.patch @@ -0,0 +1,349 @@ +From 8f1604b8776bad3a53c0175fa051581acb35ff50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:15 +0200 +Subject: netfilter: x_tables: add and use xt_unregister_table_pre_exit + +From: Florian Westphal + +[ Upstream commit 527d6931473b75d90e38942aae6537d1a527f1fd ] + +Remove the copypasted variants of _pre_exit and add one single +function in the xtables core. ebtables is not compatible with +x_tables and therefore unchanged. + +This is a preparation patch to reduce noise in the followup +bug fixes. + +Reviewed-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b4597d5fd7d2 ("netfilter: x_tables: add and use xtables_unregister_table_exit") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + include/linux/netfilter_arp/arp_tables.h | 1 - + include/linux/netfilter_ipv4/ip_tables.h | 1 - + include/linux/netfilter_ipv6/ip6_tables.h | 1 - + net/ipv4/netfilter/arp_tables.c | 9 ------- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/ip_tables.c | 9 ------- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_nat.c | 1 + + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6_tables.c | 9 ------- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_nat.c | 1 + + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + net/netfilter/x_tables.c | 29 +++++++++++++++++++++++ + 19 files changed, 41 insertions(+), 39 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index b1235098db87c..196b6d03d08a6 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -301,6 +301,7 @@ struct xt_table *xt_register_table(struct net *net, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h +index a40aaf645fa47..05631a25e6229 100644 +--- a/include/linux/netfilter_arp/arp_tables.h ++++ b/include/linux/netfilter_arp/arp_tables.h +@@ -53,7 +53,6 @@ int arpt_register_table(struct net *net, const struct xt_table *table, + const struct arpt_replace *repl, + const struct nf_hook_ops *ops); + void arpt_unregister_table(struct net *net, const char *name); +-void arpt_unregister_table_pre_exit(struct net *net, const char *name); + extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + +diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h +index 132b0e4a6d4df..13593391d6058 100644 +--- a/include/linux/netfilter_ipv4/ip_tables.h ++++ b/include/linux/netfilter_ipv4/ip_tables.h +@@ -26,7 +26,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *ops); + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name); + void ipt_unregister_table_exit(struct net *net, const char *name); + + /* Standard entry. */ +diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h +index 8b8885a73c764..c6d5b927830dd 100644 +--- a/include/linux/netfilter_ipv6/ip6_tables.h ++++ b/include/linux/netfilter_ipv6/ip6_tables.h +@@ -27,7 +27,6 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); + int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *ops); +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name); + void ip6t_unregister_table_exit(struct net *net, const char *name); + extern unsigned int ip6t_do_table(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index c02e46a0271a0..bd348b7bad2c5 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1554,15 +1554,6 @@ int arpt_register_table(struct net *net, + return ret; + } + +-void arpt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +-EXPORT_SYMBOL(arpt_unregister_table_pre_exit); +- + void arpt_unregister_table(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 359d00d74095b..382345567a600 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -43,7 +43,7 @@ static int arptable_filter_table_init(struct net *net) + + static void __net_exit arptable_filter_net_pre_exit(struct net *net) + { +- arpt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_ARP, "filter"); + } + + static void __net_exit arptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 488c5945ebb23..864489928fb5a 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1756,14 +1756,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ipt_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ipt_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); +@@ -1854,7 +1846,6 @@ static void __exit ip_tables_fini(void) + } + + EXPORT_SYMBOL(ipt_register_table); +-EXPORT_SYMBOL(ipt_unregister_table_pre_exit); + EXPORT_SYMBOL(ipt_unregister_table_exit); + EXPORT_SYMBOL(ipt_do_table); + module_init(ip_tables_init); +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 595bfb492b1c1..0dea754a91209 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -61,7 +61,7 @@ static int __net_init iptable_filter_net_init(struct net *net) + + static void __net_exit iptable_filter_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "filter"); + } + + static void __net_exit iptable_filter_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index db90db7057cc4..4d3b124923080 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -96,7 +96,7 @@ static int iptable_mangle_table_init(struct net *net) + + static void __net_exit iptable_mangle_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "mangle"); + } + + static void __net_exit iptable_mangle_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 625a1ca13b1ba..8fc4912e790d8 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -129,6 +129,7 @@ static int iptable_nat_table_init(struct net *net) + static void __net_exit iptable_nat_net_pre_exit(struct net *net) + { + ipt_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); + } + + static void __net_exit iptable_nat_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index b46a790917306..6f7afec7954bd 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -53,7 +53,7 @@ static int iptable_raw_table_init(struct net *net) + + static void __net_exit iptable_raw_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "raw"); + } + + static void __net_exit iptable_raw_net_exit(struct net *net) +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 2b89adc1e5751..81175c20ccbe8 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -50,7 +50,7 @@ static int iptable_security_table_init(struct net *net) + + static void __net_exit iptable_security_net_pre_exit(struct net *net) + { +- ipt_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "security"); + } + + static void __net_exit iptable_security_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index dbe7c7acd702e..edf50bc7787e5 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1765,14 +1765,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +-void ip6t_unregister_table_pre_exit(struct net *net, const char *name) +-{ +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +- +- if (table) +- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks)); +-} +- + void ip6t_unregister_table_exit(struct net *net, const char *name) + { + struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); +@@ -1864,7 +1856,6 @@ static void __exit ip6_tables_fini(void) + } + + EXPORT_SYMBOL(ip6t_register_table); +-EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); + EXPORT_SYMBOL(ip6t_unregister_table_exit); + EXPORT_SYMBOL(ip6t_do_table); + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index 9dcd4501fe800..cf561919bde84 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -60,7 +60,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) + + static void __net_exit ip6table_filter_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "filter"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "filter"); + } + + static void __net_exit ip6table_filter_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index ce2cbce9e3ed3..1a758f2bc5379 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -89,7 +89,7 @@ static int ip6table_mangle_table_init(struct net *net) + + static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "mangle"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "mangle"); + } + + static void __net_exit ip6table_mangle_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index 5be723232df8f..bb8aa3fc42b45 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -131,6 +131,7 @@ static int ip6table_nat_table_init(struct net *net) + static void __net_exit ip6table_nat_net_pre_exit(struct net *net) + { + ip6t_nat_unregister_lookups(net); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); + } + + static void __net_exit ip6table_nat_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 8af0f8bd036dc..923455921c1dd 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -52,7 +52,7 @@ static int ip6table_raw_table_init(struct net *net) + + static void __net_exit ip6table_raw_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "raw"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "raw"); + } + + static void __net_exit ip6table_raw_net_exit(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 66018b169b010..c44834d93fc79 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -49,7 +49,7 @@ static int ip6table_security_table_init(struct net *net) + + static void __net_exit ip6table_security_net_pre_exit(struct net *net) + { +- ip6t_unregister_table_pre_exit(net, "security"); ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "security"); + } + + static void __net_exit ip6table_security_net_exit(struct net *net) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index e5fda8c2fc6cb..92fb3a64f70d9 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1583,6 +1583,35 @@ void *xt_unregister_table(struct xt_table *table) + return private; + } + EXPORT_SYMBOL_GPL(xt_unregister_table); ++ ++/** ++ * xt_unregister_table_pre_exit - pre-shutdown unregister of a table ++ * @net: network namespace ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Unregisters the specified netfilter table from the given network namespace ++ * and also unregisters the hooks from netfilter core: no new packets will be ++ * processed. ++ */ ++void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(t, &xt_net->tables[af], list) { ++ if (strcmp(t->name, name) == 0) { ++ mutex_unlock(&xt[af].mutex); ++ ++ if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ ++ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks)); ++ return; ++ } ++ } ++ mutex_unlock(&xt[af].mutex); ++} ++EXPORT_SYMBOL(xt_unregister_table_pre_exit); + #endif + + #ifdef CONFIG_PROC_FS +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch b/queue-7.0/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch new file mode 100644 index 0000000000..a584099980 --- /dev/null +++ b/queue-7.0/netfilter-x_tables-add-and-use-xtables_unregister_ta.patch @@ -0,0 +1,334 @@ +From 0c5acaeda80c0bfcc2671fc067f9e1b5ae0d5ebc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:17 +0200 +Subject: netfilter: x_tables: add and use xtables_unregister_table_exit + +From: Florian Westphal + +[ Upstream commit b4597d5fd7d2f8cebfffd40dffb5e003cc78964c ] + +Previous change added xtables_unregister_table_pre_exit to detach the +table from the packetpath and to unlink it from the active table list. +In case of rmmod, userspace that is doing set/getsockopt for this table +will not be able to re-instantiate the table: + 1. The larval table has been removed already + 2. existing instantiated table is no longer on the xt pernet table list. + +This adds the second stage helper: + +unlink the table from the dying list, free the hook ops (if any) and do +the audit notification. It replaces xt_unregister_table(). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 2 +- + net/ipv4/netfilter/arp_tables.c | 9 ++-- + net/ipv4/netfilter/ip_tables.c | 9 ++-- + net/ipv4/netfilter/iptable_nat.c | 5 +- + net/ipv6/netfilter/ip6_tables.c | 9 ++-- + net/ipv6/netfilter/ip6table_nat.c | 5 +- + net/netfilter/x_tables.c | 81 +++++++++++++++++++++++------- + 7 files changed, 83 insertions(+), 37 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 196b6d03d08a6..6fd365f7b35b0 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -300,8 +300,8 @@ struct xt_table *xt_register_table(struct net *net, + const struct nf_hook_ops *template_ops, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); +-void *xt_unregister_table(struct xt_table *table); + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name); ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name); + + struct xt_table_info *xt_replace_table(struct xt_table *table, + unsigned int num_counters, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index bd348b7bad2c5..ad2259678c785 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1501,13 +1501,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len + + static void __arpt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; ++ void *loc_cpu_entry; + struct arpt_entry *iter; + +- private = xt_unregister_table(table); +- + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; + xt_entry_foreach(iter, loc_cpu_entry, private->size) +@@ -1515,6 +1513,7 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int arpt_register_table(struct net *net, +@@ -1556,7 +1555,7 @@ int arpt_register_table(struct net *net, + + void arpt_unregister_table(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_ARP, name); + + if (table) + __arpt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 864489928fb5a..5cbdb0815857f 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1704,12 +1704,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ipt_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ipt_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1718,6 +1716,7 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ipt_register_table(struct net *net, const struct xt_table *table, +@@ -1758,7 +1757,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + + void ipt_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV4, name); + + if (table) + __ipt_unregister_table(net, table); +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 8fc4912e790d8..a0df725540251 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -119,8 +119,11 @@ static int iptable_nat_table_init(struct net *net) + } + + ret = ipt_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV4, "nat"); ++ synchronize_rcu(); + ipt_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index edf50bc7787e5..9d9c3763f2f5e 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1713,12 +1713,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) + + static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + { +- struct xt_table_info *private; +- void *loc_cpu_entry; ++ struct xt_table_info *private = table->private; + struct module *table_owner = table->me; + struct ip6t_entry *iter; +- +- private = xt_unregister_table(table); ++ void *loc_cpu_entry; + + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries; +@@ -1727,6 +1725,7 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) + if (private->number > private->initial_entries) + module_put(table_owner); + xt_free_table_info(private); ++ kfree(table); + } + + int ip6t_register_table(struct net *net, const struct xt_table *table, +@@ -1767,7 +1766,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + + void ip6t_unregister_table_exit(struct net *net, const char *name) + { +- struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); ++ struct xt_table *table = xt_unregister_table_exit(net, NFPROTO_IPV6, name); + + if (table) + __ip6t_unregister_table(net, table); +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index bb8aa3fc42b45..c2394e2c94b56 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -121,8 +121,11 @@ static int ip6table_nat_table_init(struct net *net) + } + + ret = ip6t_nat_register_lookups(net); +- if (ret < 0) ++ if (ret < 0) { ++ xt_unregister_table_pre_exit(net, NFPROTO_IPV6, "nat"); ++ synchronize_rcu(); + ip6t_unregister_table_exit(net, "nat"); ++ } + + kfree(repl); + return ret; +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 92fb3a64f70d9..8050cc06a9a30 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -55,6 +55,9 @@ static struct list_head xt_templates[NFPROTO_NUMPROTO]; + + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; ++ ++ /* stash area used during netns exit */ ++ struct list_head dead_tables[NFPROTO_NUMPROTO]; + }; + + struct compat_delta { +@@ -1567,23 +1570,6 @@ struct xt_table *xt_register_table(struct net *net, + } + EXPORT_SYMBOL_GPL(xt_register_table); + +-void *xt_unregister_table(struct xt_table *table) +-{ +- struct xt_table_info *private; +- +- mutex_lock(&xt[table->af].mutex); +- private = table->private; +- list_del(&table->list); +- mutex_unlock(&xt[table->af].mutex); +- audit_log_nfcfg(table->name, table->af, private->number, +- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); +- kfree(table->ops); +- kfree(table); +- +- return private; +-} +-EXPORT_SYMBOL_GPL(xt_unregister_table); +- + /** + * xt_unregister_table_pre_exit - pre-shutdown unregister of a table + * @net: network namespace +@@ -1593,6 +1579,14 @@ EXPORT_SYMBOL_GPL(xt_unregister_table); + * Unregisters the specified netfilter table from the given network namespace + * and also unregisters the hooks from netfilter core: no new packets will be + * processed. ++ * ++ * This must be called prior to xt_unregister_table_exit() from the pernet ++ * .pre_exit callback. After this call, the table is no longer visible to ++ * the get/setsockopt path. In case of rmmod, module exit path must have ++ * called xt_unregister_template() prior to unregistering pernet ops to ++ * prevent re-instantiation of the table. ++ * ++ * See also: xt_unregister_table_exit() + */ + void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + { +@@ -1602,6 +1596,7 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) { + if (strcmp(t->name, name) == 0) { ++ list_move(&t->list, &xt_net->dead_tables[af]); + mutex_unlock(&xt[af].mutex); + + if (t->ops) /* nat table registers with nat core, t->ops is NULL. */ +@@ -1612,6 +1607,50 @@ void xt_unregister_table_pre_exit(struct net *net, u8 af, const char *name) + mutex_unlock(&xt[af].mutex); + } + EXPORT_SYMBOL(xt_unregister_table_pre_exit); ++ ++/** ++ * xt_unregister_table_exit - remove a table during namespace teardown ++ * @net: the network namespace from which to unregister the table ++ * @af: address family (e.g., NFPROTO_IPV4, NFPROTO_IPV6) ++ * @name: name of the table to unregister ++ * ++ * Completes the unregister process for a table. This must be called from ++ * the pernet ops .exit callback. This is the second stage after ++ * xt_unregister_table_pre_exit(). ++ * ++ * pair with xt_unregister_table_pre_exit() during namespace shutdown. ++ * ++ * Return: the unregistered table or NULL if the table was never ++ * instantiated. The caller needs to kfree() the table after it ++ * has removed the family specific matches/targets. ++ */ ++struct xt_table *xt_unregister_table_exit(struct net *net, u8 af, const char *name) ++{ ++ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *table; ++ ++ mutex_lock(&xt[af].mutex); ++ list_for_each_entry(table, &xt_net->dead_tables[af], list) { ++ struct nf_hook_ops *ops = NULL; ++ ++ if (strcmp(table->name, name) != 0) ++ continue; ++ ++ list_del(&table->list); ++ ++ audit_log_nfcfg(table->name, table->af, table->private->number, ++ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL); ++ swap(table->ops, ops); ++ mutex_unlock(&xt[af].mutex); ++ ++ kfree(ops); ++ return table; ++ } ++ mutex_unlock(&xt[af].mutex); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(xt_unregister_table_exit); + #endif + + #ifdef CONFIG_PROC_FS +@@ -2058,8 +2097,10 @@ static int __net_init xt_net_init(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + INIT_LIST_HEAD(&xt_net->tables[i]); ++ INIT_LIST_HEAD(&xt_net->dead_tables[i]); ++ } + return 0; + } + +@@ -2068,8 +2109,10 @@ static void __net_exit xt_net_exit(struct net *net) + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); + int i; + +- for (i = 0; i < NFPROTO_NUMPROTO; i++) ++ for (i = 0; i < NFPROTO_NUMPROTO; i++) { + WARN_ON_ONCE(!list_empty(&xt_net->tables[i])); ++ WARN_ON_ONCE(!list_empty(&xt_net->dead_tables[i])); ++ } + } + + static struct pernet_operations xt_net_ops = { +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-allocate-hook-ops-while-under-mut.patch b/queue-7.0/netfilter-x_tables-allocate-hook-ops-while-under-mut.patch new file mode 100644 index 0000000000..c307321e6c --- /dev/null +++ b/queue-7.0/netfilter-x_tables-allocate-hook-ops-while-under-mut.patch @@ -0,0 +1,362 @@ +From cb6bccd6446ea988e310977354e75919a4fee9dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:14 +0200 +Subject: netfilter: x_tables: allocate hook ops while under mutex + +From: Florian Westphal + +[ Upstream commit b62eb8dcf2c47d4d676a434efbd57c4f776f7829 ] + +arp/ip(6)t_register_table() add the table to the per-netns list via +xt_register_table() before allocating the per-netns hook ops copy +via kmemdup_array(). This leaves a window where the table is +visible in the list with ops=NULL. + +If the pernet exit happens runs concurrently the pre_exit callback finds +the table via xt_find_table() and passes the NULL ops pointer to +nf_unregister_net_hooks(), causing a NULL dereference: + + general protection fault in nf_unregister_net_hooks+0xbc/0x150 + RIP: nf_unregister_net_hooks (net/netfilter/core.c:613) + Call Trace: + ipt_unregister_table_pre_exit + iptable_mangle_net_pre_exit + ops_pre_exit_list + cleanup_net + +Fix by moving the ops allocation into the xtables core so the table is +never in the list without valid ops. Also ensure the table is no longer +processing packets before its torn down on error unwind. +nf_register_net_hooks might have published at least one hook; call +synchronize_rcu() if there was an error. + +audit log register message gets deferred until all operations have +passed, this avoids need to emit another ureg message in case of +error unwinding. + +Based on earlier patch by Tristan Madani. + +Fixes: f9006acc8dfe5 ("netfilter: arp_tables: pass table pointer via nf_hook_ops") +Fixes: ee177a54413a ("netfilter: ip6_tables: pass table pointer via nf_hook_ops") +Fixes: ae689334225f ("netfilter: ip_tables: pass table pointer via nf_hook_ops") +Link: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Tristan Madani +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/x_tables.h | 1 + + net/ipv4/netfilter/arp_tables.c | 35 +++------------------ + net/ipv4/netfilter/ip_tables.c | 41 +++--------------------- + net/ipv6/netfilter/ip6_tables.c | 38 +++-------------------- + net/netfilter/x_tables.c | 50 +++++++++++++++++++++++++----- + 5 files changed, 55 insertions(+), 110 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index 77c778d84d4cb..b1235098db87c 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -297,6 +297,7 @@ struct xt_counters *xt_counters_alloc(unsigned int counters); + + struct xt_table *xt_register_table(struct net *net, + const struct xt_table *table, ++ const struct nf_hook_ops *template_ops, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo); + void *xt_unregister_table(struct xt_table *table); +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 97ead883e4a13..c02e46a0271a0 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1522,13 +1522,11 @@ int arpt_register_table(struct net *net, + const struct arpt_replace *repl, + const struct nf_hook_ops *template_ops) + { +- struct nf_hook_ops *ops; +- unsigned int num_ops; +- int ret, i; +- struct xt_table_info *newinfo; + struct xt_table_info bootstrap = {0}; +- void *loc_cpu_entry; ++ struct xt_table_info *newinfo; + struct xt_table *new_table; ++ void *loc_cpu_entry; ++ int ret; + + newinfo = xt_alloc_table_info(repl->size); + if (!newinfo) +@@ -1543,7 +1541,7 @@ int arpt_register_table(struct net *net, + return ret; + } + +- new_table = xt_register_table(net, table, &bootstrap, newinfo); ++ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo); + if (IS_ERR(new_table)) { + struct arpt_entry *iter; + +@@ -1553,31 +1551,6 @@ int arpt_register_table(struct net *net, + return PTR_ERR(new_table); + } + +- num_ops = hweight32(table->valid_hooks); +- if (num_ops == 0) { +- ret = -EINVAL; +- goto out_free; +- } +- +- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL); +- if (!ops) { +- ret = -ENOMEM; +- goto out_free; +- } +- +- for (i = 0; i < num_ops; i++) +- ops[i].priv = new_table; +- +- new_table->ops = ops; +- +- ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret != 0) +- goto out_free; +- +- return ret; +- +-out_free: +- __arpt_unregister_table(net, new_table); + return ret; + } + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 23c8deff8095a..488c5945ebb23 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1724,13 +1724,11 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + const struct ipt_replace *repl, + const struct nf_hook_ops *template_ops) + { +- struct nf_hook_ops *ops; +- unsigned int num_ops; +- int ret, i; +- struct xt_table_info *newinfo; + struct xt_table_info bootstrap = {0}; +- void *loc_cpu_entry; ++ struct xt_table_info *newinfo; + struct xt_table *new_table; ++ void *loc_cpu_entry; ++ int ret; + + newinfo = xt_alloc_table_info(repl->size); + if (!newinfo) +@@ -1745,7 +1743,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +- new_table = xt_register_table(net, table, &bootstrap, newinfo); ++ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo); + if (IS_ERR(new_table)) { + struct ipt_entry *iter; + +@@ -1755,37 +1753,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table, + return PTR_ERR(new_table); + } + +- /* No template? No need to do anything. This is used by 'nat' table, it registers +- * with the nat core instead of the netfilter core. +- */ +- if (!template_ops) +- return 0; +- +- num_ops = hweight32(table->valid_hooks); +- if (num_ops == 0) { +- ret = -EINVAL; +- goto out_free; +- } +- +- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL); +- if (!ops) { +- ret = -ENOMEM; +- goto out_free; +- } +- +- for (i = 0; i < num_ops; i++) +- ops[i].priv = new_table; +- +- new_table->ops = ops; +- +- ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret != 0) +- goto out_free; +- +- return ret; +- +-out_free: +- __ipt_unregister_table(net, new_table); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index d585ac3c11133..dbe7c7acd702e 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1733,13 +1733,11 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + const struct ip6t_replace *repl, + const struct nf_hook_ops *template_ops) + { +- struct nf_hook_ops *ops; +- unsigned int num_ops; +- int ret, i; +- struct xt_table_info *newinfo; + struct xt_table_info bootstrap = {0}; +- void *loc_cpu_entry; ++ struct xt_table_info *newinfo; + struct xt_table *new_table; ++ void *loc_cpu_entry; ++ int ret; + + newinfo = xt_alloc_table_info(repl->size); + if (!newinfo) +@@ -1754,7 +1752,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return ret; + } + +- new_table = xt_register_table(net, table, &bootstrap, newinfo); ++ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo); + if (IS_ERR(new_table)) { + struct ip6t_entry *iter; + +@@ -1764,34 +1762,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, + return PTR_ERR(new_table); + } + +- if (!template_ops) +- return 0; +- +- num_ops = hweight32(table->valid_hooks); +- if (num_ops == 0) { +- ret = -EINVAL; +- goto out_free; +- } +- +- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL); +- if (!ops) { +- ret = -ENOMEM; +- goto out_free; +- } +- +- for (i = 0; i < num_ops; i++) +- ops[i].priv = new_table; +- +- new_table->ops = ops; +- +- ret = nf_register_net_hooks(net, ops, num_ops); +- if (ret != 0) +- goto out_free; +- +- return ret; +- +-out_free: +- __ip6t_unregister_table(net, new_table); + return ret; + } + +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index f694eb72e48db..e5fda8c2fc6cb 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1475,7 +1475,6 @@ xt_replace_table(struct xt_table *table, unsigned int num_counters, + private = do_replace_table(table, num_counters, newinfo, error); + if (private) + audit_log_nfcfg(table->name, table->af, private->number, +- !private->number ? AUDIT_XT_OP_REGISTER : + AUDIT_XT_OP_REPLACE, + GFP_KERNEL); + +@@ -1485,20 +1484,32 @@ EXPORT_SYMBOL_GPL(xt_replace_table); + + struct xt_table *xt_register_table(struct net *net, + const struct xt_table *input_table, ++ const struct nf_hook_ops *template_ops, + struct xt_table_info *bootstrap, + struct xt_table_info *newinfo) + { + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); ++ struct xt_table *t, *table = NULL; ++ struct nf_hook_ops *ops = NULL; + struct xt_table_info *private; +- struct xt_table *t, *table; +- int ret; ++ unsigned int num_ops; ++ int ret = -EINVAL; ++ ++ num_ops = hweight32(input_table->valid_hooks); ++ if (num_ops == 0) ++ goto out; ++ ++ ret = -ENOMEM; ++ if (template_ops) { ++ ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL); ++ if (!ops) ++ goto out; ++ } + + /* Don't add one object to multiple lists. */ + table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); +- if (!table) { +- ret = -ENOMEM; ++ if (!table) + goto out; +- } + + mutex_lock(&xt[table->af].mutex); + /* Don't autoload: we'd eat our tail... */ +@@ -1512,7 +1523,7 @@ struct xt_table *xt_register_table(struct net *net, + /* Simplifies replace_table code. */ + table->private = bootstrap; + +- if (!xt_replace_table(table, 0, newinfo, &ret)) ++ if (!do_replace_table(table, 0, newinfo, &ret)) + goto unlock; + + private = table->private; +@@ -1521,14 +1532,37 @@ struct xt_table *xt_register_table(struct net *net, + /* save number of initial entries */ + private->initial_entries = private->number; + ++ if (ops) { ++ int i; ++ ++ for (i = 0; i < num_ops; i++) ++ ops[i].priv = table; ++ ++ ret = nf_register_net_hooks(net, ops, num_ops); ++ if (ret != 0) { ++ mutex_unlock(&xt[table->af].mutex); ++ /* nf_register_net_hooks() might have published a ++ * base chain before internal error unwind. ++ */ ++ synchronize_rcu(); ++ goto out; ++ } ++ ++ table->ops = ops; ++ } ++ ++ audit_log_nfcfg(table->name, table->af, private->number, ++ AUDIT_XT_OP_REGISTER, GFP_KERNEL); ++ + list_add(&table->list, &xt_net->tables[table->af]); + mutex_unlock(&xt[table->af].mutex); + return table; + + unlock: + mutex_unlock(&xt[table->af].mutex); +- kfree(table); + out: ++ kfree(table); ++ kfree(ops); + return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(xt_register_table); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-allow-initial-table-replace-witho.patch b/queue-7.0/netfilter-x_tables-allow-initial-table-replace-witho.patch new file mode 100644 index 0000000000..e3dbad44ab --- /dev/null +++ b/queue-7.0/netfilter-x_tables-allow-initial-table-replace-witho.patch @@ -0,0 +1,75 @@ +From 7d205dfca69e7b8cba307353f735fe23bdde662f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:13 +0200 +Subject: netfilter: x_tables: allow initial table replace without emitting + audit log message + +From: Florian Westphal + +[ Upstream commit 8e72510db9fa2d41f2b06d5c01fe9020e076fee4 ] + +At the moment we emit the audit log a bit too early, which makes it +necessary to also emit an unregister log in case we have to unwind +errors after possible hook register failure. + +Followup patch will be slightly simpler if we can delay the +register message until after the hooks have been wired up. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: b62eb8dcf2c4 ("netfilter: x_tables: allocate hook ops while under mutex") +Signed-off-by: Sasha Levin +--- + net/netfilter/x_tables.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index b39017c805484..f694eb72e48db 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -1405,11 +1405,9 @@ struct xt_counters *xt_counters_alloc(unsigned int counters) + } + EXPORT_SYMBOL(xt_counters_alloc); + +-struct xt_table_info * +-xt_replace_table(struct xt_table *table, +- unsigned int num_counters, +- struct xt_table_info *newinfo, +- int *error) ++static struct xt_table_info * ++do_replace_table(struct xt_table *table, unsigned int num_counters, ++ struct xt_table_info *newinfo, int *error) + { + struct xt_table_info *private; + unsigned int cpu; +@@ -1464,10 +1462,23 @@ xt_replace_table(struct xt_table *table, + } + } + +- audit_log_nfcfg(table->name, table->af, private->number, +- !private->number ? AUDIT_XT_OP_REGISTER : +- AUDIT_XT_OP_REPLACE, +- GFP_KERNEL); ++ return private; ++} ++ ++struct xt_table_info * ++xt_replace_table(struct xt_table *table, unsigned int num_counters, ++ struct xt_table_info *newinfo, ++ int *error) ++{ ++ struct xt_table_info *private; ++ ++ private = do_replace_table(table, num_counters, newinfo, error); ++ if (private) ++ audit_log_nfcfg(table->name, table->af, private->number, ++ !private->number ? AUDIT_XT_OP_REGISTER : ++ AUDIT_XT_OP_REPLACE, ++ GFP_KERNEL); ++ + return private; + } + EXPORT_SYMBOL_GPL(xt_replace_table); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-close-dangling-table-module-init-.patch b/queue-7.0/netfilter-x_tables-close-dangling-table-module-init-.patch new file mode 100644 index 0000000000..a630162a32 --- /dev/null +++ b/queue-7.0/netfilter-x_tables-close-dangling-table-module-init-.patch @@ -0,0 +1,406 @@ +From 69d24465f9c51edc8465aa82fb79f0272dee0478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:20 +0200 +Subject: netfilter: x_tables: close dangling table module init race + +From: Florian Westphal + +[ Upstream commit 16bc4b6686b2c112c10e67d6b493adc3607256d3 ] + +Similar to the previous ebtables patch: +template add exposes the table to userspace, we must do this last to +rnsure the pernet ops are set up (contain the destructors). + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_filter.c | 23 ++++++++++++----------- + net/ipv4/netfilter/iptable_mangle.c | 25 +++++++++++++------------ + net/ipv4/netfilter/iptable_raw.c | 22 +++++++++++----------- + net/ipv4/netfilter/iptable_security.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_filter.c | 22 +++++++++++----------- + net/ipv6/netfilter/ip6table_mangle.c | 23 ++++++++++++----------- + net/ipv6/netfilter/ip6table_raw.c | 20 ++++++++++---------- + net/ipv6/netfilter/ip6table_security.c | 23 ++++++++++++----------- + 9 files changed, 105 insertions(+), 99 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 382345567a600..370b635e3523b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = { + + static int __init arptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- arptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table); +- if (IS_ERR(arpfilter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(arpfilter_ops)) + return PTR_ERR(arpfilter_ops); +- } + + ret = register_pernet_subsys(&arptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ arptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(arpfilter_ops); +- return ret; ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(arpfilter_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 0dea754a91209..672d7da1071d3 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = { + + static int __init iptable_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- iptable_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&iptable_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ++ iptable_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_filter_net_ops); ++ goto err_free; + } + + return 0; ++err_free: ++ kfree(filter_ops); ++ return ret; + } + + static void __exit iptable_filter_fini(void) +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 4d3b124923080..13d25d9a4610e 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -111,25 +111,26 @@ static struct pernet_operations iptable_mangle_net_ops = { + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); +- ret = PTR_ERR(mangle_ops); +- return ret; +- } ++ if (IS_ERR(mangle_ops)) ++ return PTR_ERR(mangle_ops); + + ret = register_pernet_subsys(&iptable_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ iptable_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 6f7afec7954bd..2745c22f4034d 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, +- iptable_raw_table_init); +- if (ret < 0) +- return ret; +- + rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&iptable_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ++ iptable_raw_table_init); + if (ret < 0) { +- xt_unregister_template(table); +- kfree(rawtable_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index 81175c20ccbe8..491894511c544 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = { + + static int __init iptable_security_init(void) + { +- int ret = xt_register_template(&security_table, +- iptable_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&iptable_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ iptable_security_table_init); + if (ret < 0) { +- xt_unregister_template(&security_table); +- kfree(sectbl_ops); +- return ret; ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index cf561919bde84..b074fc4776764 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = { + + static int __init ip6table_filter_init(void) + { +- int ret = xt_register_template(&packet_filter, +- ip6table_filter_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table); +- if (IS_ERR(filter_ops)) { +- xt_unregister_template(&packet_filter); ++ if (IS_ERR(filter_ops)) + return PTR_ERR(filter_ops); +- } + + ret = register_pernet_subsys(&ip6table_filter_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_filter, ip6table_filter_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_filter); +- kfree(filter_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_filter_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(filter_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 1a758f2bc5379..e6ee036a9b2c5 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -104,25 +104,26 @@ static struct pernet_operations ip6table_mangle_net_ops = { + + static int __init ip6table_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- ip6table_mangle_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook); +- if (IS_ERR(mangle_ops)) { +- xt_unregister_template(&packet_mangler); ++ if (IS_ERR(mangle_ops)) + return PTR_ERR(mangle_ops); +- } + + ret = register_pernet_subsys(&ip6table_mangle_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&packet_mangler, ++ ip6table_mangle_table_init); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); +- kfree(mangle_ops); +- return ret; ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(mangle_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index 923455921c1dd..3b161ee875bcc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void) + pr_info("Enabling raw table before defrag\n"); + } + +- ret = xt_register_template(table, ip6table_raw_table_init); +- if (ret < 0) +- return ret; +- + /* Register hooks */ + rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table); +- if (IS_ERR(rawtable_ops)) { +- xt_unregister_template(table); ++ if (IS_ERR(rawtable_ops)) + return PTR_ERR(rawtable_ops); +- } + + ret = register_pernet_subsys(&ip6table_raw_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(table, ip6table_raw_table_init); + if (ret < 0) { +- kfree(rawtable_ops); +- xt_unregister_template(table); +- return ret; ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(rawtable_ops); + return ret; + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index c44834d93fc79..4bd5d97b8ab65 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = { + + static int __init ip6table_security_init(void) + { +- int ret = xt_register_template(&security_table, +- ip6table_security_table_init); +- +- if (ret < 0) +- return ret; ++ int ret; + + sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table); +- if (IS_ERR(sectbl_ops)) { +- xt_unregister_template(&security_table); ++ if (IS_ERR(sectbl_ops)) + return PTR_ERR(sectbl_ops); +- } + + ret = register_pernet_subsys(&ip6table_security_net_ops); ++ if (ret < 0) ++ goto err_free; ++ ++ ret = xt_register_template(&security_table, ++ ip6table_security_table_init); + if (ret < 0) { +- kfree(sectbl_ops); +- xt_unregister_template(&security_table); +- return ret; ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ goto err_free; + } + ++ return 0; ++err_free: ++ kfree(sectbl_ops); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-unregister-the-templates-first.patch b/queue-7.0/netfilter-x_tables-unregister-the-templates-first.patch new file mode 100644 index 0000000000..4390cbbe8f --- /dev/null +++ b/queue-7.0/netfilter-x_tables-unregister-the-templates-first.patch @@ -0,0 +1,164 @@ +From 4e6c06f3e05c6e9e0de8d9a7f4ebc58cf55ecc8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 12:07:16 +0200 +Subject: netfilter: x_tables: unregister the templates first + +From: Florian Westphal + +[ Upstream commit d338693d778579b676a61346849bebd892427158 ] + +When the module is going away we need to zap the template +first. Else there is a small race window where userspace +could instantiate a new table after the pernet exit function +has removed the current table. + +Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default") +Reported-by: Tristan Madani +Reviewed-by: Tristan Madani +Closes: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/ +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_filter.c | 2 +- + net/ipv4/netfilter/iptable_mangle.c | 2 +- + net/ipv4/netfilter/iptable_raw.c | 2 +- + net/ipv4/netfilter/iptable_security.c | 2 +- + net/ipv6/netfilter/ip6table_filter.c | 2 +- + net/ipv6/netfilter/ip6table_mangle.c | 2 +- + net/ipv6/netfilter/ip6table_raw.c | 2 +- + net/ipv6/netfilter/ip6table_security.c | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c +index 78cd5ee24448f..359d00d74095b 100644 +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -82,8 +82,8 @@ static int __init arptable_filter_init(void) + + static void __exit arptable_filter_fini(void) + { +- unregister_pernet_subsys(&arptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&arptable_filter_net_ops); + kfree(arpfilter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c +index 3ab908b747951..595bfb492b1c1 100644 +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -101,8 +101,8 @@ static int __init iptable_filter_init(void) + + static void __exit iptable_filter_fini(void) + { +- unregister_pernet_subsys(&iptable_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&iptable_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c +index 385d945d8ebea..db90db7057cc4 100644 +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -135,8 +135,8 @@ static int __init iptable_mangle_init(void) + + static void __exit iptable_mangle_fini(void) + { +- unregister_pernet_subsys(&iptable_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&iptable_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c +index 0e7f53964d0af..b46a790917306 100644 +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -100,9 +100,9 @@ static int __init iptable_raw_init(void) + + static void __exit iptable_raw_fini(void) + { ++ xt_unregister_template(&packet_raw); + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c +index d885443cb2679..2b89adc1e5751 100644 +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -89,9 +89,9 @@ static int __init iptable_security_init(void) + + static void __exit iptable_security_fini(void) + { ++ xt_unregister_template(&security_table); + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c +index e8992693e14a0..9dcd4501fe800 100644 +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -100,8 +100,8 @@ static int __init ip6table_filter_init(void) + + static void __exit ip6table_filter_fini(void) + { +- unregister_pernet_subsys(&ip6table_filter_net_ops); + xt_unregister_template(&packet_filter); ++ unregister_pernet_subsys(&ip6table_filter_net_ops); + kfree(filter_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c +index 8dd4cd0c47bd4..ce2cbce9e3ed3 100644 +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -128,8 +128,8 @@ static int __init ip6table_mangle_init(void) + + static void __exit ip6table_mangle_fini(void) + { +- unregister_pernet_subsys(&ip6table_mangle_net_ops); + xt_unregister_template(&packet_mangler); ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); + kfree(mangle_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c +index fc9f6754028f2..8af0f8bd036dc 100644 +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -98,8 +98,8 @@ static int __init ip6table_raw_init(void) + + static void __exit ip6table_raw_fini(void) + { +- unregister_pernet_subsys(&ip6table_raw_net_ops); + xt_unregister_template(&packet_raw); ++ unregister_pernet_subsys(&ip6table_raw_net_ops); + kfree(rawtable_ops); + } + +diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c +index 4df14a9bae782..66018b169b010 100644 +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -88,8 +88,8 @@ static int __init ip6table_security_init(void) + + static void __exit ip6table_security_fini(void) + { +- unregister_pernet_subsys(&ip6table_security_net_ops); + xt_unregister_template(&security_table); ++ unregister_pernet_subsys(&ip6table_security_net_ops); + kfree(sectbl_ops); + } + +-- +2.53.0 + diff --git a/queue-7.0/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch b/queue-7.0/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch new file mode 100644 index 0000000000..4ffa3e511a --- /dev/null +++ b/queue-7.0/netfs-afs-fix-write-skipping-in-dir-link-writepages.patch @@ -0,0 +1,90 @@ +From 827bd3d9179d3c333790d025bbb41875573a932f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:34:00 +0100 +Subject: netfs, afs: Fix write skipping in dir/link writepages + +From: David Howells + +[ Upstream commit 9871938f99cc6cb266a77265491660e2375271f5 ] + +Fix netfs_write_single() and afs_single_writepages() to better handle a +write that would be skipped due to lock contention and WB_SYNC_NONE by +returning 1 from netfs_write_single() if it skipped and making +afs_single_writepages() skip also. If a skip occurs, the inode must be +re-marked as the VFS may have cleared the mark. + +This is really only theoretical for directories in netfs_write_single() as +the only path to that is through afs_single_writepages() that takes the +->validate_lock around it, thereby serialising it. + +Fixes: 6dd80936618c ("afs: Use netfslib for directories") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-24-dhowells@redhat.com +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/afs/dir.c | 11 ++++++++++- + fs/netfs/write_issue.c | 7 ++++++- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index 78caef3f13388..068a892d39c4e 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -2206,7 +2206,14 @@ int afs_single_writepages(struct address_space *mapping, + /* Need to lock to prevent the folio queue and folios from being thrown + * away. + */ +- down_read(&dvnode->validate_lock); ++ if (!down_read_trylock(&dvnode->validate_lock)) { ++ if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* The VFS will have undirtied the inode. */ ++ netfs_single_mark_inode_dirty(&dvnode->netfs.inode); ++ return 0; ++ } ++ down_read(&dvnode->validate_lock); ++ } + + if (is_dir ? + test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) : +@@ -2214,6 +2221,8 @@ int afs_single_writepages(struct address_space *mapping, + iov_iter_folio_queue(&iter, ITER_SOURCE, dvnode->directory, 0, 0, + i_size_read(&dvnode->netfs.inode)); + ret = netfs_writeback_single(mapping, wbc, &iter); ++ if (ret == 1) ++ ret = 0; /* Skipped write due to lock conflict. */ + } + + up_read(&dvnode->validate_lock); +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index 03961622996be..c03c7cc45e471 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -830,6 +830,9 @@ static int netfs_write_folio_single(struct netfs_io_request *wreq, + * + * Write a monolithic, non-pagecache object back to the server and/or + * the cache. ++ * ++ * Return: 0 if successful; 1 if skipped due to lock conflict and WB_SYNC_NONE; ++ * or a negative error code. + */ + int netfs_writeback_single(struct address_space *mapping, + struct writeback_control *wbc, +@@ -846,8 +849,10 @@ int netfs_writeback_single(struct address_space *mapping, + + if (!mutex_trylock(&ictx->wb_lock)) { + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* The VFS will have undirtied the inode. */ ++ netfs_single_mark_inode_dirty(&ictx->inode); + netfs_stat(&netfs_n_wb_lock_skip); +- return 0; ++ return 1; + } + netfs_stat(&netfs_n_wb_lock_wait); + mutex_lock(&ictx->wb_lock); +-- +2.53.0 + diff --git a/queue-7.0/netfs-defer-the-emission-of-trace_netfs_folio.patch b/queue-7.0/netfs-defer-the-emission-of-trace_netfs_folio.patch new file mode 100644 index 0000000000..c30d86053a --- /dev/null +++ b/queue-7.0/netfs-defer-the-emission-of-trace_netfs_folio.patch @@ -0,0 +1,116 @@ +From 212de53262be1254d9ac1841085a335080af49a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:49 +0100 +Subject: netfs: Defer the emission of trace_netfs_folio() + +From: David Howells + +[ Upstream commit daeb443b92817021c1234e8eded219e164b7c35d ] + +Change netfs_perform_write() to keep the netfs_folio trace value in a +variable and emit it later to make it easier to choose the value displayed. +This is a prerequisite for a subsequent patch. + +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-13-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Stable-dep-of: 7b4dcf1b9455 ("netfs: Fix streaming write being overwritten") +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index c887a30c14d91..a695d5168b2fc 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -150,6 +150,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + do { ++ enum netfs_folio_trace trace; + struct netfs_folio *finfo; + struct netfs_group *group; + unsigned long long fpos; +@@ -223,7 +224,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_folio_is_uptodate); ++ trace = netfs_folio_is_uptodate; + goto copied; + } + +@@ -239,7 +240,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + folio_zero_segment(folio, offset + copied, flen); + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_modify_and_clear); ++ trace = netfs_modify_and_clear; + goto copied; + } + +@@ -257,7 +258,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_whole_folio_modify); ++ trace = netfs_whole_folio_modify; + goto copied; + } + +@@ -284,7 +285,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + netfs_set_group(folio, netfs_group); +- trace_netfs_folio(folio, netfs_just_prefetch); ++ trace = netfs_just_prefetch; + goto copied; + } + +@@ -298,7 +299,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (offset == 0 && copied == flen) { + __netfs_set_group(folio, netfs_group); + folio_mark_uptodate(folio); +- trace_netfs_folio(folio, netfs_streaming_filled_page); ++ trace = netfs_streaming_filled_page; + goto copied; + } + +@@ -313,7 +314,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len = copied; + folio_attach_private(folio, (void *)((unsigned long)finfo | + NETFS_FOLIO_INFO)); +- trace_netfs_folio(folio, netfs_streaming_write); ++ trace = netfs_streaming_write; + goto copied; + } + +@@ -333,9 +334,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + folio_detach_private(folio); + folio_mark_uptodate(folio); + kfree(finfo); +- trace_netfs_folio(folio, netfs_streaming_cont_filled_page); ++ trace = netfs_streaming_cont_filled_page; + } else { +- trace_netfs_folio(folio, netfs_streaming_write_cont); ++ trace = netfs_streaming_write_cont; + } + goto copied; + } +@@ -351,6 +352,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + continue; + + copied: ++ trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); + + /* Update the inode size if we moved the EOF marker */ +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch b/queue-7.0/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch new file mode 100644 index 0000000000..8092e64a02 --- /dev/null +++ b/queue-7.0/netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch @@ -0,0 +1,342 @@ +From a7b1774b9656978e3e06a1502a3b646c79b24f51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:38 +0100 +Subject: netfs: Fix cancellation of a DIO and single read subrequests + +From: David Howells + +[ Upstream commit 6f0f7ac1915abc0d202f0eb4b003a6548a5ba60d ] + +When the preparation of a new subrequest for a read fails, if the +subrequest has already been added to the stream->subrequests list, it can't +simply be put and abandoned as the collector may see it. Also, if it +hasn't been queued yet, it has two outstanding refs that both need to be +put. Both DIO read and single-read dispatch fail at this; further, both +differ in the order they do things to the way buffered read works. + +Fix cancellation of both DIO-read and single-read subrequests that failed +preparation by the following steps: + + (1) Harmonise all three reads (buffered, dio, single) to queue the subreq + before prepping it. + + (2) Make all three call netfs_queue_read() to do the queuing. + + (3) Set NETFS_RREQ_ALL_QUEUED independently of the queuing as we don't + know the length of the subreq at this point. + + (4) In all cases, set the error and NETFS_SREQ_FAILED flag on the subreq + and then call netfs_read_subreq_terminated() to deal with it. This + will pass responsibility off to the collector for dealing with it. + +Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") +Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-2-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 34 +++++++++++++------------------- + fs/netfs/direct_read.c | 42 +++++++++++++--------------------------- + fs/netfs/internal.h | 3 +++ + fs/netfs/read_collect.c | 11 +++++++++++ + fs/netfs/read_single.c | 23 ++++++++++------------ + 5 files changed, 50 insertions(+), 63 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index a8c0d86118c58..a27ed501b6d43 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -156,9 +156,8 @@ static void netfs_read_cache_to_pagecache(struct netfs_io_request *rreq, + netfs_cache_read_terminated, subreq); + } + +-static void netfs_queue_read(struct netfs_io_request *rreq, +- struct netfs_io_subrequest *subreq, +- bool last_subreq) ++void netfs_queue_read(struct netfs_io_request *rreq, ++ struct netfs_io_subrequest *subreq) + { + struct netfs_io_stream *stream = &rreq->io_streams[0]; + +@@ -178,11 +177,6 @@ static void netfs_queue_read(struct netfs_io_request *rreq, + } + } + +- if (last_subreq) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- } +- + spin_unlock(&rreq->lock); + } + +@@ -233,6 +227,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + subreq->start = start; + subreq->len = size; + ++ netfs_queue_read(rreq, subreq); ++ + source = netfs_cache_prepare_read(rreq, subreq, rreq->i_size); + subreq->source = source; + if (source == NETFS_DOWNLOAD_FROM_SERVER) { +@@ -253,6 +249,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + rreq->debug_id, subreq->debug_index, + subreq->len, size, + subreq->start, ictx->zero_point, rreq->i_size); ++ netfs_cancel_read(subreq, ret); + break; + } + subreq->len = len; +@@ -261,12 +258,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); + if (ret < 0) { +- subreq->error = ret; +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, +- netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, +- netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } + trace_netfs_sreq(subreq, netfs_sreq_trace_prepare); +@@ -289,23 +281,23 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + + pr_err("Unexpected read source %u\n", source); + WARN_ON_ONCE(1); ++ netfs_cancel_read(subreq, ret); + break; + + issue: + slice = netfs_prepare_read_iterator(subreq, ractl); + if (slice < 0) { + ret = slice; +- subreq->error = ret; +- trace_netfs_sreq(subreq, netfs_sreq_trace_cancel); +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } +- size -= slice; + start += slice; ++ size -= slice; ++ if (size <= 0) { ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); ++ } + +- netfs_queue_read(rreq, subreq, size <= 0); + netfs_issue_read(rreq, subreq); + cond_resched(); + } while (size > 0); +diff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c +index f72e6da88cca7..6a8fb0d55e040 100644 +--- a/fs/netfs/direct_read.c ++++ b/fs/netfs/direct_read.c +@@ -45,12 +45,11 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq) + * Perform a read to a buffer from the server, slicing up the region to be read + * according to the network rsize. + */ +-static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) ++static void netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + unsigned long long start = rreq->start; + ssize_t size = rreq->len; +- int ret = 0; ++ int ret; + + do { + struct netfs_io_subrequest *subreq; +@@ -58,7 +57,10 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + + subreq = netfs_alloc_subrequest(rreq); + if (!subreq) { +- ret = -ENOMEM; ++ /* Stash the error in the request if there's not ++ * already an error set. ++ */ ++ cmpxchg(&rreq->error, 0, -ENOMEM); + break; + } + +@@ -66,25 +68,13 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + subreq->start = start; + subreq->len = size; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { +- if (!stream->active) { +- stream->collected_to = subreq->start; +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- } +- } +- trace_netfs_sreq(subreq, netfs_sreq_trace_added); +- spin_unlock(&rreq->lock); ++ netfs_queue_read(rreq, subreq); + + netfs_stat(&netfs_n_rh_download); + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); + if (ret < 0) { +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); + break; + } + } +@@ -113,8 +103,6 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + netfs_wake_collector(rreq); + } +- +- return ret; + } + + /* +@@ -137,21 +125,17 @@ static ssize_t netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync) + // TODO: Use bounce buffer if requested + + inode_dio_begin(rreq->inode); ++ netfs_dispatch_unbuffered_reads(rreq); + +- ret = netfs_dispatch_unbuffered_reads(rreq); +- +- if (!rreq->submitted) { +- netfs_put_request(rreq, netfs_rreq_trace_put_no_submit); +- inode_dio_end(rreq->inode); +- ret = 0; +- goto out; +- } ++ /* The collector will get run, even if we don't manage to submit any ++ * subreqs, so we shouldn't call inode_dio_end() here. ++ */ + + if (sync) + ret = netfs_wait_for_read(rreq); + else + ret = -EIOCBQUEUED; +-out: ++ + _leave(" = %zd", ret); + return ret; + } +diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h +index d436e20d34185..645996ecfc803 100644 +--- a/fs/netfs/internal.h ++++ b/fs/netfs/internal.h +@@ -23,6 +23,8 @@ + /* + * buffered_read.c + */ ++void netfs_queue_read(struct netfs_io_request *rreq, ++ struct netfs_io_subrequest *subreq); + void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error); + int netfs_prefetch_for_write(struct file *file, struct folio *folio, + size_t offset, size_t len); +@@ -108,6 +110,7 @@ static inline void netfs_see_subrequest(struct netfs_io_subrequest *subreq, + */ + bool netfs_read_collection(struct netfs_io_request *rreq); + void netfs_read_collection_worker(struct work_struct *work); ++void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error); + void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error); + + /* +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index e5f6665b3341e..d2d902f466271 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -575,6 +575,17 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq) + } + EXPORT_SYMBOL(netfs_read_subreq_terminated); + ++/* ++ * Cancel a read subrequest due to preparation failure. ++ */ ++void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error) ++{ ++ trace_netfs_sreq(subreq, netfs_sreq_trace_cancel); ++ subreq->error = error; ++ __set_bit(NETFS_SREQ_FAILED, &subreq->flags); ++ netfs_read_subreq_terminated(subreq); ++} ++ + /* + * Handle termination of a read from the cache. + */ +diff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c +index d0e23bc42445f..8833550d2eb60 100644 +--- a/fs/netfs/read_single.c ++++ b/fs/netfs/read_single.c +@@ -89,7 +89,6 @@ static void netfs_single_read_cache(struct netfs_io_request *rreq, + */ + static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + struct netfs_io_subrequest *subreq; + int ret = 0; + +@@ -102,14 +101,7 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + subreq->len = rreq->len; + subreq->io_iter = rreq->buffer.iter; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- trace_netfs_sreq(subreq, netfs_sreq_trace_added); +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- spin_unlock(&rreq->lock); ++ netfs_queue_read(rreq, subreq); + + netfs_single_cache_prepare_read(rreq, subreq); + switch (subreq->source) { +@@ -121,10 +113,14 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + goto cancel; + } + ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + rreq->netfs_ops->issue_read(subreq); + rreq->submitted += subreq->len; + break; + case NETFS_READ_FROM_CACHE: ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + trace_netfs_sreq(subreq, netfs_sreq_trace_submit); + netfs_single_read_cache(rreq, subreq); + rreq->submitted += subreq->len; +@@ -134,14 +130,15 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + pr_warn("Unexpected single-read source %u\n", subreq->source); + WARN_ON_ONCE(true); + ret = -EIO; +- break; ++ goto cancel; + } + +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); + return ret; + cancel: +- netfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel); ++ netfs_cancel_read(subreq, ret); ++ smp_wmb(); /* Write lists before ALL_QUEUED. */ ++ set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); ++ netfs_wake_collector(rreq); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch b/queue-7.0/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch new file mode 100644 index 0000000000..f8f72fc30a --- /dev/null +++ b/queue-7.0/netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch @@ -0,0 +1,82 @@ +From af73bce3257a8646b32f2320d436cedcca9125f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:54 +0100 +Subject: netfs: Fix early put of sink folio in netfs_read_gaps() + +From: David Howells + +[ Upstream commit 3e5dd91b87a8b1450217b56a336bee315f40da7d ] + +Fix netfs_read_gaps() to release the sink page it uses after waiting for +the request to complete. The way the sink page is used is that an +ITER_BVEC-class iterator is created that has the gaps from the target folio +at either end, but has the sink page tiled over the middle so that a single +read op can fill in both gaps. + +The bug was found by KASAN detecting a UAF on the generic/075 xfstest in +the cifsd kernel thread that handles reception of data from the TCP socket: + + BUG: KASAN: use-after-free in _copy_to_iter+0x48a/0xa20 + Write of size 885 at addr ffff888107f92000 by task cifsd/1285 + CPU: 2 UID: 0 PID: 1285 Comm: cifsd Not tainted 7.0.0 #6 PREEMPT(lazy) + Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x17f/0x4f1 + kasan_report+0x100/0x1e0 + kasan_check_range+0x10f/0x1e0 + __asan_memcpy+0x3c/0x60 + _copy_to_iter+0x48a/0xa20 + __skb_datagram_iter+0x2c9/0x430 + skb_copy_datagram_iter+0x6e/0x160 + tcp_recvmsg_locked+0xce0/0x1130 + tcp_recvmsg+0xeb/0x300 + inet_recvmsg+0xcf/0x3a0 + sock_recvmsg+0xea/0x100 + cifs_readv_from_socket+0x3a6/0x4d0 [cifs] + cifs_read_iter_from_socket+0xdd/0x130 [cifs] + cifs_readv_receive+0xaad/0xb10 [cifs] + cifs_demultiplex_thread+0x1148/0x1740 [cifs] + kthread+0x1cf/0x210 + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Reported-by: Steve French +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-18-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 51f844bfbdff6..e7ad511e494cc 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -457,9 +457,6 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + + netfs_read_to_pagecache(rreq, NULL); + +- if (sink) +- folio_put(sink); +- + ret = netfs_wait_for_read(rreq); + if (ret >= 0) { + if (group) +@@ -471,6 +468,9 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } ++ ++ if (sink) ++ folio_put(sink); + folio_unlock(folio); + netfs_put_request(rreq, netfs_rreq_trace_put_return); + return ret < 0 ? ret : 0; +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch b/queue-7.0/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch new file mode 100644 index 0000000000..4090399289 --- /dev/null +++ b/queue-7.0/netfs-fix-folio-private-handling-in-netfs_perform_wr.patch @@ -0,0 +1,307 @@ +From 372931162569f14a2faed97fce70b887d22c13ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:58 +0100 +Subject: netfs: Fix folio->private handling in netfs_perform_write() + +From: David Howells + +[ Upstream commit ccde2ac757c713535b224233a296de40efe5212d ] + +Under some circumstances, netfs_perform_write() doesn't correctly +manipulate folio->private between NULL, NETFS_FOLIO_COPY_TO_CACHE, pointing +to a group and pointing to a netfs_folio struct, leading to potential +multiple attachments of private data with associated folio ref leaks and +also leaks of netfs_folio structs or netfs_group refs. + +Fix this by consolidating the place at which a folio is marked uptodate in +one place and having that look at what's attached to folio->private and +decide how to clean it up and then set the new group. Also, the content +shouldn't be flushed if group is NULL, even if a group is specified in the +netfs_group parameter, as that would be the case for a new folio. A +filesystem should always specify netfs_group or never specify netfs_group. + +The Sashiko auto-review tool noted that it was theoretically possible that +the fpos >= ctx->zero_point section might leak if it modified a streaming +write folio. This is unlikely, but with a network filesystem, third party +changes can happen. It also pointed out that __netfs_set_group() would +leak if called multiple times on the same folio from the "whole folio +modify section". + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-22-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 134 +++++++++++++++++++++-------------- + include/trace/events/netfs.h | 1 + + 2 files changed, 82 insertions(+), 53 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index b606c3bd84bcd..dee10570383bb 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -13,24 +13,6 @@ + #include + #include "internal.h" + +-static void __netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- if (netfs_group) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +-} +- +-static void netfs_set_group(struct folio *folio, struct netfs_group *netfs_group) +-{ +- void *priv = folio_get_private(folio); +- +- if (unlikely(priv != netfs_group)) { +- if (netfs_group && (!priv || priv == NETFS_FOLIO_COPY_TO_CACHE)) +- folio_attach_private(folio, netfs_get_group(netfs_group)); +- else if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) +- folio_detach_private(folio); +- } +-} +- + /* + * Grab a folio for writing and lock it. Attempt to allocate as large a folio + * as possible to hold as much of the remaining length as possible in one go. +@@ -158,6 +140,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + size_t offset; /* Offset into pagecache folio */ + size_t part; /* Bytes to write to folio */ + size_t copied; /* Bytes copied from user */ ++ void *priv; + + offset = pos & (max_chunk - 1); + part = min(max_chunk - offset, iov_iter_count(iter)); +@@ -203,6 +186,25 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto error_folio_unlock; + } + ++ finfo = netfs_folio_info(folio); ++ group = netfs_folio_group(folio); ++ ++ /* If the requested group differs from the group set on the ++ * page, then we need to flush out the folio if it has a group ++ * set (ie. is non-NULL). Note that COPY_TO_CACHE is a special ++ * case, being a netfs annotation rather than an actual group. ++ * ++ * The filesystem isn't permitted to mix writes with groups and ++ * writes without groups as the NULL group is used to indicate ++ * that no group is set. ++ */ ++ if (unlikely(group != netfs_group) && ++ group != NETFS_FOLIO_COPY_TO_CACHE && ++ group) { ++ WARN_ON_ONCE(!netfs_group); ++ goto flush_content; ++ } ++ + /* Decide how we should modify a folio. We might be attempting + * to do write-streaming, as we don't want to a local RMW cycle + * if we can avoid it. If we're doing local caching or content +@@ -210,22 +212,14 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + * file is open readably, then we let ->read_folio() fill in + * the gaps. + */ +- finfo = netfs_folio_info(folio); +- group = netfs_folio_group(folio); +- +- if (unlikely(group != netfs_group) && +- group != NETFS_FOLIO_COPY_TO_CACHE) +- goto flush_content; +- + if (folio_test_uptodate(folio)) { + if (mapping_writably_mapped(mapping)) + flush_dcache_folio(folio); + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_folio_is_uptodate; +- goto copied; ++ goto copied_uptodate; + } + + /* If the page is above the zero-point then we assume that the +@@ -238,24 +232,22 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + folio_zero_segment(folio, offset + copied, flen); +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_modify_and_clear; +- goto copied; ++ if (finfo) ++ trace = netfs_modify_and_clear_rm_finfo; ++ else ++ trace = netfs_modify_and_clear; ++ goto mark_uptodate; + } + + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (likely(copied == part)) { +- if (finfo) { ++ if (finfo) + trace = netfs_whole_folio_modify_filled; +- goto folio_now_filled; +- } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; +- goto copied; ++ else ++ trace = netfs_whole_folio_modify; ++ goto mark_uptodate; + } + if (copied == 0) + goto copy_failed; +@@ -273,7 +265,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += finfo->dirty_offset; + if (finfo->dirty_len == flen) { + trace = netfs_whole_folio_modify_filled_efault; +- goto folio_now_filled; ++ goto mark_uptodate; + } + if (copied > finfo->dirty_len) + finfo->dirty_len = copied; +@@ -301,11 +293,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) + goto copy_failed; +- netfs_set_group(folio, netfs_group); + trace = netfs_just_prefetch; +- goto copied; ++ goto copied_uptodate; + } + ++ /* Do a streaming write on a folio that has nothing in it yet. */ + if (!finfo) { + ret = -EIO; + if (WARN_ON(folio_get_private(folio))) +@@ -314,10 +306,8 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + if (unlikely(copied == 0)) + goto copy_failed; + if (offset == 0 && copied == flen) { +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); + trace = netfs_streaming_filled_page; +- goto copied; ++ goto mark_uptodate; + } + + finfo = kzalloc_obj(*finfo); +@@ -346,7 +336,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { + trace = netfs_streaming_cont_filled_page; +- goto folio_now_filled; ++ goto mark_uptodate; + } + trace = netfs_streaming_write_cont; + goto copied; +@@ -362,13 +352,36 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + +- folio_now_filled: +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); ++ /* Mark a folio as being up to data when we've filled it ++ * completely. If the folio has a group attached, then it must ++ * be the same group, otherwise we should have flushed it out ++ * above. We have to get rid of the netfs_folio struct if ++ * there was one. ++ */ ++ mark_uptodate: + folio_mark_uptodate(folio); +- kfree(finfo); ++ ++ copied_uptodate: ++ priv = folio_get_private(folio); ++ if (likely(priv == netfs_group)) { ++ /* Already set correctly; no change required. */ ++ } else if (priv == NETFS_FOLIO_COPY_TO_CACHE) { ++ if (!netfs_group) ++ folio_detach_private(folio); ++ else ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ } else if (!priv) { ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ } else { ++ WARN_ON_ONCE(!finfo); ++ if (netfs_group) ++ /* finfo->netfs_group has a ref */ ++ folio_change_private(folio, netfs_group); ++ else ++ folio_detach_private(folio); ++ kfree(finfo); ++ } ++ + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +@@ -531,6 +544,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + struct inode *inode = file_inode(file); + struct netfs_inode *ictx = netfs_inode(inode); + vm_fault_t ret = VM_FAULT_NOPAGE; ++ void *priv; + int err; + + _enter("%lx", folio->index); +@@ -551,7 +565,9 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + } + + group = netfs_folio_group(folio); +- if (group != netfs_group && group != NETFS_FOLIO_COPY_TO_CACHE) { ++ if (group && ++ group != netfs_group && ++ group != NETFS_FOLIO_COPY_TO_CACHE) { + folio_unlock(folio); + err = filemap_fdatawrite_range(mapping, + folio_pos(folio), +@@ -573,7 +589,19 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + trace_netfs_folio(folio, netfs_folio_trace_mkwrite_plus); + else + trace_netfs_folio(folio, netfs_folio_trace_mkwrite); +- netfs_set_group(folio, netfs_group); ++ ++ priv = folio_get_private(folio); ++ if (priv != netfs_group) { ++ if (!netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_detach_private(folio); ++ else if (netfs_group && priv == NETFS_FOLIO_COPY_TO_CACHE) ++ folio_change_private(folio, netfs_get_group(netfs_group)); ++ else if (netfs_group && !priv) ++ folio_attach_private(folio, netfs_get_group(netfs_group)); ++ else ++ WARN_ON_ONCE(1); ++ } ++ + file_update_time(file); + set_bit(NETFS_ICTX_MODIFIED_ATTR, &ictx->flags); + if (ictx->ops->post_modify) +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index db045135406c9..3fe3980902c24 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -181,6 +181,7 @@ + EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ + EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ ++ EM(netfs_modify_and_clear_rm_finfo, "mod-n-clear+") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ + EM(netfs_flush_content, "flush") \ +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch b/queue-7.0/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch new file mode 100644 index 0000000000..a34172d6aa --- /dev/null +++ b/queue-7.0/netfs-fix-leak-of-request-in-netfs_write_begin-error.patch @@ -0,0 +1,44 @@ +From f030ea9d960d06909ee7bfe3876d1e0ac2996c81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:55 +0100 +Subject: netfs: Fix leak of request in netfs_write_begin() error handling + +From: David Howells + +[ Upstream commit 5046a34f0643441f05b0253ea64e1a3af87efe14 ] + +Fix netfs_write_begin() to not leak our ref on the request in the event +that we get an error from netfs_wait_for_read(). + +Fixes: 4090b31422a6 ("netfs: Add a function to consolidate beginning a read") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-19-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index e7ad511e494cc..004d426c02b41 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -687,9 +687,9 @@ int netfs_write_begin(struct netfs_inode *ctx, + + netfs_read_to_pagecache(rreq, NULL); + ret = netfs_wait_for_read(rreq); ++ netfs_put_request(rreq, netfs_rreq_trace_put_return); + if (ret < 0) + goto error; +- netfs_put_request(rreq, netfs_rreq_trace_put_return); + + have_folio: + ret = folio_wait_private_2_killable(folio); +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-missing-barriers-when-accessing-stream-sub.patch b/queue-7.0/netfs-fix-missing-barriers-when-accessing-stream-sub.patch new file mode 100644 index 0000000000..4b3aa5b762 --- /dev/null +++ b/queue-7.0/netfs-fix-missing-barriers-when-accessing-stream-sub.patch @@ -0,0 +1,184 @@ +From a4b810d52f75b962c064e57f52692bb71ae35f5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:40 +0100 +Subject: netfs: Fix missing barriers when accessing stream->subrequests + locklessly + +From: David Howells + +[ Upstream commit b5782e2d462c028096f922abca46318cec890670 ] + +The list of subrequests attached to stream->subrequests is accessed without +locks by netfs_collect_read_results() and netfs_collect_write_results(), +and then they access subreq->flags without taking a barrier after getting +the subreq pointer from the list. Relatedly, the functions that build the +list don't use any sort of write barrier when constructing the list to make +sure that the NETFS_SREQ_IN_PROGRESS flag is perceived to be set first if +no lock is taken. + +Fix this by: + + (1) Add a new list_add_tail_release() function that uses a release barrier + to set the pointer to the new member of the list. + + (2) Add a new list_first_entry_or_null_acquire() function that uses an + acquire barrier to read the pointer to the first member in a list (or + return NULL). + + (3) Use list_add_tail_release() when adding a subreq to ->subrequests. + + (4) Use list_first_entry_or_null_acquire() when initially accessing the + front of the list (when an item is removed, the pointer to the new + front iterm is obtained under the same lock). + +Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") +Fixes: 288ace2f57c9 ("netfs: New writeback implementation") +Link: https://sashiko.dev/#/patchset/20260326104544.509518-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-4-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 3 ++- + fs/netfs/misc.c | 1 + + fs/netfs/read_collect.c | 6 ++++-- + fs/netfs/write_collect.c | 6 ++++-- + fs/netfs/write_issue.c | 3 ++- + include/linux/list.h | 37 +++++++++++++++++++++++++++++++++++++ + 6 files changed, 50 insertions(+), 6 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index a27ed501b6d43..15d73026ff643 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -168,7 +168,8 @@ void netfs_queue_read(struct netfs_io_request *rreq, + * remove entries off of the front. + */ + spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); ++ /* Write IN_PROGRESS before pointer to new subreq */ ++ list_add_tail_release(&subreq->rreq_link, &stream->subrequests); + if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { + if (!stream->active) { + stream->collected_to = subreq->start; +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 6df89c92b10b0..21357907b7eee 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -356,6 +356,7 @@ void netfs_wait_for_in_progress_stream(struct netfs_io_request *rreq, + DEFINE_WAIT(myself); + + list_for_each_entry(subreq, &stream->subrequests, rreq_link) { ++ smp_rmb(); /* Read ->next before IN_PROGRESS. */ + if (!netfs_check_subreq_in_progress(subreq)) + continue; + +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index d2d902f466271..3c9b847885c2a 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -205,8 +205,10 @@ static void netfs_collect_read_results(struct netfs_io_request *rreq) + * in progress. The issuer thread may be adding stuff to the tail + * whilst we're doing this. + */ +- front = list_first_entry_or_null(&stream->subrequests, +- struct netfs_io_subrequest, rreq_link); ++ front = list_first_entry_or_null_acquire(&stream->subrequests, ++ struct netfs_io_subrequest, rreq_link); ++ /* Read first subreq pointer before IN_PROGRESS flag. */ ++ + while (front) { + size_t transferred; + +diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c +index b194447f4b111..7fbf50907a7fc 100644 +--- a/fs/netfs/write_collect.c ++++ b/fs/netfs/write_collect.c +@@ -228,8 +228,10 @@ static void netfs_collect_write_results(struct netfs_io_request *wreq) + if (!smp_load_acquire(&stream->active)) + continue; + +- front = list_first_entry_or_null(&stream->subrequests, +- struct netfs_io_subrequest, rreq_link); ++ front = list_first_entry_or_null_acquire(&stream->subrequests, ++ struct netfs_io_subrequest, rreq_link); ++ /* Read first subreq pointer before IN_PROGRESS flag. */ ++ + while (front) { + trace_netfs_collect_sreq(wreq, front); + //_debug("sreq [%x] %llx %zx/%zx", +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index 2db688f941251..b0e9690bb90ce 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -204,7 +204,8 @@ void netfs_prepare_write(struct netfs_io_request *wreq, + * remove entries off of the front. + */ + spin_lock(&wreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); ++ /* Write IN_PROGRESS before pointer to new subreq */ ++ list_add_tail_release(&subreq->rreq_link, &stream->subrequests); + if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { + if (!stream->active) { + stream->collected_to = subreq->start; +diff --git a/include/linux/list.h b/include/linux/list.h +index 00ea8e5fb88b0..09d979976b3b8 100644 +--- a/include/linux/list.h ++++ b/include/linux/list.h +@@ -191,6 +191,29 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) + __list_add(new, head->prev, head); + } + ++/** ++ * list_add_tail_release - add a new entry with release barrier ++ * @new: new entry to be added ++ * @head: list head to add it before ++ * ++ * Insert a new entry before the specified head, using a release barrier to set ++ * the ->next pointer that points to it. This is useful for implementing ++ * queues, in particular one that the elements will be walked through forwards ++ * locklessly. ++ */ ++static inline void list_add_tail_release(struct list_head *new, ++ struct list_head *head) ++{ ++ struct list_head *prev = head->prev; ++ ++ if (__list_add_valid(new, prev, head)) { ++ new->next = head; ++ new->prev = prev; ++ head->prev = new; ++ smp_store_release(&prev->next, new); ++ } ++} ++ + /* + * Delete a list entry by making the prev/next entries + * point to each other. +@@ -644,6 +667,20 @@ static inline void list_splice_tail_init(struct list_head *list, + pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ + }) + ++/** ++ * list_first_entry_or_null_acquire - get the first element from a list with barrier ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_head within the struct. ++ * ++ * Note that if the list is empty, it returns NULL. ++ */ ++#define list_first_entry_or_null_acquire(ptr, type, member) ({ \ ++ struct list_head *head__ = (ptr); \ ++ struct list_head *pos__ = smp_load_acquire(&head__->next); \ ++ pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ ++}) ++ + /** + * list_last_entry_or_null - get the last element from a list + * @ptr: the list head to take the element from. +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-missing-locking-around-retry-adding-new-su.patch b/queue-7.0/netfs-fix-missing-locking-around-retry-adding-new-su.patch new file mode 100644 index 0000000000..5ef12ca0c2 --- /dev/null +++ b/queue-7.0/netfs-fix-missing-locking-around-retry-adding-new-su.patch @@ -0,0 +1,83 @@ +From f237c49d19a79ff104f7e77cf1adfca6940d13d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:39 +0100 +Subject: netfs: Fix missing locking around retry adding new subreqs + +From: David Howells + +[ Upstream commit cce18c263e9623872327ba3c956012f73c1179cc ] + +Fix netfs_retry_read_subrequests() and netfs_retry_write_stream() to take +the appropriate lock when adding extra subrequests into +stream->subrequests. + +Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") +Fixes: 288ace2f57c9 ("netfs: New writeback implementation") +Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-3-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/read_retry.c | 6 +++++- + fs/netfs/write_retry.c | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index cca9ac43c0773..5ec548b996d65 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -175,7 +175,9 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + list_for_each_entry_safe_from(subreq, tmp, + &stream->subrequests, rreq_link) { + trace_netfs_sreq(subreq, netfs_sreq_trace_superfluous); ++ spin_lock(&rreq->lock); + list_del(&subreq->rreq_link); ++ spin_unlock(&rreq->lock); + netfs_put_subrequest(subreq, netfs_sreq_trace_put_done); + if (subreq == to) + break; +@@ -203,8 +205,10 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + refcount_read(&subreq->ref), + netfs_sreq_trace_new); + ++ spin_lock(&rreq->lock); + list_add(&subreq->rreq_link, &to->rreq_link); +- to = list_next_entry(to, rreq_link); ++ spin_unlock(&rreq->lock); ++ to = subreq; + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + + stream->sreq_max_len = umin(len, rreq->rsize); +diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c +index 29489a23a2209..32735abfa03f0 100644 +--- a/fs/netfs/write_retry.c ++++ b/fs/netfs/write_retry.c +@@ -130,7 +130,9 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, + list_for_each_entry_safe_from(subreq, tmp, + &stream->subrequests, rreq_link) { + trace_netfs_sreq(subreq, netfs_sreq_trace_discard); ++ spin_lock(&wreq->lock); + list_del(&subreq->rreq_link); ++ spin_unlock(&wreq->lock); + netfs_put_subrequest(subreq, netfs_sreq_trace_put_done); + if (subreq == to) + break; +@@ -153,8 +155,10 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, + netfs_sreq_trace_new); + trace_netfs_sreq(subreq, netfs_sreq_trace_split); + ++ spin_lock(&wreq->lock); + list_add(&subreq->rreq_link, &to->rreq_link); +- to = list_next_entry(to, rreq_link); ++ spin_unlock(&wreq->lock); ++ to = subreq; + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + + stream->sreq_max_len = len; +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch b/queue-7.0/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch new file mode 100644 index 0000000000..1aee1bbac9 --- /dev/null +++ b/queue-7.0/netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch @@ -0,0 +1,128 @@ +From f6c7095d765e08e6d85ac9a7e9ce83375f371d33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:48 +0100 +Subject: netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes + gone + +From: David Howells + +[ Upstream commit 156ac2ec2ee77c44c4eb7439d6d165247ba12247 ] + +If a streaming write is made, this will leave the relevant modified folio +in a not-uptodate, but dirty state with a netfs_folio struct hung off of +folio->private indicating the dirty range. Subsequently truncating the +file such that the dirty data in the folio is removed, but the first part +of the folio theoretically remains will cause the netfs_folio struct to be +discarded... but will leave the dirty flag set. + +If the folio is then read via mmap(), netfs_read_folio() will see that the +page is dirty and jump to netfs_read_gaps() to fill in the missing bits. +netfs_read_gaps(), however, expects there to be a netfs_folio struct +present and can oops because truncate removed it. + +Fix this by calling folio_cancel_dirty() in netfs_invalidate_folio() in the +event that all the dirty data in the folio is erased (as nfs does). + +Also add some tracepoints to log modifications to a dirty page. + +This can be reproduced with something like: + + dd if=/dev/zero of=/xfstest.test/foo bs=1M count=1 + umount /xfstest.test + mount /xfstest.test + xfs_io -c "w 0xbbbf 0xf96c" \ + -c "truncate 0xbbbf" \ + -c "mmap -r 0xb000 0x11000" \ + -c "mr 0xb000 0x11000" \ + /xfstest.test/foo + +with fscaching disabled (otherwise streaming writes are suppressed) and a +change to netfs_perform_write() to disallow streaming writes if the fd is +open O_RDWR: + + if (//(file->f_mode & FMODE_READ) || <--- comment this out + netfs_is_cache_enabled(ctx)) { + +It should be reproducible even without this change, but if prevents the +above trivial xfs_io command from reproducing it. + +Note that the initial dd is important: the file must start out sufficiently +large that the zero-point logic doesn't just clear the gaps because it +knows there's nothing in the file to read yet. Unmounting and mounting is +needed to clear the pagecache (there are other ways to do that that may +also work). + +This was initially reproduced with the generic/522 xfstest on some patches +that remove the FMODE_READ restriction. + +Fixes: 9ebff83e6481 ("netfs: Prep to use folio->private for write grouping and streaming write") +Reported-by: Marc Dionne +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-12-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 6 +++++- + include/trace/events/netfs.h | 4 ++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 723571ca1b885..24b20e80e9a8a 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -263,6 +263,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; + finfo->dirty_offset = offset; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } + +@@ -271,12 +272,14 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + */ + if (iend >= fend) { + finfo->dirty_len = offset - fstart; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_tail); + return; + } + + /* A partial write was split. The caller has already zeroed + * it, so just absorb the hole. + */ ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_middle); + } + return; + +@@ -284,8 +287,9 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + netfs_put_group(netfs_folio_group(folio)); + folio_detach_private(folio); + folio_clear_uptodate(folio); ++ folio_cancel_dirty(folio); + kfree(finfo); +- return; ++ trace_netfs_folio(folio, netfs_folio_trace_invalidate_all); + } + EXPORT_SYMBOL(netfs_invalidate_folio); + +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index cbe28211106c5..88d814ba1e697 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -194,6 +194,10 @@ + EM(netfs_folio_trace_copy_to_cache, "mark-copy") \ + EM(netfs_folio_trace_end_copy, "end-copy") \ + EM(netfs_folio_trace_filled_gaps, "filled-gaps") \ ++ EM(netfs_folio_trace_invalidate_all, "inval-all") \ ++ EM(netfs_folio_trace_invalidate_front, "inval-front") \ ++ EM(netfs_folio_trace_invalidate_middle, "inval-mid") \ ++ EM(netfs_folio_trace_invalidate_tail, "inval-tail") \ + EM(netfs_folio_trace_kill, "kill") \ + EM(netfs_folio_trace_kill_cc, "kill-cc") \ + EM(netfs_folio_trace_kill_g, "kill-g") \ +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch b/queue-7.0/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch new file mode 100644 index 0000000000..7d71752586 --- /dev/null +++ b/queue-7.0/netfs-fix-netfs_read_folio-to-wait-on-writeback.patch @@ -0,0 +1,44 @@ +From 4979ba461c3f9f66476b38c8b6d098426b2f2512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:59 +0100 +Subject: netfs: Fix netfs_read_folio() to wait on writeback + +From: David Howells + +[ Upstream commit ded0c6f1606061148c202825f7e53d711f9f84cf ] + +Fix netfs_read_folio() to wait for an ongoing writeback to complete so that +it can trust the dirty flag and whatever is attached to folio->private +(folio->private may get cleaned up by the collector before it clears the +writeback flag). + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-23-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 83d0b8153e96e..76d0f6a29abab 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -503,6 +503,8 @@ int netfs_read_folio(struct file *file, struct folio *folio) + struct netfs_inode *ctx = netfs_inode(mapping->host); + int ret; + ++ folio_wait_writeback(folio); ++ + if (folio_test_dirty(folio)) + return netfs_read_gaps(file, folio); + +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch b/queue-7.0/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch new file mode 100644 index 0000000000..c307cb890f --- /dev/null +++ b/queue-7.0/netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch @@ -0,0 +1,44 @@ +From 5e09fdd13cde363bba69826cfe6cfe182f6e9b4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:41 +0100 +Subject: netfs: Fix netfs_read_to_pagecache() to pause on subreq failure + +From: David Howells + +[ Upstream commit 8a8c0cfdf4658fc5b295b7fc87be56e0d76741f4 ] + +Fix netfs_read_to_pagecache() so that it pauses the generation of new +subrequests if an already-issued subrequest fails. + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-5-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 15d73026ff643..fee0aebf5a3d6 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -300,6 +300,11 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + } + + netfs_issue_read(rreq, subreq); ++ ++ if (test_bit(NETFS_RREQ_PAUSE, &rreq->flags)) ++ netfs_wait_for_paused_read(rreq); ++ if (test_bit(NETFS_RREQ_FAILED, &rreq->flags)) ++ break; + cond_resched(); + } while (size > 0); + +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch b/queue-7.0/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch new file mode 100644 index 0000000000..3f6197f7ad --- /dev/null +++ b/queue-7.0/netfs-fix-overrun-check-in-netfs_extract_user_iter.patch @@ -0,0 +1,80 @@ +From 1cffd51744d7044924085d3ee43edbcf64e00bcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:47 +0100 +Subject: netfs: Fix overrun check in netfs_extract_user_iter() + +From: David Howells + +[ Upstream commit 0ef37eef83fad3542ee06db2940433ae1a92b39d ] + +Fix netfs_extract_user_iter() so that if iov_iter_extract_pages() overfills +pages[], then those pages don't get included in the iterator constructed at +the end of the function. If there was an overfill, memory corruption has +already happened. + +Fixes: 85dd2c8ff368 ("netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-11-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/iterator.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c +index 429e4396e1b00..b375567e0520e 100644 +--- a/fs/netfs/iterator.c ++++ b/fs/netfs/iterator.c +@@ -72,21 +72,24 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + break; + } + +- if (ret > count) { +- pr_err("get_pages rc=%zd more than %zu\n", ret, count); ++ if (WARN(ret > count, ++ "%s: extract_pages overrun %zd > %zu bytes\n", ++ __func__, ret, count)) { ++ ret = -EIO; + break; + } + +- count -= ret; +- ret += offset; +- cur_npages = DIV_ROUND_UP(ret, PAGE_SIZE); +- +- if (npages + cur_npages > max_pages) { +- pr_err("Out of bvec array capacity (%u vs %u)\n", +- npages + cur_npages, max_pages); ++ cur_npages = DIV_ROUND_UP(offset + ret, PAGE_SIZE); ++ if (WARN(cur_npages > max_pages - npages, ++ "%s: extract_pages overrun %u > %u pages\n", ++ __func__, npages + cur_npages, max_pages)) { ++ ret = -EIO; + break; + } + ++ count -= ret; ++ ret += offset; ++ + for (i = 0; i < cur_npages; i++) { + len = ret > PAGE_SIZE ? PAGE_SIZE : ret; + bvec_set_page(bv + npages + i, *pages++, len - offset, offset); +@@ -97,6 +100,11 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, + npages += cur_npages; + } + ++ /* Note: Don't try to clean up after EIO. Either we got no pages, so ++ * nothing to clean up, or we got a buffer overrun, memory corruption ++ * and can't trust the stuff in the buffer (a WARN was emitted). ++ */ ++ + if (ret < 0 && (ret == -ENOMEM || npages == 0)) { + for (i = 0; i < npages; i++) + unpin_user_page(bv[i].bv_page); +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-partial-invalidation-of-streaming-write-fo.patch b/queue-7.0/netfs-fix-partial-invalidation-of-streaming-write-fo.patch new file mode 100644 index 0000000000..ea1a9458db --- /dev/null +++ b/queue-7.0/netfs-fix-partial-invalidation-of-streaming-write-fo.patch @@ -0,0 +1,49 @@ +From af8c27e18adc93fd2a38b15ef48d5b8b4fd437c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:57 +0100 +Subject: netfs: Fix partial invalidation of streaming-write folio + +From: David Howells + +[ Upstream commit 6d91acc7fb85d33ea58fca9b964a32a453937f4b ] + +In netfs_invalidate_folio(), if the region of a partial invalidation +overlaps the front (but not all) of a dirty write cached in a streaming +write page (dirty, but not uptodate, with the dirty region tracked by a +netfs_folio struct), the function modifies the dirty region - but +incorrectly as it moves the region forward by setting the start to the +start, not the end, of the invalidation region. + +Fix this by setting finfo->dirty_offset to the end of the invalidation +region (iend). + +Fixes: cce6bfa6ca0e ("netfs: Fix trimming of streaming-write folios in netfs_inval_folio()") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-21-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 24b20e80e9a8a..5d554512ed23a 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -262,7 +262,7 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + goto erase_completely; + /* Move the start of the data. */ + finfo->dirty_len = fend - iend; +- finfo->dirty_offset = offset; ++ finfo->dirty_offset = iend; + trace_netfs_folio(folio, netfs_folio_trace_invalidate_front); + return; + } +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-potential-deadlock-in-write-through-mode.patch b/queue-7.0/netfs-fix-potential-deadlock-in-write-through-mode.patch new file mode 100644 index 0000000000..4adadfa0d6 --- /dev/null +++ b/queue-7.0/netfs-fix-potential-deadlock-in-write-through-mode.patch @@ -0,0 +1,119 @@ +From debc74d077f0538654d318e095b6c3b5de075439 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:51 +0100 +Subject: netfs: Fix potential deadlock in write-through mode + +From: David Howells + +[ Upstream commit b6a4ae1634b3ad2aaa05222e53d36da532852faf ] + +Fix netfs_advance_writethrough() to always unlock the supplied folio and to +mark it dirty if it isn't yet written to the end. Unfortunately, it can't +be marked for writeback until the folio is done with as that may cause a +deadlock against mmapped reads and writes. + +Even though it has been marked dirty, premature writeback can't occur as +the caller is holding both inode->i_rwsem (which will prevent concurrent +truncation, fallocation, DIO and other writes) and ictx->wb_lock (which +will cause flushing to wait and writeback to skip or wait). + +Note that this may be easier to deal with once the queuing of folios is +split from the generation of subrequests. + +Fixes: 288ace2f57c9 ("netfs: New writeback implementation") +Closes: https://sashiko.dev/#/patchset/20260427154639.180684-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-15-dhowells@redhat.com +cc: Paulo Alcantara +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/write_issue.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index b0e9690bb90ce..03961622996be 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -414,12 +414,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq, + if (streamw) + netfs_issue_write(wreq, cache); + +- /* Flip the page to the writeback state and unlock. If we're called +- * from write-through, then the page has already been put into the wb +- * state. +- */ +- if (wreq->origin == NETFS_WRITEBACK) +- folio_start_writeback(folio); ++ folio_start_writeback(folio); + folio_unlock(folio); + + if (fgroup == NETFS_FOLIO_COPY_TO_CACHE) { +@@ -647,29 +642,41 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c + struct folio *folio, size_t copied, bool to_page_end, + struct folio **writethrough_cache) + { ++ int ret; ++ + _enter("R=%x ic=%zu ws=%u cp=%zu tp=%u", + wreq->debug_id, wreq->buffer.iter.count, wreq->wsize, copied, to_page_end); + +- if (!*writethrough_cache) { +- if (folio_test_dirty(folio)) +- /* Sigh. mmap. */ +- folio_clear_dirty_for_io(folio); ++ /* The folio is locked. */ + ++ if (*writethrough_cache != folio) { ++ if (*writethrough_cache) { ++ /* Did the folio get moved? */ ++ folio_put(*writethrough_cache); ++ *writethrough_cache = NULL; ++ } + /* We can make multiple writes to the folio... */ +- folio_start_writeback(folio); + if (wreq->len == 0) + trace_netfs_folio(folio, netfs_folio_trace_wthru); + else + trace_netfs_folio(folio, netfs_folio_trace_wthru_plus); + *writethrough_cache = folio; ++ folio_get(folio); + } + + wreq->len += copied; +- if (!to_page_end) ++ ++ if (!to_page_end) { ++ folio_mark_dirty(folio); ++ folio_unlock(folio); + return 0; ++ } + ++ ret = netfs_write_folio(wreq, wbc, folio); ++ folio_put(*writethrough_cache); + *writethrough_cache = NULL; +- return netfs_write_folio(wreq, wbc, folio); ++ wreq->submitted = wreq->len; ++ return ret; + } + + /* +@@ -683,8 +690,12 @@ ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_c + + _enter("R=%x", wreq->debug_id); + +- if (writethrough_cache) ++ if (writethrough_cache) { ++ folio_lock(writethrough_cache); + netfs_write_folio(wreq, wbc, writethrough_cache); ++ folio_put(writethrough_cache); ++ wreq->submitted = wreq->len; ++ } + + netfs_end_issue_write(wreq); + +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-potential-for-tearing-in-remote_i_size-and.patch b/queue-7.0/netfs-fix-potential-for-tearing-in-remote_i_size-and.patch new file mode 100644 index 0000000000..ce177e7c5c --- /dev/null +++ b/queue-7.0/netfs-fix-potential-for-tearing-in-remote_i_size-and.patch @@ -0,0 +1,1140 @@ +From 40cbc0720e93092d863b35fcf1cd88c17e03da22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:42 +0100 +Subject: netfs: Fix potential for tearing in ->remote_i_size and ->zero_point + +From: David Howells + +[ Upstream commit 2c8f4742bb76117d735f92a3932d85239b16c494 ] + +Fix potential tearing in using ->remote_i_size and ->zero_point by copying +i_size_read() and i_size_write() and using the same seqcount as for i_size. + +We need to make sure that netfslib and the filesystems that use it always +hold i_lock whilst updating any of the sizes to prevent i_size_seqcount +from getting corrupted. + +Fixes: 4058f742105e ("netfs: Keep track of the actual remote file size") +Fixes: 100ccd18bb41 ("netfs: Optimise away reads above the point at which there can be no data") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-6-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/9p/v9fs_vfs.h | 13 -- + fs/9p/vfs_inode.c | 6 +- + fs/9p/vfs_inode_dotl.c | 12 +- + fs/afs/file.c | 24 +++- + fs/afs/inode.c | 31 ++-- + fs/afs/internal.h | 11 +- + fs/afs/write.c | 2 +- + fs/netfs/buffered_read.c | 6 +- + fs/netfs/buffered_write.c | 2 +- + fs/netfs/direct_write.c | 6 +- + fs/netfs/misc.c | 32 +++-- + fs/netfs/write_collect.c | 9 +- + fs/smb/client/cifsfs.c | 38 +++-- + fs/smb/client/cifssmb.c | 3 +- + fs/smb/client/file.c | 13 +- + fs/smb/client/inode.c | 14 +- + fs/smb/client/readdir.c | 3 +- + fs/smb/client/smb2ops.c | 42 +++--- + fs/smb/client/smb2pdu.c | 3 +- + include/linux/netfs.h | 293 ++++++++++++++++++++++++++++++++++++-- + 20 files changed, 450 insertions(+), 113 deletions(-) + +diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h +index d3aefbec4de6e..34c115d7c2502 100644 +--- a/fs/9p/v9fs_vfs.h ++++ b/fs/9p/v9fs_vfs.h +@@ -75,17 +75,4 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode) + + int v9fs_open_to_dotl_flags(int flags); + +-static inline void v9fs_i_size_write(struct inode *inode, loff_t i_size) +-{ +- /* +- * 32-bit need the lock, concurrent updates could break the +- * sequences and make i_size_read() loop forever. +- * 64-bit updates are atomic and can skip the locking. +- */ +- if (sizeof(i_size) > sizeof(long)) +- spin_lock(&inode->i_lock); +- i_size_write(inode, i_size); +- if (sizeof(i_size) > sizeof(long)) +- spin_unlock(&inode->i_lock); +-} + #endif +diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c +index 97abe65bf7c1f..a0a5aec8e5d53 100644 +--- a/fs/9p/vfs_inode.c ++++ b/fs/9p/vfs_inode.c +@@ -1141,11 +1141,13 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; + +- v9inode->netfs.remote_i_size = stat->length; ++ spin_lock(&inode->i_lock); ++ netfs_write_remote_i_size(inode, stat->length); + if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE)) +- v9fs_i_size_write(inode, stat->length); ++ i_size_write(inode, stat->length); + /* not real number of blocks, but 512 byte ones ... */ + inode->i_blocks = (stat->length + 512 - 1) >> 9; ++ spin_unlock(&inode->i_lock); + v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR; + } + +diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c +index 643e759eacb2a..d800f4fad555c 100644 +--- a/fs/9p/vfs_inode_dotl.c ++++ b/fs/9p/vfs_inode_dotl.c +@@ -634,10 +634,12 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode, + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; + +- v9inode->netfs.remote_i_size = stat->st_size; ++ spin_lock(&inode->i_lock); ++ netfs_write_remote_i_size(inode, stat->st_size); + if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE)) +- v9fs_i_size_write(inode, stat->st_size); ++ i_size_write(inode, stat->st_size); + inode->i_blocks = stat->st_blocks; ++ spin_unlock(&inode->i_lock); + } else { + if (stat->st_result_mask & P9_STATS_ATIME) { + inode_set_atime(inode, stat->st_atime_sec, +@@ -662,13 +664,15 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode, + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; + } ++ spin_lock(&inode->i_lock); + if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) && + stat->st_result_mask & P9_STATS_SIZE) { +- v9inode->netfs.remote_i_size = stat->st_size; +- v9fs_i_size_write(inode, stat->st_size); ++ netfs_write_remote_i_size(inode, stat->st_size); ++ i_size_write(inode, stat->st_size); + } + if (stat->st_result_mask & P9_STATS_BLOCKS) + inode->i_blocks = stat->st_blocks; ++ spin_unlock(&inode->i_lock); + } + if (stat->st_result_mask & P9_STATS_GEN) + inode->i_generation = stat->st_gen; +diff --git a/fs/afs/file.c b/fs/afs/file.c +index 74d04af51ff4a..650595e1c3f37 100644 +--- a/fs/afs/file.c ++++ b/fs/afs/file.c +@@ -424,21 +424,35 @@ static void afs_free_request(struct netfs_io_request *rreq) + afs_put_wb_key(rreq->netfs_priv2); + } + +-static void afs_update_i_size(struct inode *inode, loff_t new_i_size) ++/* ++ * Set the file size and block count, taking ->cb_lock and ->i_lock to maintain ++ * coherency and prevent 64-bit tearing on 32-bit arches. ++ * ++ * Also, estimate the number of 512 bytes blocks used, rounded up to nearest 1K ++ * for consistency with other AFS clients. ++ */ ++void afs_set_i_size(struct afs_vnode *vnode, loff_t new_i_size) + { +- struct afs_vnode *vnode = AFS_FS_I(inode); ++ struct inode *inode = &vnode->netfs.inode; + loff_t i_size; + + write_seqlock(&vnode->cb_lock); +- i_size = i_size_read(&vnode->netfs.inode); ++ spin_lock(&inode->i_lock); ++ i_size = i_size_read(inode); + if (new_i_size > i_size) { +- i_size_write(&vnode->netfs.inode, new_i_size); +- inode_set_bytes(&vnode->netfs.inode, new_i_size); ++ i_size_write(inode, new_i_size); ++ inode_set_bytes(inode, round_up(new_i_size, 1024)); + } ++ spin_unlock(&inode->i_lock); + write_sequnlock(&vnode->cb_lock); + fscache_update_cookie(afs_vnode_cache(vnode), NULL, &new_i_size); + } + ++static void afs_update_i_size(struct inode *inode, loff_t new_i_size) ++{ ++ afs_set_i_size(AFS_FS_I(inode), new_i_size); ++} ++ + static void afs_netfs_invalidate_cache(struct netfs_io_request *wreq) + { + struct afs_vnode *vnode = AFS_FS_I(wreq->inode); +diff --git a/fs/afs/inode.c b/fs/afs/inode.c +index dde1857fcabb3..df95b39ed308e 100644 +--- a/fs/afs/inode.c ++++ b/fs/afs/inode.c +@@ -224,7 +224,8 @@ static int afs_inode_init_from_status(struct afs_operation *op, + return afs_protocol_error(NULL, afs_eproto_file_type); + } + +- afs_set_i_size(vnode, status->size); ++ i_size_write(inode, status->size); ++ inode_set_bytes(inode, status->size); + afs_set_netfs_context(vnode); + + vnode->invalid_before = status->data_version; +@@ -253,7 +254,8 @@ static void afs_apply_status(struct afs_operation *op, + { + struct afs_file_status *status = &vp->scb.status; + struct afs_vnode *vnode = vp->vnode; +- struct inode *inode = &vnode->netfs.inode; ++ struct netfs_inode *ictx = &vnode->netfs; ++ struct inode *inode = &ictx->inode; + struct timespec64 t; + umode_t mode; + bool unexpected_jump = false; +@@ -336,6 +338,8 @@ static void afs_apply_status(struct afs_operation *op, + } + + if (data_changed) { ++ unsigned long long zero_point, size = status->size; ++ + inode_set_iversion_raw(inode, status->data_version); + + /* Only update the size if the data version jumped. If the +@@ -343,16 +347,25 @@ static void afs_apply_status(struct afs_operation *op, + * idea of what the size should be that's not the same as + * what's on the server. + */ +- vnode->netfs.remote_i_size = status->size; +- if (change_size || status->size > i_size_read(inode)) { +- afs_set_i_size(vnode, status->size); ++ spin_lock(&inode->i_lock); ++ ++ if (change_size || size > i_size_read(inode)) { ++ /* We can read the sizes directly as we hold i_lock. */ ++ zero_point = ictx->_zero_point; ++ + if (unexpected_jump) +- vnode->netfs.zero_point = status->size; ++ zero_point = size; ++ netfs_write_sizes(inode, size, size, zero_point); ++ inode_set_bytes(inode, size); + inode_set_ctime_to_ts(inode, t); + inode_set_atime_to_ts(inode, t); ++ } else { ++ netfs_write_remote_i_size(inode, size); + } ++ spin_unlock(&inode->i_lock); ++ + if (op->ops == &afs_fetch_data_operation) +- op->fetch.subreq->rreq->i_size = status->size; ++ op->fetch.subreq->rreq->i_size = size; + } + } + +@@ -709,7 +722,7 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path, + * it, but we need to give userspace the server's size. + */ + if (S_ISDIR(inode->i_mode)) +- stat->size = vnode->netfs.remote_i_size; ++ stat->size = netfs_read_remote_i_size(inode); + } while (read_seqretry(&vnode->cb_lock, seq)); + + return 0; +@@ -889,7 +902,7 @@ int afs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + */ + if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) && + attr->ia_size < i_size && +- attr->ia_size > vnode->netfs.remote_i_size) { ++ attr->ia_size > netfs_read_remote_i_size(inode)) { + truncate_setsize(inode, attr->ia_size); + netfs_resize_file(&vnode->netfs, size, false); + fscache_resize_cookie(afs_vnode_cache(vnode), +diff --git a/fs/afs/internal.h b/fs/afs/internal.h +index 009064b8d6616..fb0449d024ff2 100644 +--- a/fs/afs/internal.h ++++ b/fs/afs/internal.h +@@ -1158,6 +1158,7 @@ extern int afs_open(struct inode *, struct file *); + extern int afs_release(struct inode *, struct file *); + void afs_fetch_data_async_rx(struct work_struct *work); + void afs_fetch_data_immediate_cancel(struct afs_call *call); ++void afs_set_i_size(struct afs_vnode *vnode, loff_t new_i_size); + + /* + * flock.c +@@ -1759,16 +1760,6 @@ static inline void afs_update_dentry_version(struct afs_operation *op, + (void *)(unsigned long)dir_vp->scb.status.data_version; + } + +-/* +- * Set the file size and block count. Estimate the number of 512 bytes blocks +- * used, rounded up to nearest 1K for consistency with other AFS clients. +- */ +-static inline void afs_set_i_size(struct afs_vnode *vnode, u64 size) +-{ +- i_size_write(&vnode->netfs.inode, size); +- vnode->netfs.inode.i_blocks = ((size + 1023) >> 10) << 1; +-} +- + /* + * Check for a conflicting operation on a directory that we just unlinked from. + * If someone managed to sneak a link or an unlink in on the file we just +diff --git a/fs/afs/write.c b/fs/afs/write.c +index 93ad86ff33453..e2ef19a73bbfc 100644 +--- a/fs/afs/write.c ++++ b/fs/afs/write.c +@@ -143,7 +143,7 @@ static void afs_issue_write_worker(struct work_struct *work) + afs_begin_vnode_operation(op); + + op->store.write_iter = &subreq->io_iter; +- op->store.i_size = umax(pos + len, vnode->netfs.remote_i_size); ++ op->store.i_size = umax(pos + len, netfs_read_remote_i_size(&vnode->netfs.inode)); + op->mtime = inode_get_mtime(&vnode->netfs.inode); + + afs_wait_for_operation(op); +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index fee0aebf5a3d6..ebd84a6cc3f09 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -209,7 +209,6 @@ static void netfs_issue_read(struct netfs_io_request *rreq, + static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + struct readahead_control *ractl) + { +- struct netfs_inode *ictx = netfs_inode(rreq->inode); + unsigned long long start = rreq->start; + ssize_t size = rreq->len; + int ret = 0; +@@ -233,7 +232,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + source = netfs_cache_prepare_read(rreq, subreq, rreq->i_size); + subreq->source = source; + if (source == NETFS_DOWNLOAD_FROM_SERVER) { +- unsigned long long zp = umin(ictx->zero_point, rreq->i_size); ++ unsigned long long zero_point = netfs_read_zero_point(rreq->inode); ++ unsigned long long zp = umin(zero_point, rreq->i_size); + size_t len = subreq->len; + + if (unlikely(rreq->origin == NETFS_READ_SINGLE)) +@@ -249,7 +249,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq, + pr_err("ZERO-LEN READ: R=%08x[%x] l=%zx/%zx s=%llx z=%llx i=%llx", + rreq->debug_id, subreq->debug_index, + subreq->len, size, +- subreq->start, ictx->zero_point, rreq->i_size); ++ subreq->start, zero_point, rreq->i_size); + netfs_cancel_read(subreq, ret); + break; + } +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 22a4d61631c9d..c887a30c14d91 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -231,7 +231,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + * server would just return a block of zeros or a short read if + * we try to read it. + */ +- if (fpos >= ctx->zero_point) { ++ if (fpos >= netfs_read_zero_point(inode)) { + folio_zero_segment(folio, 0, offset); + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); + if (unlikely(copied == 0)) +diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c +index f9ab69de3e298..25f8ceb15fad6 100644 +--- a/fs/netfs/direct_write.c ++++ b/fs/netfs/direct_write.c +@@ -376,8 +376,10 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from) + if (ret < 0) + goto out; + end = iocb->ki_pos + iov_iter_count(from); +- if (end > ictx->zero_point) +- ictx->zero_point = end; ++ spin_lock(&inode->i_lock); ++ if (end > ictx->_zero_point) ++ netfs_write_zero_point(inode, end); ++ spin_unlock(&inode->i_lock); + + fscache_invalidate(netfs_i_cookie(ictx), NULL, i_size_read(inode), + FSCACHE_INVAL_DIO_WRITE); +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index 21357907b7eee..bad661ff2bec8 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -211,18 +211,25 @@ EXPORT_SYMBOL(netfs_clear_inode_writeback); + void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length) + { + struct netfs_folio *finfo; +- struct netfs_inode *ctx = netfs_inode(folio_inode(folio)); ++ struct inode *inode = folio_inode(folio); ++ struct netfs_inode *ctx = netfs_inode(inode); + size_t flen = folio_size(folio); + + _enter("{%lx},%zx,%zx", folio->index, offset, length); + + if (offset == 0 && length == flen) { +- unsigned long long i_size = i_size_read(&ctx->inode); ++ unsigned long long i_size, remote_i_size, zero_point; + unsigned long long fpos = folio_pos(folio), end; + ++ netfs_read_sizes(inode, &i_size, &remote_i_size, &zero_point); + end = umin(fpos + flen, i_size); +- if (fpos < i_size && end > ctx->zero_point) +- ctx->zero_point = end; ++ if (fpos < i_size && end > zero_point) { ++ spin_lock(&inode->i_lock); ++ end = umin(fpos + flen, inode->i_size); ++ if (fpos < i_size && end > ctx->_zero_point) ++ netfs_write_zero_point(inode, end); ++ spin_unlock(&inode->i_lock); ++ } + } + + folio_wait_private_2(folio); /* [DEPRECATED] */ +@@ -292,15 +299,22 @@ EXPORT_SYMBOL(netfs_invalidate_folio); + */ + bool netfs_release_folio(struct folio *folio, gfp_t gfp) + { +- struct netfs_inode *ctx = netfs_inode(folio_inode(folio)); +- unsigned long long end; ++ struct inode *inode = folio_inode(folio); ++ struct netfs_inode *ctx = netfs_inode(inode); ++ unsigned long long i_size, remote_i_size, zero_point, end; + + if (folio_test_dirty(folio)) + return false; + +- end = umin(folio_next_pos(folio), i_size_read(&ctx->inode)); +- if (end > ctx->zero_point) +- ctx->zero_point = end; ++ netfs_read_sizes(inode, &i_size, &remote_i_size, &zero_point); ++ end = umin(folio_next_pos(folio), i_size); ++ if (end > zero_point) { ++ spin_lock(&inode->i_lock); ++ end = umin(folio_next_pos(folio), inode->i_size); ++ if (end > ctx->_zero_point) ++ netfs_write_zero_point(inode, end); ++ spin_unlock(&inode->i_lock); ++ } + + if (folio_test_private(folio)) + return false; +diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c +index 7fbf50907a7fc..24fc2bb2f8a47 100644 +--- a/fs/netfs/write_collect.c ++++ b/fs/netfs/write_collect.c +@@ -57,7 +57,8 @@ static void netfs_dump_request(const struct netfs_io_request *rreq) + int netfs_folio_written_back(struct folio *folio) + { + enum netfs_folio_trace why = netfs_folio_trace_clear; +- struct netfs_inode *ictx = netfs_inode(folio->mapping->host); ++ struct inode *inode = folio_inode(folio); ++ struct netfs_inode *ictx = netfs_inode(inode); + struct netfs_folio *finfo; + struct netfs_group *group = NULL; + int gcount = 0; +@@ -69,8 +70,10 @@ int netfs_folio_written_back(struct folio *folio) + unsigned long long fend; + + fend = folio_pos(folio) + finfo->dirty_offset + finfo->dirty_len; +- if (fend > ictx->zero_point) +- ictx->zero_point = fend; ++ spin_lock(&ictx->inode.i_lock); ++ if (fend > ictx->_zero_point) ++ netfs_write_zero_point(inode, fend); ++ spin_unlock(&ictx->inode.i_lock); + + folio_detach_private(folio); + group = finfo->netfs_group; +diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c +index 32d0305a1239a..941670de16f3c 100644 +--- a/fs/smb/client/cifsfs.c ++++ b/fs/smb/client/cifsfs.c +@@ -468,7 +468,8 @@ cifs_alloc_inode(struct super_block *sb) + spin_lock_init(&cifs_inode->writers_lock); + cifs_inode->writers = 0; + cifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +- cifs_inode->netfs.remote_i_size = 0; ++ cifs_inode->netfs._remote_i_size = 0; ++ cifs_inode->netfs._zero_point = 0; + cifs_inode->uniqueid = 0; + cifs_inode->createtime = 0; + cifs_inode->epoch = 0; +@@ -1336,7 +1337,8 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, + struct cifsFileInfo *smb_file_src = src_file->private_data; + struct cifsFileInfo *smb_file_target = dst_file->private_data; + struct cifs_tcon *target_tcon, *src_tcon; +- unsigned long long destend, fstart, fend, old_size, new_size; ++ unsigned long long i_size, old_size, new_size, zero_point; ++ unsigned long long destend, fstart, fend; + unsigned int xid; + int rc; + +@@ -1380,7 +1382,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, + * Advance the EOF marker after the flush above to the end of the range + * if it's short of that. + */ +- if (src_cifsi->netfs.remote_i_size < off + len) { ++ if (netfs_read_remote_i_size(src_inode) < off + len) { + rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); + if (rc < 0) + goto unlock; +@@ -1401,16 +1403,18 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, + rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); + if (rc) + goto unlock; +- if (fend > target_cifsi->netfs.zero_point) +- target_cifsi->netfs.zero_point = fend + 1; +- old_size = target_cifsi->netfs.remote_i_size; ++ ++ spin_lock(&target_inode->i_lock); ++ if (fend > zero_point) ++ netfs_write_zero_point(target_inode, fend + 1); ++ i_size = target_inode->i_size; ++ spin_unlock(&target_inode->i_lock); + + /* Discard all the folios that overlap the destination region. */ + cifs_dbg(FYI, "about to discard pages %llx-%llx\n", fstart, fend); + truncate_inode_pages_range(&target_inode->i_data, fstart, fend); + +- fscache_invalidate(cifs_inode_cookie(target_inode), NULL, +- i_size_read(target_inode), 0); ++ fscache_invalidate(cifs_inode_cookie(target_inode), NULL, i_size, 0); + + rc = -EOPNOTSUPP; + if (target_tcon->ses->server->ops->duplicate_extents) { +@@ -1435,8 +1439,12 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, + rc = -EINVAL; + } + } +- if (rc == 0 && new_size > target_cifsi->netfs.zero_point) +- target_cifsi->netfs.zero_point = new_size; ++ if (rc == 0) { ++ spin_lock(&target_inode->i_lock); ++ if (new_size > target_cifsi->netfs._zero_point) ++ netfs_write_zero_point(target_inode, new_size); ++ spin_unlock(&target_inode->i_lock); ++ } + } + + /* force revalidate of size and timestamps of target file now +@@ -1507,7 +1515,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, + * Advance the EOF marker after the flush above to the end of the range + * if it's short of that. + */ +- if (src_cifsi->netfs.remote_i_size < off + len) { ++ if (netfs_read_remote_i_size(src_inode) < off + len) { + rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); + if (rc < 0) + goto unlock; +@@ -1535,8 +1543,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, + fscache_resize_cookie(cifs_inode_cookie(target_inode), + i_size_read(target_inode)); + } +- if (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point) +- target_cifsi->netfs.zero_point = destoff + rc; ++ if (rc > 0) { ++ spin_lock(&target_inode->i_lock); ++ if (destoff + rc > target_cifsi->netfs._zero_point) ++ netfs_write_zero_point(target_inode, destoff + rc); ++ spin_unlock(&target_inode->i_lock); ++ } + } + + file_accessed(src_file); +diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c +index 3990a90122640..9e27bfa7376b1 100644 +--- a/fs/smb/client/cifssmb.c ++++ b/fs/smb/client/cifssmb.c +@@ -1465,6 +1465,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) + struct cifs_io_subrequest *rdata = mid->callback_data; + struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); ++ struct inode *inode = &ictx->inode; + struct smb_rqst rqst = { .rq_iov = rdata->iov, + .rq_nvec = 1, + .rq_iter = rdata->subreq.io_iter }; +@@ -1538,7 +1539,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) + } else { + size_t trans = rdata->subreq.transferred + rdata->got_bytes; + if (trans < rdata->subreq.len && +- rdata->subreq.start + trans >= ictx->remote_i_size) { ++ rdata->subreq.start + trans >= netfs_read_remote_i_size(inode)) { + rdata->result = 0; + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + } else if (rdata->got_bytes > 0) { +diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c +index a69e05f86d7e2..ad624c01193eb 100644 +--- a/fs/smb/client/file.c ++++ b/fs/smb/client/file.c +@@ -2491,18 +2491,23 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) + void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result) + { + struct netfs_io_request *wreq = wdata->rreq; +- struct netfs_inode *ictx = netfs_inode(wreq->inode); ++ struct inode *inode = wreq->inode; ++ struct netfs_inode *ictx = netfs_inode(inode); + loff_t wrend; + + if (result > 0) { ++ spin_lock(&inode->i_lock); ++ + wrend = wdata->subreq.start + wdata->subreq.transferred + result; + +- if (wrend > ictx->zero_point && ++ if (wrend > ictx->_zero_point && + (wdata->rreq->origin == NETFS_UNBUFFERED_WRITE || + wdata->rreq->origin == NETFS_DIO_WRITE)) +- ictx->zero_point = wrend; +- if (wrend > ictx->remote_i_size) ++ netfs_write_zero_point(inode, wrend); ++ if (wrend > ictx->_remote_i_size) + netfs_resize_file(ictx, wrend, true); ++ ++ spin_unlock(&inode->i_lock); + } + + netfs_write_subrequest_terminated(&wdata->subreq, result); +diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c +index 888f9e35f14b8..5b1beba77c0ec 100644 +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -119,7 +119,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) + fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); + mtime = inode_get_mtime(inode); + if (timespec64_equal(&mtime, &fattr->cf_mtime) && +- cifs_i->netfs.remote_i_size == fattr->cf_eof) { ++ netfs_read_remote_i_size(inode) == fattr->cf_eof) { + cifs_dbg(FYI, "%s: inode %llu is unchanged\n", + __func__, cifs_i->uniqueid); + return; +@@ -173,12 +173,12 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, + CIFS_I(inode)->time = 0; /* force reval */ + return -ESTALE; + } +- if (inode_state_read_once(inode) & I_NEW) +- CIFS_I(inode)->netfs.zero_point = fattr->cf_eof; +- + cifs_revalidate_cache(inode, fattr); + + spin_lock(&inode->i_lock); ++ if (inode_state_read_once(inode) & I_NEW) ++ netfs_write_zero_point(inode, fattr->cf_eof); ++ + fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); + fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode); + fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode); +@@ -212,7 +212,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, + else + clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); + +- cifs_i->netfs.remote_i_size = fattr->cf_eof; ++ netfs_write_remote_i_size(inode, fattr->cf_eof); + /* + * Can't safely change the file size here if the client is writing to + * it due to potential races. +@@ -2771,7 +2771,9 @@ cifs_revalidate_mapping(struct inode *inode) + if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RW_CACHE) + goto skip_invalidate; + +- cifs_inode->netfs.zero_point = cifs_inode->netfs.remote_i_size; ++ spin_lock(&inode->i_lock); ++ netfs_write_zero_point(inode, netfs_inode(inode)->_remote_i_size); ++ spin_unlock(&inode->i_lock); + rc = filemap_invalidate_inode(inode, true, 0, LLONG_MAX); + if (rc) { + cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", +diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c +index be22bbc4a65a0..e860fa08b5e30 100644 +--- a/fs/smb/client/readdir.c ++++ b/fs/smb/client/readdir.c +@@ -143,7 +143,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, + fattr->cf_rdev = inode->i_rdev; + fattr->cf_uid = inode->i_uid; + fattr->cf_gid = inode->i_gid; +- fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size; ++ fattr->cf_eof = ++ netfs_read_remote_i_size(inode); + fattr->cf_symlink_target = NULL; + } else { + CIFS_I(inode)->time = 0; +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index ccc06c83956b5..f4c95cc26db21 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -3402,8 +3402,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, + struct inode *inode = file_inode(file); + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct cifsFileInfo *cfile = file->private_data; +- struct netfs_inode *ictx = netfs_inode(inode); +- unsigned long long i_size, new_size, remote_size; ++ unsigned long long i_size, new_size, remote_i_size, zero_point; + long rc; + unsigned int xid; + +@@ -3414,9 +3413,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, + + filemap_invalidate_lock(inode->i_mapping); + +- i_size = i_size_read(inode); +- remote_size = ictx->remote_i_size; +- if (offset + len >= remote_size && offset < i_size) { ++ netfs_read_sizes(inode, &i_size, &remote_i_size, &zero_point); ++ if (offset + len >= remote_i_size && offset < i_size) { + unsigned long long top = umin(offset + len, i_size); + + rc = filemap_write_and_wait_range(inode->i_mapping, offset, top - 1); +@@ -3449,9 +3447,11 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, + cfile->fid.volatile_fid, cfile->pid, new_size); + if (rc >= 0) { + truncate_setsize(inode, new_size); ++ spin_lock(&inode->i_lock); + netfs_resize_file(&cifsi->netfs, new_size, true); +- if (offset < cifsi->netfs.zero_point) +- cifsi->netfs.zero_point = offset; ++ if (offset < cifsi->netfs._zero_point) ++ netfs_write_zero_point(inode, offset); ++ spin_unlock(&inode->i_lock); + fscache_resize_cookie(cifs_inode_cookie(inode), new_size); + } + } +@@ -3474,7 +3474,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + struct inode *inode = file_inode(file); + struct cifsFileInfo *cfile = file->private_data; + struct file_zero_data_information fsctl_buf; +- unsigned long long end = offset + len, i_size, remote_i_size; ++ unsigned long long end = offset + len, i_size, remote_i_size, zero_point; + long rc; + unsigned int xid; + __u8 set_sparse = 1; +@@ -3516,14 +3516,17 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + * that we locally hole-punch the tail of the dirty data, the proposed + * EOF update will end up in the wrong place. + */ +- i_size = i_size_read(inode); +- remote_i_size = netfs_inode(inode)->remote_i_size; ++ netfs_read_sizes(inode, &i_size, &remote_i_size, &zero_point); ++ + if (end > remote_i_size && i_size > remote_i_size) { + unsigned long long extend_to = umin(end, i_size); + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, extend_to); +- if (rc >= 0) +- netfs_inode(inode)->remote_i_size = extend_to; ++ if (rc >= 0) { ++ spin_lock(&inode->i_lock); ++ netfs_write_remote_i_size(inode, extend_to); ++ spin_unlock(&inode->i_lock); ++ } + } + + unlock: +@@ -3787,7 +3790,6 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + struct inode *inode = file_inode(file); + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct cifsFileInfo *cfile = file->private_data; +- struct netfs_inode *ictx = &cifsi->netfs; + loff_t old_eof, new_eof; + + xid = get_xid(); +@@ -3805,7 +3807,9 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + goto out_2; + + truncate_pagecache_range(inode, off, old_eof); +- ictx->zero_point = old_eof; ++ spin_lock(&inode->i_lock); ++ netfs_write_zero_point(inode, old_eof); ++ spin_unlock(&inode->i_lock); + netfs_wait_for_outstanding_io(inode); + + rc = smb2_copychunk_range(xid, cfile, cfile, off + len, +@@ -3822,8 +3826,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + rc = 0; + + truncate_setsize(inode, new_eof); ++ spin_lock(&inode->i_lock); + netfs_resize_file(&cifsi->netfs, new_eof, true); +- ictx->zero_point = new_eof; ++ netfs_write_zero_point(inode, new_eof); ++ spin_unlock(&inode->i_lock); + fscache_resize_cookie(cifs_inode_cookie(inode), new_eof); + out_2: + filemap_invalidate_unlock(inode->i_mapping); +@@ -3866,13 +3872,17 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, + goto out_2; + + truncate_setsize(inode, new_eof); ++ spin_lock(&inode->i_lock); + netfs_resize_file(&cifsi->netfs, i_size_read(inode), true); ++ spin_unlock(&inode->i_lock); + fscache_resize_cookie(cifs_inode_cookie(inode), i_size_read(inode)); + + rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len); + if (rc < 0) + goto out_2; +- cifsi->netfs.zero_point = new_eof; ++ spin_lock(&inode->i_lock); ++ netfs_write_zero_point(inode, new_eof); ++ spin_unlock(&inode->i_lock); + + rc = smb3_zero_data(file, tcon, off, len, xid); + if (rc < 0) +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 5188218c25be4..967047894a1e6 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -4596,6 +4596,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) + struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); + struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base; ++ struct inode *inode = &ictx->inode; + struct cifs_credits credits = { + .value = 0, + .instance = 0, +@@ -4709,7 +4710,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) + } else { + size_t trans = rdata->subreq.transferred + rdata->got_bytes; + if (trans < rdata->subreq.len && +- rdata->subreq.start + trans >= ictx->remote_i_size) { ++ rdata->subreq.start + trans >= netfs_read_remote_i_size(inode)) { + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + rdata->result = 0; + } +diff --git a/include/linux/netfs.h b/include/linux/netfs.h +index ba17ac5bf356a..4fd1d796ad73b 100644 +--- a/include/linux/netfs.h ++++ b/include/linux/netfs.h +@@ -62,8 +62,8 @@ struct netfs_inode { + struct fscache_cookie *cache; + #endif + struct mutex wb_lock; /* Writeback serialisation */ +- loff_t remote_i_size; /* Size of the remote file */ +- loff_t zero_point; /* Size after which we assume there's no data ++ loff_t _remote_i_size; /* Size of the remote file */ ++ loff_t _zero_point; /* Size after which we assume there's no data + * on the server */ + atomic_t io_count; /* Number of outstanding reqs */ + unsigned long flags; +@@ -474,6 +474,254 @@ static inline struct netfs_inode *netfs_inode(struct inode *inode) + return container_of(inode, struct netfs_inode, inode); + } + ++/** ++ * netfs_read_remote_i_size - Read remote_i_size safely ++ * @inode: The inode to access ++ * ++ * Read remote_i_size safely without the potential for tearing on 32-bit ++ * arches. ++ * ++ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the ++ * i_size_read/write must be atomic with respect to the local cpu (unlike with ++ * preempt disabled), but they don't need to be atomic with respect to other ++ * cpus like in true SMP (so they need either to either locally disable irq ++ * around the read or for example on x86 they can be still implemented as a ++ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit ++ * archs it makes no difference if preempt is enabled or not. ++ */ ++static inline unsigned long long netfs_read_remote_i_size(const struct inode *inode) ++{ ++ const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode); ++ unsigned long long remote_i_size; ++ ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ unsigned int seq; ++ ++ do { ++ seq = read_seqcount_begin(&inode->i_size_seqcount); ++ remote_i_size = ictx->_remote_i_size; ++ } while (read_seqcount_retry(&inode->i_size_seqcount, seq)); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ remote_i_size = ictx->_remote_i_size; ++ preempt_enable(); ++#else ++ /* Pairs with smp_store_release() in netfs_write_remote_i_size() */ ++ remote_i_size = smp_load_acquire(&ictx->_remote_i_size); ++#endif ++ return remote_i_size; ++} ++ ++/* ++ * netfs_write_remote_i_size - Set remote_i_size safely ++ * @inode: The inode to access ++ * @remote_i_size: The new value for the size of the file on the server ++ * ++ * Set remote_i_size safely without the potential for tearing on 32-bit arches. ++ * ++ * Context: The caller must hold inode->i_lock. ++ * ++ * NOTE: unlike netfs_read_remote_i_size(), netfs_write_remote_i_size() does ++ * need locking around it (normally i_rwsem), otherwise on 32bit/SMP an update ++ * of i_size_seqcount can be lost, resulting in subsequent i_size_read() calls ++ * spinning forever. ++ */ ++static inline void netfs_write_remote_i_size(struct inode *inode, ++ unsigned long long remote_i_size) ++{ ++ struct netfs_inode *ictx = netfs_inode(inode); ++ ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ write_seqcount_begin(&inode->i_size_seqcount); ++ ictx->_remote_i_size = remote_i_size; ++ write_seqcount_end(&inode->i_size_seqcount); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ ictx->_remote_i_size = remote_i_size; ++ preempt_enable(); ++#else ++ /* ++ * Pairs with smp_load_acquire() in netfs_read_remote_i_size() to ++ * ensure changes related to inode size (such as page contents) are ++ * visible before we see the changed inode size. ++ */ ++ smp_store_release(&ictx->_remote_i_size, remote_i_size); ++#endif ++} ++ ++/** ++ * netfs_read_zero_point - Read zero_point safely ++ * @inode: The inode to access ++ * ++ * Read zero_point safely without the potential for tearing on 32-bit ++ * arches. ++ * ++ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the ++ * i_size_read/write must be atomic with respect to the local cpu (unlike with ++ * preempt disabled), but they don't need to be atomic with respect to other ++ * cpus like in true SMP (so they need either to either locally disable irq ++ * around the read or for example on x86 they can be still implemented as a ++ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit ++ * archs it makes no difference if preempt is enabled or not. ++ */ ++static inline unsigned long long netfs_read_zero_point(const struct inode *inode) ++{ ++ struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode); ++ unsigned long long zero_point; ++ ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ unsigned int seq; ++ ++ do { ++ seq = read_seqcount_begin(&inode->i_size_seqcount); ++ zero_point = ictx->_zero_point; ++ } while (read_seqcount_retry(&inode->i_size_seqcount, seq)); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ zero_point = ictx->_zero_point; ++ preempt_enable(); ++#else ++ /* Pairs with smp_store_release() in netfs_write_zero_point() */ ++ zero_point = smp_load_acquire(&ictx->_zero_point); ++#endif ++ return zero_point; ++} ++ ++/* ++ * netfs_write_zero_point - Set zero_point safely ++ * @inode: The inode to access ++ * @zero_point: The new value for the point beyond which the server has no data ++ * ++ * Set zero_point safely without the potential for tearing on 32-bit arches. ++ * ++ * Context: The caller must hold inode->i_lock. ++ * ++ * NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need ++ * locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of ++ * i_size_seqcount can be lost, resulting in subsequent read calls spinning ++ * forever. ++ */ ++static inline void netfs_write_zero_point(struct inode *inode, ++ unsigned long long zero_point) ++{ ++ struct netfs_inode *ictx = netfs_inode(inode); ++ ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ write_seqcount_begin(&inode->i_size_seqcount); ++ ictx->_zero_point = zero_point; ++ write_seqcount_end(&inode->i_size_seqcount); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ ictx->_zero_point = zero_point; ++ preempt_enable(); ++#else ++ /* ++ * Pairs with smp_load_acquire() in netfs_read_zero_point() to ++ * ensure changes related to inode size (such as page contents) are ++ * visible before we see the changed inode size. ++ */ ++ smp_store_release(&ictx->_zero_point, zero_point); ++#endif ++} ++ ++/** ++ * netfs_read_sizes - Read remote_i_size and zero_point safely ++ * @inode: The inode to access ++ * @i_size: Where to return the local file size. ++ * @remote_i_size: Where to return the size of the file on the server ++ * @zero_point: Where to return the the point beyond which the server has no data ++ * ++ * Read remote_i_size and zero_point safely without the potential for tearing ++ * on 32-bit arches. ++ * ++ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the ++ * i_size_read/write must be atomic with respect to the local cpu (unlike with ++ * preempt disabled), but they don't need to be atomic with respect to other ++ * cpus like in true SMP (so they need either to either locally disable irq ++ * around the read or for example on x86 they can be still implemented as a ++ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit ++ * archs it makes no difference if preempt is enabled or not. ++ */ ++static inline void netfs_read_sizes(const struct inode *inode, ++ unsigned long long *i_size, ++ unsigned long long *remote_i_size, ++ unsigned long long *zero_point) ++{ ++ const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode); ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ unsigned int seq; ++ ++ do { ++ seq = read_seqcount_begin(&inode->i_size_seqcount); ++ *i_size = inode->i_size; ++ *remote_i_size = ictx->_remote_i_size; ++ *zero_point = ictx->_zero_point; ++ } while (read_seqcount_retry(&inode->i_size_seqcount, seq)); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ *i_size = inode->i_size; ++ *remote_i_size = ictx->_remote_i_size; ++ *zero_point = ictx->_zero_point; ++ preempt_enable(); ++#else ++ /* Pairs with smp_store_release() in i_size_write() */ ++ *i_size = smp_load_acquire(&inode->i_size); ++ /* Pairs with smp_store_release() in netfs_write_remote_i_size() */ ++ *remote_i_size = smp_load_acquire(&ictx->_remote_i_size); ++ /* Pairs with smp_store_release() in netfs_write_zero_point() */ ++ *zero_point = smp_load_acquire(&ictx->_zero_point); ++#endif ++} ++ ++/* ++ * netfs_write_sizes - Set i_size, remote_i_size and zero_point safely ++ * @inode: The inode to access ++ * @i_size: The new value for the local size of the file ++ * @remote_i_size: The new value for the size of the file on the server ++ * @zero_point: The new value for the point beyond which the server has no data ++ * ++ * Set both remote_i_size and zero_point safely without the potential for ++ * tearing on 32-bit arches. ++ * ++ * Context: The caller must hold inode->i_lock. ++ * ++ * NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need ++ * locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of ++ * i_size_seqcount can be lost, resulting in subsequent read calls spinning ++ * forever. ++ */ ++static inline void netfs_write_sizes(struct inode *inode, ++ unsigned long long i_size, ++ unsigned long long remote_i_size, ++ unsigned long long zero_point) ++{ ++ struct netfs_inode *ictx = netfs_inode(inode); ++ ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ write_seqcount_begin(&inode->i_size_seqcount); ++ inode->i_size = i_size; ++ ictx->_remote_i_size = remote_i_size; ++ ictx->_zero_point = zero_point; ++ write_seqcount_end(&inode->i_size_seqcount); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); ++ inode->i_size = i_size; ++ ictx->_remote_i_size = remote_i_size; ++ ictx->_zero_point = zero_point; ++ preempt_enable(); ++#else ++ /* ++ * Pairs with smp_load_acquire() in i_size_read(), ++ * netfs_read_remote_i_size() and netfs_read_zero_point() to ensure ++ * changes related to inode size (such as page contents) are visible ++ * before we see the changed inode size. ++ */ ++ smp_store_release(&inode->i_size, i_size); ++ smp_store_release(&ictx->_remote_i_size, remote_i_size); ++ smp_store_release(&ictx->_zero_point, zero_point); ++#endif ++} ++ + /** + * netfs_inode_init - Initialise a netfslib inode context + * @ctx: The netfs inode to initialise +@@ -488,8 +736,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, + bool use_zero_point) + { + ctx->ops = ops; +- ctx->remote_i_size = i_size_read(&ctx->inode); +- ctx->zero_point = LLONG_MAX; ++ ctx->_remote_i_size = i_size_read(&ctx->inode); ++ ctx->_zero_point = LLONG_MAX; + ctx->flags = 0; + atomic_set(&ctx->io_count, 0); + #if IS_ENABLED(CONFIG_FSCACHE) +@@ -498,7 +746,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, + mutex_init(&ctx->wb_lock); + /* ->releasepage() drives zero_point */ + if (use_zero_point) { +- ctx->zero_point = ctx->remote_i_size; ++ ctx->_zero_point = ctx->_remote_i_size; + mapping_set_release_always(ctx->inode.i_mapping); + } + } +@@ -511,13 +759,40 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, + * + * Inform the netfs lib that a file got resized so that it can adjust its state. + */ +-static inline void netfs_resize_file(struct netfs_inode *ctx, loff_t new_i_size, ++static inline void netfs_resize_file(struct netfs_inode *ictx, ++ unsigned long long new_i_size, + bool changed_on_server) + { ++#if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ struct inode *inode = &ictx->inode; ++ ++ preempt_disable(); ++ write_seqcount_begin(&inode->i_size_seqcount); ++ if (changed_on_server) ++ ictx->_remote_i_size = new_i_size; ++ if (new_i_size < ictx->_zero_point) ++ ictx->_zero_point = new_i_size; ++ write_seqcount_end(&inode->i_size_seqcount); ++ preempt_enable(); ++#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION) ++ preempt_disable(); + if (changed_on_server) +- ctx->remote_i_size = new_i_size; +- if (new_i_size < ctx->zero_point) +- ctx->zero_point = new_i_size; ++ ictx->_remote_i_size = new_i_size; ++ if (new_i_size < ictx->_zero_point) ++ ictx->_zero_point = new_i_size; ++ preempt_enable(); ++#else ++ /* ++ * Pairs with smp_load_acquire() in netfs_read_remote_i_size and ++ * netfs_read_zero_point() to ensure changes related to inode size ++ * (such as page contents) are visible before we see the changed inode ++ * size. ++ */ ++ if (changed_on_server) ++ smp_store_release(&ictx->_remote_i_size, new_i_size); ++ if (new_i_size < ictx->_zero_point) ++ smp_store_release(&ictx->_zero_point, new_i_size); ++#endif + } + + /** +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch b/queue-7.0/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch new file mode 100644 index 0000000000..1535ece610 --- /dev/null +++ b/queue-7.0/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch @@ -0,0 +1,104 @@ +From dba2257d7c1b33e553204569bccfe6aa02dd6bd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:56 +0100 +Subject: netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages() + +From: David Howells + +[ Upstream commit dbe556972100fabb8e5a1b3d2163831ff07b1e8e ] + +netfs_unlock_abandoned_read_pages(rreq) accesses the index of the folios it +is wanting to unlock and compares that to rreq->no_unlock_folio so that it +doesn't unlock a folio being read for netfs_perform_write() or +netfs_write_begin(). + +However, given that netfs_unlock_abandoned_read_pages() is called _after_ +NETFS_RREQ_IN_PROGRESS is cleared, the one folio that it's not allowed to +dereference is the one specified by ->no_unlock_folio as ownership +immediately reverts to the caller. + +Fix this by storing the folio pointer instead and using that rather than +the index. Also fix netfs_unlock_read_folio() where the same applies. + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-20-dhowells@redhat.com +cc: Paulo Alcantara +cc: Viacheslav Dubeyko +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 4 ++-- + fs/netfs/read_collect.c | 2 +- + fs/netfs/read_retry.c | 2 +- + include/linux/netfs.h | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index 004d426c02b41..83d0b8153e96e 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -670,7 +670,7 @@ int netfs_write_begin(struct netfs_inode *ctx, + ret = PTR_ERR(rreq); + goto error; + } +- rreq->no_unlock_folio = folio->index; ++ rreq->no_unlock_folio = folio; + __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); + + ret = netfs_begin_cache_read(rreq, ctx); +@@ -736,7 +736,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio, + goto error; + } + +- rreq->no_unlock_folio = folio->index; ++ rreq->no_unlock_folio = folio; + __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); + ret = netfs_begin_cache_read(rreq, ctx); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index 3c9b847885c2a..23660a5901246 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -83,7 +83,7 @@ static void netfs_unlock_read_folio(struct netfs_io_request *rreq, + } + + just_unlock: +- if (folio->index == rreq->no_unlock_folio && ++ if (folio == rreq->no_unlock_folio && + test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) { + _debug("no unlock"); + } else { +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index e10eb5a073326..f59a70f3a086b 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -292,7 +292,7 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq) + struct folio *folio = folioq_folio(p, slot); + + if (folio && !folioq_is_marked2(p, slot)) { +- if (folio->index == rreq->no_unlock_folio && ++ if (folio == rreq->no_unlock_folio && + test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, + &rreq->flags)) { + _debug("no unlock"); +diff --git a/include/linux/netfs.h b/include/linux/netfs.h +index 4fd1d796ad73b..243c0f7379388 100644 +--- a/include/linux/netfs.h ++++ b/include/linux/netfs.h +@@ -252,7 +252,7 @@ struct netfs_io_request { + unsigned long long collected_to; /* Point we've collected to */ + unsigned long long cleaned_to; /* Position we've cleaned folios to */ + unsigned long long abandon_to; /* Position to abandon folios to */ +- pgoff_t no_unlock_folio; /* Don't unlock this folio after read */ ++ const struct folio *no_unlock_folio; /* Don't unlock this folio after read */ + unsigned int direct_bv_count; /* Number of elements in direct_bv[] */ + unsigned int debug_id; + unsigned int rsize; /* Maximum read size (0 for none) */ +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch b/queue-7.0/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch new file mode 100644 index 0000000000..3691131704 --- /dev/null +++ b/queue-7.0/netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch @@ -0,0 +1,93 @@ +From 9c7bc4d8964e0a86a6a947d986fc280ea15778ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:52 +0100 +Subject: netfs: Fix read-gaps to remove netfs_folio from filled folio + +From: David Howells + +[ Upstream commit a41168aef634356a9b87ec44349e3c82835700a5 ] + +Fix netfs_read_gaps() to remove the netfs_folio record from the folio +record before marking the folio uptodate if it successfully fills the gaps +around the dirty data in a streaming write folio (dirty, but not uptodate). + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0x138b1 0x8b15d * + write 0x507ee 0x10df7 0x927c0 + write 0x19993 0x10e04 0x927c0 * + mapwrite 0x66214 0x1a253 0x927c0 + copy_range 0xb704 0x89b9 0x24429 0x79380 + write 0x2402b 0x144a2 0x90660 * + mapwrite 0x204d5 0x140a0 0x927c0 * + copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 * + read 0 0x9157c 0x9157c + +on cifs with the default cache option. + +It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in +netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-16-dhowells@redhat.com +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_read.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index ebd84a6cc3f09..51f844bfbdff6 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -395,6 +395,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + { + struct netfs_io_request *rreq; + struct address_space *mapping = folio->mapping; ++ struct netfs_group *group = netfs_folio_group(folio); + struct netfs_folio *finfo = netfs_folio_info(folio); + struct netfs_inode *ctx = netfs_inode(mapping->host); + struct folio *sink = NULL; +@@ -461,6 +462,12 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + + ret = netfs_wait_for_read(rreq); + if (ret >= 0) { ++ if (group) ++ folio_change_private(folio, group); ++ else ++ folio_detach_private(folio); ++ kfree(finfo); ++ trace_netfs_folio(folio, netfs_folio_trace_filled_gaps); + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } +@@ -496,10 +503,8 @@ int netfs_read_folio(struct file *file, struct folio *folio) + struct netfs_inode *ctx = netfs_inode(mapping->host); + int ret; + +- if (folio_test_dirty(folio)) { +- trace_netfs_folio(folio, netfs_folio_trace_read_gaps); ++ if (folio_test_dirty(folio)) + return netfs_read_gaps(file, folio); +- } + + _enter("%lx", folio->index); + +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-streaming-write-being-overwritten.patch b/queue-7.0/netfs-fix-streaming-write-being-overwritten.patch new file mode 100644 index 0000000000..7f1eef6811 --- /dev/null +++ b/queue-7.0/netfs-fix-streaming-write-being-overwritten.patch @@ -0,0 +1,176 @@ +From 78ffc14b9cecb276a8095887f6e541f267032815 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:50 +0100 +Subject: netfs: Fix streaming write being overwritten + +From: David Howells + +[ Upstream commit 7b4dcf1b9455a6e52ac7478b4057dbe10359576d ] + +In order to avoid reading whilst writing, netfslib will allow "streaming +writes" in which dirty data is stored directly into folios without reading +them first. Such folios are marked dirty but may not be marked uptodate. +If a folio is entirely written by a streaming write, uptodate will be set, +otherwise it will have a netfs_folio struct attached to ->private recording +the dirty region. + +In the event that a partially written streaming write page is to be +overwritten entirely by a single write(), netfs_perform_write() will try to +copy over it, but doesn't discard the netfs_folio if it succeeds; further, +it doesn't correctly handle a partial copy that overwrites some of the +dirty data. + +Fix this by the following: + + (1) If the folio is successfully overwritten, free the netfs_folio struct + before marking the page uptodate. + + (2) If the copy to the folio partially fails, but short of the dirty data, + just ignore the copy. + + (3) If the copy partially fails and overwrites some of the dirty data, + accept the copy, update the netfs_folio struct to record the new data. + If the folio is now filled, free the netfs_folio and set uptodate, + otherwise return a partial write. + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0 0x927c0 + write 0x63fb8 0x53c8 0 + copy_range 0xb704 0x19b9 0x24429 0x79380 + write 0x2402b 0x144a2 0x90660 * + write 0x204d5 0x140a0 0x927c0 * + copy_range 0x1f72c 0x137d0 0x7a906 0x927c0 * + read 0x00000 0x20000 0x9157c + read 0x20000 0x20000 0x9157c + read 0x40000 0x20000 0x9157c + read 0x60000 0x20000 0x9157c + read 0x7e1a0 0xcfb9 0x9157c + +on cifs with the default cache option. + +It shows folio 0x24 misbehaving if the FMODE_READ check is commented out in +netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Fixes: 8f52de0077ba ("netfs: Reduce number of conditional branches in netfs_perform_write()") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-14-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 47 ++++++++++++++++++++++++++---------- + include/trace/events/netfs.h | 3 +++ + 2 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index a695d5168b2fc..0ff4c790ae263 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -247,18 +247,38 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + /* See if we can write a whole folio in one go. */ + if (!maybe_trouble && offset == 0 && part >= flen) { + copied = copy_folio_from_iter_atomic(folio, offset, part, iter); +- if (unlikely(copied == 0)) ++ if (likely(copied == part)) { ++ if (finfo) { ++ trace = netfs_whole_folio_modify_filled; ++ goto folio_now_filled; ++ } ++ __netfs_set_group(folio, netfs_group); ++ folio_mark_uptodate(folio); ++ trace = netfs_whole_folio_modify; ++ goto copied; ++ } ++ if (copied == 0) + goto copy_failed; +- if (unlikely(copied < part)) { ++ if (!finfo || copied <= finfo->dirty_offset) { + maybe_trouble = true; + iov_iter_revert(iter, copied); + copied = 0; + folio_unlock(folio); + goto retry; + } +- __netfs_set_group(folio, netfs_group); +- folio_mark_uptodate(folio); +- trace = netfs_whole_folio_modify; ++ ++ /* We overwrote some existing dirty data, so we have to ++ * accept the partial write. ++ */ ++ finfo->dirty_len += finfo->dirty_offset; ++ if (finfo->dirty_len == flen) { ++ trace = netfs_whole_folio_modify_filled_efault; ++ goto folio_now_filled; ++ } ++ if (copied > finfo->dirty_len) ++ finfo->dirty_len = copied; ++ finfo->dirty_offset = 0; ++ trace = netfs_whole_folio_modify_efault; + goto copied; + } + +@@ -328,16 +348,10 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto copy_failed; + finfo->dirty_len += copied; + if (finfo->dirty_offset == 0 && finfo->dirty_len == flen) { +- if (finfo->netfs_group) +- folio_change_private(folio, finfo->netfs_group); +- else +- folio_detach_private(folio); +- folio_mark_uptodate(folio); +- kfree(finfo); + trace = netfs_streaming_cont_filled_page; +- } else { +- trace = netfs_streaming_write_cont; ++ goto folio_now_filled; + } ++ trace = netfs_streaming_write_cont; + goto copied; + } + +@@ -351,6 +365,13 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + goto out; + continue; + ++ folio_now_filled: ++ if (finfo->netfs_group) ++ folio_change_private(folio, finfo->netfs_group); ++ else ++ folio_detach_private(folio); ++ folio_mark_uptodate(folio); ++ kfree(finfo); + copied: + trace_netfs_folio(folio, trace); + flush_dcache_folio(folio); +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index 88d814ba1e697..db045135406c9 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -177,6 +177,9 @@ + EM(netfs_folio_is_uptodate, "mod-uptodate") \ + EM(netfs_just_prefetch, "mod-prefetch") \ + EM(netfs_whole_folio_modify, "mod-whole-f") \ ++ EM(netfs_whole_folio_modify_efault, "mod-whole-f!") \ ++ EM(netfs_whole_folio_modify_filled, "mod-whole-f+") \ ++ EM(netfs_whole_folio_modify_filled_efault, "mod-whole-f+!") \ + EM(netfs_modify_and_clear, "mod-n-clear") \ + EM(netfs_streaming_write, "mod-streamw") \ + EM(netfs_streaming_write_cont, "mod-streamw+") \ +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch b/queue-7.0/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch new file mode 100644 index 0000000000..e9a40d0019 --- /dev/null +++ b/queue-7.0/netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch @@ -0,0 +1,169 @@ +From 966dc76ccb8c9baf0ce219ef09638d33b335422a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:44 +0100 +Subject: netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call + +From: Viacheslav Dubeyko + +[ Upstream commit dc7832d05deb4d632e8035e3299e31a3528fa0d0 ] + +The multiple runs of generic/013 test-case is capable +to reproduce a kernel BUG at mm/filemap.c:1504 with +probability of 30%. + +while true; do + sudo ./check generic/013 +done + +[ 9849.452376] page: refcount:3 mapcount:0 mapping:00000000e58ff252 index:0x10781 pfn:0x1c322 +[ 9849.452412] memcg:ffff8881a1915800 +[ 9849.452417] aops:ceph_aops ino:1000058db9e dentry name(?):"f9XXXXXX" +[ 9849.452432] flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff) +[ 9849.452441] raw: 0017ffffc0000000 0000000000000000 dead000000000122 ffff88816110d248 +[ 9849.452445] raw: 0000000000010781 0000000000000000 00000003ffffffff ffff8881a1915800 +[ 9849.452447] page dumped because: VM_BUG_ON_FOLIO(!folio_test_locked(folio)) +[ 9849.452474] ------------[ cut here ]------------ +[ 9849.452476] kernel BUG at mm/filemap.c:1504! +[ 9849.478635] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +[ 9849.481772] CPU: 2 UID: 0 PID: 84223 Comm: fsstress Not tainted 7.0.0-rc1+ #18 PREEMPT(full) +[ 9849.482881] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/1 +0/2025 +[ 9849.484539] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.485076] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc +cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.493818] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.495740] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.498678] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.500559] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.501097] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.502108] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.502516] FS: 00007e36cbe94740(0000) GS:ffff88824a899000(0000) knlGS:0000000000000000 +[ 9849.502996] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.503810] CR2: 000000c0002b0000 CR3: 000000011bbf6004 CR4: 0000000000772ef0 +[ 9849.504459] PKRU: 55555554 +[ 9849.504626] Call Trace: +[ 9849.505242] +[ 9849.505379] netfs_write_begin+0x7c8/0x10a0 +[ 9849.505877] ? __kasan_check_read+0x11/0x20 +[ 9849.506384] ? __pfx_netfs_write_begin+0x10/0x10 +[ 9849.507178] ceph_write_begin+0x8c/0x1c0 +[ 9849.507934] generic_perform_write+0x391/0x8f0 +[ 9849.508503] ? __pfx_generic_perform_write+0x10/0x10 +[ 9849.509062] ? file_update_time_flags+0x19a/0x4b0 +[ 9849.509581] ? ceph_get_caps+0x63/0xf0 +[ 9849.510259] ? ceph_get_caps+0x63/0xf0 +[ 9849.510530] ceph_write_iter+0xe79/0x1ae0 +[ 9849.511282] ? __pfx_ceph_write_iter+0x10/0x10 +[ 9849.511839] ? lock_acquire+0x1ad/0x310 +[ 9849.512334] ? ksys_write+0xf9/0x230 +[ 9849.512582] ? lock_is_held_type+0xaa/0x140 +[ 9849.513128] vfs_write+0x512/0x1110 +[ 9849.513634] ? __fget_files+0x33/0x350 +[ 9849.513893] ? __pfx_vfs_write+0x10/0x10 +[ 9849.514143] ? mutex_lock_nested+0x1b/0x30 +[ 9849.514394] ksys_write+0xf9/0x230 +[ 9849.514621] ? __pfx_ksys_write+0x10/0x10 +[ 9849.514887] ? do_syscall_64+0x25e/0x1520 +[ 9849.515122] ? __kasan_check_read+0x11/0x20 +[ 9849.515366] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.515655] __x64_sys_write+0x72/0xd0 +[ 9849.515885] ? trace_hardirqs_on+0x24/0x1c0 +[ 9849.516130] x64_sys_call+0x22f/0x2390 +[ 9849.516341] do_syscall_64+0x12b/0x1520 +[ 9849.516545] ? do_syscall_64+0x27c/0x1520 +[ 9849.516783] ? do_syscall_64+0x27c/0x1520 +[ 9849.517003] ? lock_release+0x318/0x480 +[ 9849.517220] ? __x64_sys_io_getevents+0x143/0x2d0 +[ 9849.517479] ? percpu_ref_put_many.constprop.0+0x8f/0x210 +[ 9849.517779] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.518073] ? do_syscall_64+0x25e/0x1520 +[ 9849.518291] ? __kasan_check_read+0x11/0x20 +[ 9849.518519] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.518799] ? do_syscall_64+0x27c/0x1520 +[ 9849.519024] ? local_clock_noinstr+0xf/0x120 +[ 9849.519262] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.519544] ? do_syscall_64+0x25e/0x1520 +[ 9849.519781] ? __kasan_check_read+0x11/0x20 +[ 9849.520008] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520273] ? do_syscall_64+0x27c/0x1520 +[ 9849.520491] ? trace_hardirqs_on_prepare+0x178/0x1c0 +[ 9849.520767] ? irqentry_exit+0x10c/0x6c0 +[ 9849.520984] ? trace_hardirqs_off+0x86/0x1b0 +[ 9849.521224] ? exc_page_fault+0xab/0x130 +[ 9849.521472] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 9849.521766] RIP: 0033:0x7e36cbd14907 +[ 9849.521989] Code: 10 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 9849.523057] RSP: 002b:00007ffff2d2a968 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 9849.523484] RAX: ffffffffffffffda RBX: 000000000000e549 RCX: 00007e36cbd14907 +[ 9849.523885] RDX: 000000000000e549 RSI: 00005bd797ec6370 RDI: 0000000000000004 +[ 9849.524277] RBP: 0000000000000004 R08: 0000000000000047 R09: 00005bd797ec6370 +[ 9849.524652] R10: 0000000000000078 R11: 0000000000000246 R12: 0000000000000049 +[ 9849.525062] R13: 0000000010781a37 R14: 00005bd797ec6370 R15: 0000000000000000 +[ 9849.525447] +[ 9849.525574] Modules linked in: intel_rapl_msr intel_rapl_common intel_uncore_frequency_common intel_pmc_core pmt_telemetry pmt_discovery pmt_class intel_pmc_ssram_telemetry intel_vsec kvm_intel joydev kvm irqbypass ghash_clmulni_intel aesni_intel input_leds rapl mac_hid psmouse vga16fb serio_raw vgastate floppy i2c_piix4 bochs qemu_fw_cfg i2c_smbus pata_acpi sch_fq_codel rbd msr parport_pc ppdev lp parport efi_pstore +[ 9849.529150] ---[ end trace 0000000000000000 ]--- +[ 9849.529502] RIP: 0010:folio_unlock+0x85/0xa0 +[ 9849.530813] Code: 89 df 31 f6 e8 1c f3 ff ff 48 8b 5d f8 c9 31 c0 31 d2 31 f6 31 ff c3 cc cc cc cc 48 c7 c6 80 6c d9 a7 48 89 df e8 4b b3 10 00 <0f> 0b 48 89 df e8 21 e6 2c 00 eb 9d 0f 1f 40 00 66 66 2e 0f 1f 84 +[ 9849.534986] RSP: 0018:ffff8881bb8076b0 EFLAGS: 00010246 +[ 9849.536198] RAX: 0000000000000000 RBX: ffffea00070c8980 RCX: 0000000000000000 +[ 9849.537718] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 +[ 9849.539321] RBP: ffff8881bb8076b8 R08: 0000000000000000 R09: 0000000000000000 +[ 9849.540862] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000010782000 +[ 9849.542438] R13: ffff8881935de738 R14: ffff88816110d010 R15: 0000000000001000 +[ 9849.543996] FS: 00007e36cbe94740(0000) GS:ffff88824b899000(0000) knlGS:0000000000000000 +[ 9849.545854] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 9849.547092] CR2: 00007e36cb3ff000 CR3: 000000011bbf6006 CR4: 0000000000772ef0 +[ 9849.548679] PKRU: 55555554 + +The race sequence: +1. Read completes -> netfs_read_collection() runs +2. netfs_wake_rreq_flag(rreq, NETFS_RREQ_IN_PROGRESS, ...) +3. netfs_wait_for_read() returns -EFAULT to netfs_write_begin() +4. The netfs_unlock_abandoned_read_pages() unlocks the folio +5. netfs_write_begin() calls folio_unlock(folio) -> VM_BUG_ON_FOLIO() + +The key reason of the issue that netfs_unlock_abandoned_read_pages() +doesn't check the flag NETFS_RREQ_NO_UNLOCK_FOLIO and executes +folio_unlock() unconditionally. This patch implements in +netfs_unlock_abandoned_read_pages() logic similar to +netfs_unlock_read_folio(). + +Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading") +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-8-dhowells@redhat.com +Reviewed-by: Paulo Alcantara (Red Hat) +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +cc: Ceph Development +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/read_retry.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index 5ec548b996d65..e10eb5a073326 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -292,8 +292,15 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq) + struct folio *folio = folioq_folio(p, slot); + + if (folio && !folioq_is_marked2(p, slot)) { +- trace_netfs_folio(folio, netfs_folio_trace_abandon); +- folio_unlock(folio); ++ if (folio->index == rreq->no_unlock_folio && ++ test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, ++ &rreq->flags)) { ++ _debug("no unlock"); ++ } else { ++ trace_netfs_folio(folio, ++ netfs_folio_trace_abandon); ++ folio_unlock(folio); ++ } + } + } + } +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch b/queue-7.0/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch new file mode 100644 index 0000000000..24dd728692 --- /dev/null +++ b/queue-7.0/netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch @@ -0,0 +1,80 @@ +From 82d585fcb9437c0f49dbc43b93b6cf624171cb4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:53 +0100 +Subject: netfs: Fix write streaming disablement if fd open O_RDWR + +From: David Howells + +[ Upstream commit 70a7b9193bbbfceaab5974de66834c64ccc875dd ] + +In netfs_perform_write(), "write streaming" (the caching of dirty data in +dirty but !uptodate folios) is performed to avoid the need to read data +that is just going to get immediately overwritten. However, this is/will +be disabled in three circumstances: if the fd is open O_RDWR, if fscache is +in use (as we need to round out the blocks for DIO) or if content +encryption is enabled (again for rounding out purposes). + +The idea behind disabling it if the fd is open O_RDWR is that we'd need to +flush the write-streaming page before we could read the data, particularly +through mmap. But netfs now fills in the gaps if ->read_folio() is called +on the page, so that is unnecessary. Further, this doesn't actually work +if a separate fd is open for reading. + +Fix this by removing the check for O_RDWR, thereby allowing streaming +writes even when we might read. + +This caused a number of problems with the generic/522 xfstest, but those +are now fixed. + +Fixes: c38f4e96e605 ("netfs: Provide func to copy data to pagecache for buffered write") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-17-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/buffered_write.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c +index 0ff4c790ae263..b606c3bd84bcd 100644 +--- a/fs/netfs/buffered_write.c ++++ b/fs/netfs/buffered_write.c +@@ -204,11 +204,11 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + } + + /* Decide how we should modify a folio. We might be attempting +- * to do write-streaming, in which case we don't want to a +- * local RMW cycle if we can avoid it. If we're doing local +- * caching or content crypto, we award that priority over +- * avoiding RMW. If the file is open readably, then we also +- * assume that we may want to read what we wrote. ++ * to do write-streaming, as we don't want to a local RMW cycle ++ * if we can avoid it. If we're doing local caching or content ++ * crypto, we award that priority over avoiding RMW. If the ++ * file is open readably, then we let ->read_folio() fill in ++ * the gaps. + */ + finfo = netfs_folio_info(folio); + group = netfs_folio_group(folio); +@@ -284,12 +284,9 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, + + /* We don't want to do a streaming write on a file that loses + * caching service temporarily because the backing store got +- * culled and we don't really want to get a streaming write on +- * a file that's open for reading as ->read_folio() then has to +- * be able to flush it. ++ * culled. + */ +- if ((file->f_mode & FMODE_READ) || +- netfs_is_cache_enabled(ctx)) { ++ if (netfs_is_cache_enabled(ctx)) { + if (finfo) { + netfs_stat(&netfs_n_wh_wstream_conflict); + goto flush_content; +-- +2.53.0 + diff --git a/queue-7.0/netfs-fix-zeropoint-update-where-i_size-remote_i_siz.patch b/queue-7.0/netfs-fix-zeropoint-update-where-i_size-remote_i_siz.patch new file mode 100644 index 0000000000..41043e9174 --- /dev/null +++ b/queue-7.0/netfs-fix-zeropoint-update-where-i_size-remote_i_siz.patch @@ -0,0 +1,80 @@ +From 82fdcc02d8cefaa0f8bcd44c6c6e5855ebe7ff88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 13:33:43 +0100 +Subject: netfs: Fix zeropoint update where i_size > remote_i_size + +From: David Howells + +[ Upstream commit 4543a4d737944134a1394afe797622546fbcc98a ] + +Fix the update of the zero point[*] by netfs_release_folio() when there is +uncommitted data in the pagecache beyond the folio being released but the +on-server EOF is in this folio (ie. i_size > remote_i_size). The update +needs to limit zero_point to remote_i_size, not i_size as i_size is a local +phenomenon reflecting updates made locally to the pagecache, not stuff +written to the server. remote_i_size tracks the server's i_size. + +[*] The zero point is the file position from which we can assume that the + server will just return zeros, so we can avoid generating reads. + +Note that netfs_invalidate_folio() probably doesn't need fixing as +zero_point should be updated by setattr after truncation or fallocate. + +Found with: + + fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \ + /xfstest.test/junk --replay-ops=junk.fsxops + +using the following as junk.fsxops: + + truncate 0x0 0x1bbae 0x82864 + write 0x3ef2e 0xf9c8 0x1bbae + write 0x67e05 0xcb5a 0x4e8f6 + mapread 0x57781 0x85b6 0x7495f + copy_range 0x5d3d 0x10329 0x54fac 0x7495f + write 0x64710 0x1c2b 0x7495f + mapread 0x64000 0x1000 0x7495f + +on cifs with the default cache option. + +It shows read-gaps on folio 0x64 failing with a short read (ie. it hits +EOF) if the FMODE_READ check is commented out in netfs_perform_write(): + + if (//(file->f_mode & FMODE_READ) || + netfs_is_cache_enabled(ctx)) { + +and no fscache. This was initially found with the generic/522 xfstest. + +Fixes: cce6bfa6ca0e ("netfs: Fix trimming of streaming-write folios in netfs_inval_folio()") +Signed-off-by: David Howells +Link: https://patch.msgid.link/20260512123404.719402-7-dhowells@redhat.com +cc: Paulo Alcantara +cc: Matthew Wilcox +cc: netfs@lists.linux.dev +cc: linux-fsdevel@vger.kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/netfs/misc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c +index bad661ff2bec8..723571ca1b885 100644 +--- a/fs/netfs/misc.c ++++ b/fs/netfs/misc.c +@@ -307,10 +307,10 @@ bool netfs_release_folio(struct folio *folio, gfp_t gfp) + return false; + + netfs_read_sizes(inode, &i_size, &remote_i_size, &zero_point); +- end = umin(folio_next_pos(folio), i_size); ++ end = folio_next_pos(folio); + if (end > zero_point) { + spin_lock(&inode->i_lock); +- end = umin(folio_next_pos(folio), inode->i_size); ++ end = umin(end, ctx->_remote_i_size); + if (end > ctx->_zero_point) + netfs_write_zero_point(inode, end); + spin_unlock(&inode->i_lock); +-- +2.53.0 + diff --git a/queue-7.0/nfs-fix-writeback-in-presence-of-errors.patch b/queue-7.0/nfs-fix-writeback-in-presence-of-errors.patch new file mode 100644 index 0000000000..1a8ff552e2 --- /dev/null +++ b/queue-7.0/nfs-fix-writeback-in-presence-of-errors.patch @@ -0,0 +1,157 @@ +From df7782c5d9f308e30320336f81717c48481b2b0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 18:24:23 -0400 +Subject: NFS: fix writeback in presence of errors + +From: Olga Kornievskaia + +[ Upstream commit 5d3869a41f3608101c00ff9c9c7c2364c555fa65 ] + +After running xfstest generic/751, in certain conditions, can have +a writeback IO stuck while experiencing one of the two patterns. + +Pattern#1: writeback IO experiences ENOSPC on an offset smaller +than the filesize. Example, +write offset=0 len=4096 how=unstable OK +write offset=8192 len=4096 how=unstable OK +write offset=12288 len=4096 how=unstable ENOSPC +write offset=4096 len=4096 how=unstable ENOSPC +client sends a commit and receives a verifier which is different +from the last successful write. It marks pages dirty and writeback +retries. But it again send writes unstable and gets into the same +pattern, running into the ENOSPC error and sending a commit because +writes were sent at unstable. + +Pattern#2: an unstable write followed by a short write and ENOSPC. +write offset=0 len=4096 how=unstable OK +write offset=4096 len=4096 how=unstable returns OK but count=100 +write offset=4197 len=3996 how=stable returns ENOSPC +client send a commit and receives a verifier different from +the last unstable write. The same behaviour is retried in a loop. + +Instead, this patch proposes to identify those conditions and mark +requests to be done synchronously instead. Previous solution tried +to mark it in the nfs_page, however that's not persistent thus +instead mark it in the nfs_open_context. + +Furthermore, the same problem occurs during localio code path so +recognize that IO needs to be done sync in that case as well. + +Signed-off-by: Olga Kornievskaia +Signed-off-by: Trond Myklebust +Signed-off-by: Sasha Levin +--- + fs/nfs/localio.c | 15 ++++++++++++++- + fs/nfs/pagelist.c | 3 +++ + fs/nfs/write.c | 9 +++++++++ + include/linux/nfs_fs.h | 1 + + 4 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c +index 4c7d16a99ed61..e55c5977fcc3a 100644 +--- a/fs/nfs/localio.c ++++ b/fs/nfs/localio.c +@@ -865,6 +865,8 @@ static void nfs_local_call_write(struct work_struct *work) + file_start_write(filp); + n_iters = atomic_read(&iocb->n_iters); + for (int i = 0; i < n_iters ; i++) { ++ size_t icount; ++ + if (iocb->iter_is_dio_aligned[i]) { + iocb->kiocb.ki_flags |= IOCB_DIRECT; + /* Only use AIO completion if DIO-aligned segment is last */ +@@ -881,8 +883,16 @@ static void nfs_local_call_write(struct work_struct *work) + if (status == -EIOCBQUEUED) + continue; + /* Break on completion, errors, or short writes */ ++ icount = iov_iter_count(&iocb->iters[i]); + if (nfs_local_pgio_done(iocb, status) || status < 0 || +- (size_t)status < iov_iter_count(&iocb->iters[i])) { ++ (size_t)status < icount) { ++ if ((size_t)status < icount) { ++ struct nfs_lock_context *ctx = ++ iocb->hdr->req->wb_lock_context; ++ ++ set_bit(NFS_CONTEXT_WRITE_SYNC, ++ &ctx->open_context->flags); ++ } + nfs_local_write_iocb_done(iocb); + break; + } +@@ -901,6 +911,9 @@ static void nfs_local_do_write(struct nfs_local_kiocb *iocb, + __func__, hdr->args.count, hdr->args.offset, + (hdr->args.stable == NFS_UNSTABLE) ? "unstable" : "stable"); + ++ if (test_bit(NFS_CONTEXT_WRITE_SYNC, ++ &hdr->req->wb_lock_context->open_context->flags)) ++ hdr->args.stable = NFS_FILE_SYNC; + switch (hdr->args.stable) { + default: + break; +diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c +index a9373de891c98..4a87b2fdb2e6e 100644 +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -1186,6 +1186,9 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, + + nfs_page_group_lock(req); + ++ if (test_bit(NFS_CONTEXT_WRITE_SYNC, ++ &req->wb_lock_context->open_context->flags)) ++ desc->pg_ioflags |= FLUSH_STABLE; + subreq = req; + subreq_size = subreq->wb_bytes; + for(;;) { +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 1ed4b3590b1ac..ddae197d2d3f9 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -927,9 +927,13 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) + goto remove_req; + } + if (nfs_write_need_commit(hdr)) { ++ struct nfs_open_context *ctx = ++ hdr->req->wb_lock_context->open_context; ++ + /* Reset wb_nio, since the write was successful. */ + req->wb_nio = 0; + memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); ++ clear_bit(NFS_CONTEXT_WRITE_SYNC, &ctx->flags); + nfs_mark_request_commit(req, hdr->lseg, &cinfo, + hdr->ds_commit_idx); + goto next; +@@ -1553,7 +1557,10 @@ static void nfs_writeback_result(struct rpc_task *task, + + if (resp->count < argp->count) { + static unsigned long complain; ++ struct nfs_open_context *ctx = ++ hdr->req->wb_lock_context->open_context; + ++ set_bit(NFS_CONTEXT_WRITE_SYNC, &ctx->flags); + /* This a short write! */ + nfs_inc_stats(hdr->inode, NFSIOS_SHORTWRITE); + +@@ -1837,6 +1844,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) + /* We have a mismatch. Write the page again */ + dprintk(" mismatch\n"); + nfs_mark_request_dirty(req); ++ set_bit(NFS_CONTEXT_WRITE_SYNC, ++ &req->wb_lock_context->open_context->flags); + atomic_long_inc(&NFS_I(data->inode)->redirtied_pages); + next: + nfs_unlock_and_release_request(req); +diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h +index 8dd79a3f3d662..4623262da3c09 100644 +--- a/include/linux/nfs_fs.h ++++ b/include/linux/nfs_fs.h +@@ -109,6 +109,7 @@ struct nfs_open_context { + #define NFS_CONTEXT_BAD (2) + #define NFS_CONTEXT_UNLOCK (3) + #define NFS_CONTEXT_FILE_OPEN (4) ++#define NFS_CONTEXT_WRITE_SYNC (5) + + struct nfs4_threshold *mdsthreshold; + struct list_head list; +-- +2.53.0 + diff --git a/queue-7.0/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch b/queue-7.0/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch new file mode 100644 index 0000000000..c1885985fd --- /dev/null +++ b/queue-7.0/nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch @@ -0,0 +1,116 @@ +From 079a08216dc0c2d5fbb0fa6b483e61a3dc6a313c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:19:27 -0500 +Subject: NFS: Use nlmclnt_shutdown_rpc_clnt() to safely shut down NLM + +From: Chuck Lever + +[ Upstream commit 840621fd2ff23ada8b9262d90477e75232566e6b ] + +A race condition exists in shutdown_store() when writing to the sysfs +"shutdown" file concurrently with nlm_shutdown_hosts_net(). Without +synchronization, the following sequence can occur: + + 1. shutdown_store() reads server->nlm_host (non-NULL) + 2. nlm_shutdown_hosts_net() acquires nlm_host_mutex, calls + rpc_shutdown_client(), sets h_rpcclnt to NULL, and potentially + frees the host via nlm_gc_hosts() + 3. shutdown_store() dereferences the now-stale or freed host + +Introduce nlmclnt_shutdown_rpc_clnt(), which acquires nlm_host_mutex +before accessing h_rpcclnt. This synchronizes with +nlm_shutdown_hosts_net() and ensures the rpc_clnt pointer remains +valid during the shutdown operation. + +This change also improves API layering: NFS client code no longer +needs to include the internal lockd header to access nlm_host fields. +The new helper resides in bind.h alongside other public lockd +interfaces. + +Reported-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 29 +++++++++++++++++++++++++++++ + fs/nfs/sysfs.c | 4 ++-- + include/linux/lockd/bind.h | 1 + + 3 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 1a9582a10a86f..015900d2d4c22 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -306,6 +306,35 @@ void nlmclnt_release_host(struct nlm_host *host) + } + } + ++/* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ ++static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) ++{ ++ return true; ++} ++ ++/** ++ * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations ++ * @host: nlm_host to shut down ++ * ++ * Cancels outstanding RPC tasks and marks the client as shut down. ++ * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent ++ * races between shutdown and host destruction. Safe to call if h_rpcclnt ++ * is NULL or already shut down. ++ */ ++void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) ++{ ++ struct rpc_clnt *clnt; ++ ++ mutex_lock(&nlm_host_mutex); ++ clnt = host->h_rpcclnt; ++ if (clnt) { ++ clnt->cl_shutdown = 1; ++ rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); ++ } ++ mutex_unlock(&nlm_host_mutex); ++} ++EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); ++ + /** + * nlmsvc_lookup_host - Find an NLM host handle matching a remote client + * @rqstp: incoming NLM request +diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c +index 1da4f707f9efe..3a197252a1329 100644 +--- a/fs/nfs/sysfs.c ++++ b/fs/nfs/sysfs.c +@@ -13,7 +13,7 @@ + #include + #include + #include +-#include ++#include + + #include "internal.h" + #include "nfs4_fs.h" +@@ -288,7 +288,7 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr, + shutdown_client(server->client_acl); + + if (server->nlm_host) +- shutdown_client(server->nlm_host->h_rpcclnt); ++ nlmclnt_shutdown_rpc_clnt(server->nlm_host); + out: + shutdown_nfs_client(server->nfs_client); + return count; +diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h +index c53c81242e727..40c124f932252 100644 +--- a/include/linux/lockd/bind.h ++++ b/include/linux/lockd/bind.h +@@ -58,6 +58,7 @@ struct nlmclnt_initdata { + extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); + extern void nlmclnt_done(struct nlm_host *host); + extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); ++extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); + + /* + * NLM client operations provide a means to modify RPC processing of NLM +-- +2.53.0 + diff --git a/queue-7.0/nfsd-fix-infinite-loop-in-layout-state-revocation.patch b/queue-7.0/nfsd-fix-infinite-loop-in-layout-state-revocation.patch new file mode 100644 index 0000000000..a4d527b93e --- /dev/null +++ b/queue-7.0/nfsd-fix-infinite-loop-in-layout-state-revocation.patch @@ -0,0 +1,46 @@ +From c7da7ec2bde9bf5de8eab54bbe4ba7e9343d5baf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 14:52:59 -0400 +Subject: NFSD: Fix infinite loop in layout state revocation + +From: Chuck Lever + +[ Upstream commit 4f8ef58c10bfe5f86a643c7c8331b37e69e3dae1 ] + +find_one_sb_stid() skips stids whose sc_status is non-zero, but the +SC_TYPE_LAYOUT case in nfsd4_revoke_states() never sets sc_status +before calling nfsd4_close_layout(). The retry loop therefore finds +the same layout stid on every iteration, hanging the revoker +indefinitely. + +Fixes: 1e33e1414bec ("nfsd: allow layout state to be admin-revoked.") +Reported-by: Dai Ngo +Reviewed-by: Jeff Layton +Tested-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 44b1a93f219af..530459dfa7606 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1850,6 +1850,13 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) + break; + case SC_TYPE_LAYOUT: + ls = layoutstateid(stid); ++ spin_lock(&clp->cl_lock); ++ if (stid->sc_status == 0) { ++ stid->sc_status |= ++ SC_STATUS_ADMIN_REVOKED; ++ atomic_inc(&clp->cl_admin_revoked); ++ } ++ spin_unlock(&clp->cl_lock); + nfsd4_close_layout(ls); + break; + } +-- +2.53.0 + diff --git a/queue-7.0/nouveau-pci-quiesce-gpu-on-shutdown.patch b/queue-7.0/nouveau-pci-quiesce-gpu-on-shutdown.patch new file mode 100644 index 0000000000..53d5c3fc70 --- /dev/null +++ b/queue-7.0/nouveau-pci-quiesce-gpu-on-shutdown.patch @@ -0,0 +1,204 @@ +From 90fcbdecf9edb7000cb84818ed8a4ea2c303156d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 19:36:44 +0800 +Subject: nouveau: pci: quiesce GPU on shutdown + +From: Li Chen + +[ Upstream commit 310326bb7df4bba094a3fc60364c641c547fd923 ] + +Kexec reboot does not reset PCI devices. +Invoking the full DRM/TTM teardown from ->shutdown can trigger WARNs when +userspace still holds DRM file descriptors. + +Quiesce the GPU through the suspend path and then power down the PCI +function so the next kernel can re-initialize the device from a consistent +state. + +WARNING: drivers/gpu/drm/drm_mode_config.c:578 at drm_mode_config_cleanup+0x2e7/0x300, CPU#2: kexec/1300 +Call Trace: + + ? srso_return_thunk+0x5/0x5f + ? enable_work+0x3a/0x100 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +nouveau 0000:26:00.0: [drm] drm_WARN_ON(!list_empty(&fb->filp_head)) +WARNING: drivers/gpu/drm/drm_framebuffer.c:833 at drm_framebuffer_free+0x73/0xa0, CPU#2: kexec/1300 +Call Trace: + + drm_mode_config_cleanup+0x248/0x300 + ? __pfx___drm_printfn_dbg+0x10/0x10 + ? drm_mode_config_cleanup+0x1dc/0x300 + nouveau_display_destroy+0x39/0x70 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_device_fini+0x7b/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +WARNING: include/drm/ttm/ttm_resource.h:406 at nouveau_ttm_fini+0x257/0x270 [nouveau], CPU#2: kexec/1300 +Call Trace: + + nouveau_drm_device_fini+0x93/0x1f0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + nouveau_drm_shutdown+0x52/0xc0 [nouveau c19e0da7fd83583a023f855c510d9a3903808734] + pci_device_shutdown+0x35/0x60 + device_shutdown+0x11c/0x1b0 + kernel_kexec+0x13a/0x160 + __do_sys_reboot+0x209/0x240 + do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? __rtnl_unlock+0x37/0x70 + ? srso_return_thunk+0x5/0x5f + ? netdev_run_todo+0x63/0x570 + ? netif_change_flags+0x54/0x70 + ? srso_return_thunk+0x5/0x5f + ? devinet_ioctl+0x1e5/0x790 + ? srso_return_thunk+0x5/0x5f + ? inet_ioctl+0x1e9/0x200 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x7d/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x23b/0x610 + ? srso_return_thunk+0x5/0x5f + ? put_user_ifreq+0x7a/0x90 + ? srso_return_thunk+0x5/0x5f + ? sock_do_ioctl+0x107/0x130 + ? srso_return_thunk+0x5/0x5f + ? __x64_sys_ioctl+0x97/0xe0 + ? srso_return_thunk+0x5/0x5f + ? do_syscall_64+0x81/0x610 + ? srso_return_thunk+0x5/0x5f + ? exc_page_fault+0x7e/0x1a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Signed-off-by: Li Chen +Reviewed-by: Dave Airlie +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/20260121113646.111561-1-me@linux.beauty +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 32 +++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index 0c23398dd4f1d..acac77dfae703 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -1079,6 +1079,37 @@ nouveau_pmops_resume(struct device *dev) + return ret; + } + ++static void ++nouveau_drm_shutdown(struct pci_dev *pdev) ++{ ++ struct nouveau_drm *drm = pci_get_drvdata(pdev); ++ int ret; ++ ++ if (!drm) ++ return; ++ ++ if (drm->dev->switch_power_state == DRM_SWITCH_POWER_OFF || ++ drm->dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) ++ return; ++ ++ ret = nouveau_do_suspend(drm, false); ++ if (ret) ++ NV_ERROR(drm, "shutdown suspend failed with: %d\n", ret); ++ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ /* ++ * This is just to give the pci power transition time to settle ++ * before an immediate kexec jump. it’s mirroring the existing ++ * nouveau_pmops_suspend() behavior, which already does ++ * udelay(200) right after pci_set_power_state(..., pci_d3hot). In ++ * ->shutdown() we’re allowed to sleep, so I used usleep_range() ++ * instead of a busy-wait udelay(). ++ */ ++ usleep_range(200, 400); ++} ++ + static int + nouveau_pmops_freeze(struct device *dev) + { +@@ -1408,6 +1439,7 @@ nouveau_drm_pci_driver = { + .id_table = nouveau_drm_pci_table, + .probe = nouveau_drm_probe, + .remove = nouveau_drm_remove, ++ .shutdown = nouveau_drm_shutdown, + .driver.pm = &nouveau_pm_ops, + }; + +-- +2.53.0 + diff --git a/queue-7.0/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch b/queue-7.0/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch new file mode 100644 index 0000000000..a8597354a3 --- /dev/null +++ b/queue-7.0/nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch @@ -0,0 +1,43 @@ +From abf960791813e12a244575f5caf14771d40777d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 19:23:01 +0800 +Subject: nsfs: fix wrong error code returned for pidns ioctls + +From: Zhihao Cheng + +[ Upstream commit 725ecd80688bf3c57ca9205431f2c06174ff0756 ] + +When executing NS_GET_PID_FROM_PIDNS (or similar pidns ioctls), if the +target task cannot be found in the corresponding pid_ns, the error code +should be ESRCH instead of ENOTTY. + +This bug was introduced when the extensible ioctl handling was added. +Without proper return, ret would be overwritten by the default case in +the extensible ioctl switch statement. + +Fixes: a1d220d9dafa8 ("nsfs: iterate through mount namespaces") +Signed-off-by: Zhihao Cheng +Link: https://patch.msgid.link/20260507112301.1042757-1-chengzhihao1@huawei.com +Reviewed-by: Yang Erkun +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/nsfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nsfs.c b/fs/nsfs.c +index c215878d55e87..fb0dcc1196699 100644 +--- a/fs/nsfs.c ++++ b/fs/nsfs.c +@@ -266,7 +266,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, + else + tsk = find_task_by_pid_ns(arg, pid_ns); + if (!tsk) +- break; ++ return ret; + + switch (ioctl) { + case NS_GET_PID_FROM_PIDNS: +-- +2.53.0 + diff --git a/queue-7.0/ntfs3-fix-memory-leak-in-indx_create_allocate.patch b/queue-7.0/ntfs3-fix-memory-leak-in-indx_create_allocate.patch new file mode 100644 index 0000000000..ec5dca7794 --- /dev/null +++ b/queue-7.0/ntfs3-fix-memory-leak-in-indx_create_allocate.patch @@ -0,0 +1,45 @@ +From 861a885e2be5abbf0bbc33aa7854bc842f226b25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:51:48 +0530 +Subject: ntfs3: fix memory leak in indx_create_allocate() + +From: Deepanshu Kartikey + +[ Upstream commit 87ac077d6ea8613b7c1debdf3b5e92c78618fd23 ] + +When indx_create_allocate() fails after +attr_allocate_clusters() succeeds, run_deallocate() +frees the disk clusters but never frees the memory +allocated by run_add_entry() via kvmalloc() for the +runs_tree structure. + +Fix this by adding run_close() at the out: label to +free the run.runs memory on all error paths. The +success path is unaffected as it returns 0 directly +without going through out:, transferring ownership +of the run memory to indx->alloc_run via memcpy(). + +Reported-by: syzbot+7adcddaeeb860e5d3f2f@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7adcddaeeb860e5d3f2f +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/index.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c +index 97f06c26fe1a6..11f59d7b9ea45 100644 +--- a/fs/ntfs3/index.c ++++ b/fs/ntfs3/index.c +@@ -1481,6 +1481,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, + run_deallocate(sbi, &run, false); + + out: ++ run_close(&run); + return err; + } + +-- +2.53.0 + diff --git a/queue-7.0/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch b/queue-7.0/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch new file mode 100644 index 0000000000..1134cd12a2 --- /dev/null +++ b/queue-7.0/ntfs3-fix-oob-write-in-attr_wof_frame_info.patch @@ -0,0 +1,56 @@ +From 78947f47bf2da130a2793c4c006b1ebc8d209dd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 13:57:57 +0200 +Subject: ntfs3: fix OOB write in attr_wof_frame_info() + +From: 0xkato <0xkkato@gmail.com> + +[ Upstream commit 859d777646b56dd878b136392f3d03fb8153b559 ] + +In attr_wof_frame_info(), the offset-table read range for a nonresident +WofCompressedData stream is: + + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ... + ntfs_read_run(sbi, run, addr, from, to - from); + +A crafted image sets WofCompressedData.nres.data_size to 0xfff while the +file is large enough to request frame 1024 (offset 0x400000). This gives +from=0x1000, to=0xfff. The unsigned (to - from) wraps to 0xffffffffffffffff +and ntfs_read_write_run() overflows the single-page offs_folio via memcpy. + +Triggered by pread() on a mounted NTFS image. Depending on adjacent +memory layout at the time of the overflow, KASAN reports this as +slab-out-of-bounds, use-after-free, or slab-use-after-free all at +ntfs_read_write_run(). Secondary corruption/panic paths were also observed. + +Reject the read when the offset-table page is outside the stream. + +Signed-off-by: 0xkato <0xkkato@gmail.com> +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index 76e581d3961d0..6b5b58ebbf852 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1591,6 +1591,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr, + u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1); + u64 to = min(from + PAGE_SIZE, wof_size); + ++ if (from >= wof_size) { ++ _ntfs_bad_inode(&ni->vfs_inode); ++ err = -EINVAL; ++ goto out1; ++ } ++ + err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME, + ARRAY_SIZE(WOF_NAME), run, + from, to); +-- +2.53.0 + diff --git a/queue-7.0/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch b/queue-7.0/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch new file mode 100644 index 0000000000..8427c13f95 --- /dev/null +++ b/queue-7.0/ntfs3-reject-inodes-with-zero-non-dos-link-count.patch @@ -0,0 +1,51 @@ +From dbaab9930e2c2e2ee52c8088ef106bd5d1d9361c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 15:56:34 +0000 +Subject: ntfs3: reject inodes with zero non-DOS link count + +From: Ziyi Guo + +[ Upstream commit e10e72f69734a90c8719d160e8efb164ce5d9e26 ] + +ntfs_read_mft() counts file name attributes into two variables: +names (all names including DOS 8.3) and links (non-DOS names +only). The validation at line 424 checks names but set_nlink() +at line 436 uses links. A corrupted NTFS image where all file +name attributes have type FILE_NAME_DOS passes the names check +but results in set_nlink(inode, 0). + +When such an inode is loaded via a code path that passes name=NULL +to ntfs_iget5() and the nlink=0 inode enters the VFS. The subsequent +unlink, rmdir, or rename targeting this inode calls drop_nlink() +which triggers WARN_ON(inode->i_nlink == 0) in fs/inode.c. + +An all-DOS-name MFT record cannot exist on a valid NTFS volume. +Reject such records by checking for links == 0 before +calling set_nlink(). + +Signed-off-by: Ziyi Guo +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index eac421cf98a87..733d4c86edbaf 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -432,6 +432,11 @@ static struct inode *ntfs_read_mft(struct inode *inode, + ni->mi.dirty = true; + } + ++ if (!links) { ++ err = -EINVAL; ++ goto out; ++ } ++ + set_nlink(inode, links); + + if (S_ISDIR(mode)) { +-- +2.53.0 + diff --git a/queue-7.0/nvme-add-missing-module_alias-for-fabrics-transports.patch b/queue-7.0/nvme-add-missing-module_alias-for-fabrics-transports.patch new file mode 100644 index 0000000000..ef04241a49 --- /dev/null +++ b/queue-7.0/nvme-add-missing-module_alias-for-fabrics-transports.patch @@ -0,0 +1,54 @@ +From 03863f3e2c6e791244633ce0cf7c3aad020a6819 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:17:31 +0800 +Subject: nvme: add missing MODULE_ALIAS for fabrics transports + +From: Geliang Tang + +[ Upstream commit 723277b15ed97185ce6f75abbf19f06e00f0a6f5 ] + +The generic fabrics layer uses request_module("nvme-%s", opts->transport) +to auto-load transport modules. Currently, the nvme-tcp, nvme-rdma, and +nvme-fc modules lack MODULE_ALIAS entries for these names, which prevents +the kernel from automatically finding and loading them when requested. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Geliang Tang +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/fc.c | 1 + + drivers/nvme/host/rdma.c | 1 + + drivers/nvme/host/tcp.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index e1bb4707183ca..e4f4528fe2a2d 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module); + + MODULE_DESCRIPTION("NVMe host FC transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-fc"); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 57111139e84fa..1ec6e867aedb6 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -2432,3 +2432,4 @@ module_exit(nvme_rdma_cleanup_module); + + MODULE_DESCRIPTION("NVMe host RDMA transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-rdma"); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 243dab830dc84..02c95c32b07e3 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -3071,3 +3071,4 @@ module_exit(nvme_tcp_cleanup_module); + + MODULE_DESCRIPTION("NVMe host TCP transport driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("nvme-tcp"); +-- +2.53.0 + diff --git a/queue-7.0/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch b/queue-7.0/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch new file mode 100644 index 0000000000..de203a65cb --- /dev/null +++ b/queue-7.0/nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch @@ -0,0 +1,48 @@ +From e86bd12c5a99ae20455deaa902dc8ab755d9f1e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:15:25 +0800 +Subject: nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808 (Samsung + PM981/983/970 EVO Plus ) + +From: Alan Cui + +[ Upstream commit 7f991e3f9b8f044640bcb5fa8570350a68932843 ] + +The firmware for Samsung 970 Evo Plus / PM981 / PM983 does not support SUBNQN. +Make quirks to suppress warnings. + +# nvme id-ctrl /dev/nvme1n1 +NVME Identify Controller: +vid : 0x144d +ssvid : 0x144d +sn : *** +mn : Samsung SSD 970 EVO Plus 500GB +fr : 2B2QEXM7 + +mcdqpc : 0 +subnqn : +ioccsz : 0 + +Signed-off-by: Alan Cui +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 6d522c52dca67..66aa2fa9bf088 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -4107,6 +4107,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, ++ { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ ++ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ +-- +2.53.0 + diff --git a/queue-7.0/nvme-core-fix-parameter-name-in-comment.patch b/queue-7.0/nvme-core-fix-parameter-name-in-comment.patch new file mode 100644 index 0000000000..851c9bc8c4 --- /dev/null +++ b/queue-7.0/nvme-core-fix-parameter-name-in-comment.patch @@ -0,0 +1,43 @@ +From 5424e797ee315095aed71cd74ba0ba640c2ba982 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:45:22 +0200 +Subject: nvme-core: fix parameter name in comment + +From: Flavio Suligoi + +[ Upstream commit e80e39f25567310c1c7392eed886890b5c6788ba ] + +In the declaration of the structure "core_quirks[]", in the comment +referred to the devices "Kioxia CD6-V Series / HPE PE8030", the +parameter "default_ps_max_latency_us" is reported in a wrong way: + +nvme_core.default_ps_max_latency=0 + +The correct form is, instead: + +nvme_core.default_ps_max_latency_us=0 + +Reviewed-by: Christoph Hellwig +Signed-off-by: Flavio Suligoi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index ce25c8a4e84bc..bf12692367bc4 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3013,7 +3013,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { + * + * The device is left in a state where it is also not possible + * to use "nvme set-feature" to disable APST, but booting with +- * nvme_core.default_ps_max_latency=0 works. ++ * nvme_core.default_ps_max_latency_us=0 works. + */ + .vid = 0x1e0f, + .mn = "KCD6XVUL6T40", +-- +2.53.0 + diff --git a/queue-7.0/nvme-fix-bio-leak-on-mapping-failure.patch b/queue-7.0/nvme-fix-bio-leak-on-mapping-failure.patch new file mode 100644 index 0000000000..d52ec450e2 --- /dev/null +++ b/queue-7.0/nvme-fix-bio-leak-on-mapping-failure.patch @@ -0,0 +1,48 @@ +From 33597f340bb2501763eba4dea52e6161e905d903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 06:16:02 -0700 +Subject: nvme: fix bio leak on mapping failure + +From: Keith Busch + +[ Upstream commit 2279cd9c61a330e5de4d6eb0bc422820dd6fdf36 ] + +The local bio is always NULL, so we'd leak the bio if the integrity +mapping failed. Just get it directly from the request. + +Fixes: d0d1d522316e91f ("blk-map: provide the bdev to bio if one exists") +Reviewed-by: Sagi Grimberg +Reviewed-by: John Garry +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/ioctl.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c +index 8844bbd395159..77c668282d996 100644 +--- a/drivers/nvme/host/ioctl.c ++++ b/drivers/nvme/host/ioctl.c +@@ -122,7 +122,6 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + bool supports_metadata = bdev && blk_get_integrity(bdev->bd_disk); + struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; + bool has_metadata = meta_buffer && meta_len; +- struct bio *bio = NULL; + int ret; + + if (!nvme_ctrl_sgl_supported(ctrl)) +@@ -154,8 +153,8 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, + return ret; + + out_unmap: +- if (bio) +- blk_rq_unmap_user(bio); ++ if (req->bio) ++ blk_rq_unmap_user(req->bio); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch b/queue-7.0/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch new file mode 100644 index 0000000000..1906c17126 --- /dev/null +++ b/queue-7.0/nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch @@ -0,0 +1,110 @@ +From a9e635a4e126fa0e2ec8c1d06525ce954ad661d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:08:48 +0530 +Subject: nvme-loop: do not cancel I/O and admin tagset during ctrl + reset/shutdown + +From: Nilay Shroff + +[ Upstream commit 886f35201591ded7958e16fe3750871d3ca0bcdf ] + +Cancelling the I/O and admin tagsets during nvme-loop controller reset +or shutdown is unnecessary. The subsequent destruction of the I/O and +admin queues already waits for all in-flight target operations to +complete. + +Cancelling the tagsets first also opens a race window. After a request +tag has been cancelled, a late completion from the target may still +arrive before the queues are destroyed. In that case the completion path +may access a request whose tag has already been cancelled or freed, +which can lead to a kernel crash. Please see below the kernel crash +encountered while running blktests nvme/040: + +run blktests nvme/040 at 2026-03-08 06:34:27 +loop0: detected capacity change from 0 to 2097152 +nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +nvme nvme6: creating 96 I/O queues. +nvme nvme6: new ctrl: "blktests-subsystem-1" +nvme_log_error: 1 callbacks suppressed +block nvme6n1: no usable path - requeuing I/O +nvme6c6n1: Read(0x2) @ LBA 2096384, 128 blocks, Host Aborted Command (sct 0x3 / sc 0x71) +blk_print_req_error: 1 callbacks suppressed +I/O error, dev nvme6c6n1, sector 2096384 op 0x0:(READ) flags 0x2880700 phys_seg 1 prio class 2 +block nvme6n1: no usable path - requeuing I/O +Kernel attempted to read user page (236) - exploit attempt? (uid: 0) +BUG: Kernel NULL pointer dereference on read at 0x00000236 +Faulting instruction address: 0xc000000000961274 +Oops: Kernel access of bad area, sig: 11 [#1] +LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA pSeries +Modules linked in: nvme_loop nvme_fabrics loop nvmet null_blk rpadlpar_io rpaphp xsk_diag bonding rfkill nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink pseries_rng dax_pmem vmx_crypto drm drm_panel_orientation_quirks xfs mlx5_core nvme bnx2x sd_mod nd_pmem nd_btt nvme_core sg papr_scm tls libnvdimm ibmvscsi ibmveth scsi_transport_srp nvme_keyring nvme_auth mdio hkdf pseries_wdt dm_mirror dm_region_hash dm_log dm_mod fuse [last unloaded: loop] +CPU: 25 UID: 0 PID: 0 Comm: swapper/25 Kdump: loaded Not tainted 7.0.0-rc3+ #14 PREEMPT +Hardware name: IBM,9043-MRX Power11 (architected) 0x820200 0xf000007 of:IBM,FW1120.00 (RF1120_128) hv:phyp pSeries +NIP: c000000000961274 LR: c008000009af1808 CTR: c00000000096124c +REGS: c0000007ffc0f910 TRAP: 0300 Not tainted (7.0.0-rc3+) +MSR: 8000000000009033 CR: 22222222 XER: 00000000 +CFAR: c008000009af232c DAR: 0000000000000236 DSISR: 40000000 IRQMASK: 0 +GPR00: c008000009af17fc c0000007ffc0fbb0 c000000001c78100 c0000000be05cc00 +GPR04: 0000000000000001 0000000000000000 0000000000000007 0000000000000000 +GPR08: 0000000000000000 0000000000000000 0000000000000002 c008000009af2318 +GPR12: c00000000096124c c0000007ffdab880 0000000000000000 0000000000000000 +GPR16: 0000000000000010 0000000000000000 0000000000000004 0000000000000000 +GPR20: 0000000000000001 c000000002ca2b00 0000000100043bb2 000000000000000a +GPR24: 000000000000000a 0000000000000000 0000000000000000 0000000000000000 +GPR28: c000000084021d40 c000000084021d50 c0000000be05cd60 c0000000be05cc00 +NIP [c000000000961274] blk_mq_complete_request_remote+0x28/0x2d4 +LR [c008000009af1808] nvme_loop_queue_response+0x110/0x290 [nvme_loop] +Call Trace: + 0xc00000000502c640 (unreliable) + nvme_loop_queue_response+0x104/0x290 [nvme_loop] + __nvmet_req_complete+0x80/0x498 [nvmet] + nvmet_req_complete+0x24/0xf8 [nvmet] + nvmet_bio_done+0x58/0xcc [nvmet] + bio_endio+0x250/0x390 + blk_update_request+0x2e8/0x68c + blk_mq_end_request+0x30/0x5c + lo_complete_rq+0x94/0x110 [loop] + blk_complete_reqs+0x78/0x98 + handle_softirqs+0x148/0x454 + do_softirq_own_stack+0x3c/0x50 + __irq_exit_rcu+0x18c/0x1b4 + irq_exit+0x1c/0x34 + do_IRQ+0x114/0x278 + hardware_interrupt_common_virt+0x28c/0x290 + +Since the queue teardown path already guarantees that all target-side +operations have completed, cancelling the tagsets is redundant and +unsafe. So avoid cancelling the I/O and admin tagsets during controller +reset and shutdown. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Nilay Shroff +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/loop.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index 4b3f4f11928d4..d98d0cdc5d6fa 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -419,7 +419,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + { + if (ctrl->ctrl.queue_count > 1) { + nvme_quiesce_io_queues(&ctrl->ctrl); +- nvme_cancel_tagset(&ctrl->ctrl); + nvme_loop_destroy_io_queues(ctrl); + } + +@@ -427,7 +426,6 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl) + if (nvme_ctrl_state(&ctrl->ctrl) == NVME_CTRL_LIVE) + nvme_disable_ctrl(&ctrl->ctrl, true); + +- nvme_cancel_admin_tagset(&ctrl->ctrl); + nvme_loop_destroy_admin_queue(ctrl); + } + +-- +2.53.0 + diff --git a/queue-7.0/nvme-multipath-put-module-reference-when-delayed-rem.patch b/queue-7.0/nvme-multipath-put-module-reference-when-delayed-rem.patch new file mode 100644 index 0000000000..a60e740af4 --- /dev/null +++ b/queue-7.0/nvme-multipath-put-module-reference-when-delayed-rem.patch @@ -0,0 +1,41 @@ +From 4aa6585f2f922acc94a410fd8e2b51ba6f6af1bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 15:53:58 +0000 +Subject: nvme-multipath: put module reference when delayed removal work is + canceled + +From: John Garry + +[ Upstream commit 3f150f0f010f234f34a67897344f18e68fe803f7 ] + +The delayed disk removal work is canceled when a NS (re)appears. However, +we do not put the module reference grabbed in nvme_mpath_remove_disk(), so +fix that. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Nilay Shroff +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: John Garry +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index bf12692367bc4..9ddb494caaea6 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4052,7 +4052,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info) + mutex_unlock(&ctrl->subsys->lock); + + #ifdef CONFIG_NVME_MULTIPATH +- cancel_delayed_work(&head->remove_work); ++ if (cancel_delayed_work(&head->remove_work)) ++ module_put(THIS_MODULE); + #endif + return 0; + +-- +2.53.0 + diff --git a/queue-7.0/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch b/queue-7.0/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch new file mode 100644 index 0000000000..26cef69355 --- /dev/null +++ b/queue-7.0/nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch @@ -0,0 +1,90 @@ +From c2d775a16b2874bbdd08b42755b9ada9c3b93e88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 16:11:16 +0800 +Subject: nvme-pci: fix use-after-free in nvme_free_host_mem() + +From: Chia-Lin Kao (AceLan) + +[ Upstream commit b35a13036755c5803168a7cb93bc66035c3e65b8 ] + +nvme_free_host_mem() frees dev->hmb_sgt via dma_free_noncontiguous() +but never clears the pointer afterward. This leads to a use-after-free +if nvme_free_host_mem() is called twice in the same error path. + +This can happen during nvme_probe() when nvme_setup_host_mem() succeeds +in allocating the HMB (setting dev->hmb_sgt) but nvme_set_host_mem() +fails with an I/O error: + + nvme_setup_host_mem() + nvme_alloc_host_mem_single() -> sets dev->hmb_sgt + nvme_set_host_mem() -> fails with -EIO + nvme_free_host_mem() -> frees hmb_sgt, but does NOT NULL it + return error + + nvme_probe() error path: + nvme_free_host_mem() -> dev->hmb_sgt is stale, use-after-free + +The second call dereferences the freed sgt, causing a NULL pointer +dereference in iommu_dma_free_noncontiguous() when it accesses +sgt->sgl->dma_address (the backing memory has been freed and zeroed). + +This is reproducible on Thunderbolt-attached NVMe devices (e.g., OWC +Envoy Express behind a Dell WD22TB4 dock) where the device intermittently +returns I/O errors during HMB setup due to PCIe link instability. + + BUG: kernel NULL pointer dereference, address: 0000000000000010 + RIP: 0010:iommu_dma_free_noncontiguous+0x22/0x80 + Call Trace: + + dma_free_noncontiguous+0x3b/0x130 + nvme_free_host_mem+0x30/0xf0 [nvme] + nvme_probe.cold+0xcc/0x275 [nvme] + local_pci_probe+0x43/0xa0 + pci_device_probe+0xeea/0x290 + really_probe+0xf9/0x3b0 + __driver_probe_device+0x8b/0x170 + driver_probe_device+0x24/0xd0 + __driver_attach_async_helper+0x6b/0x110 + async_run_entry_fn+0x37/0x170 + process_one_work+0x1ac/0x3d0 + worker_thread+0x1b8/0x360 + kthread+0xf7/0x130 + ret_from_fork+0x2d8/0x3a0 + ret_from_fork_asm+0x1a/0x30 + + +Fix this by setting dev->hmb_sgt to NULL after freeing it, so the +second call takes the multi-descriptor path which safely handles the +already-cleaned-up state. + +Fixes: 63a5c7a4b4c4 ("nvme-pci: use dma_alloc_noncontigous if possible") +Signed-off-by: Chia-Lin Kao (AceLan) +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 4c052ed18cb8d..6d522c52dca67 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2533,11 +2533,13 @@ static void nvme_free_host_mem_multi(struct nvme_dev *dev) + + static void nvme_free_host_mem(struct nvme_dev *dev) + { +- if (dev->hmb_sgt) ++ if (dev->hmb_sgt) { + dma_free_noncontiguous(dev->dev, dev->host_mem_size, + dev->hmb_sgt, DMA_BIDIRECTIONAL); +- else ++ dev->hmb_sgt = NULL; ++ } else { + nvme_free_host_mem_multi(dev); ++ } + + dma_free_coherent(dev->dev, dev->host_mem_descs_size, + dev->host_mem_descs, dev->host_mem_descs_dma); +-- +2.53.0 + diff --git a/queue-7.0/nvme-tcp-teardown-circular-locking-fixes.patch b/queue-7.0/nvme-tcp-teardown-circular-locking-fixes.patch new file mode 100644 index 0000000000..19bbf592ba --- /dev/null +++ b/queue-7.0/nvme-tcp-teardown-circular-locking-fixes.patch @@ -0,0 +1,304 @@ +From b37d6d25e569e4234f8d19e57f968cd552547edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 10:16:28 -0700 +Subject: nvme-tcp: teardown circular locking fixes + +From: Chaitanya Kulkarni + +[ Upstream commit 26bb12b9caafa2e62d638104bf2732f610cdbb0b ] + +When a controller reset is triggered via sysfs (by writing to +/sys/class/nvme//reset_controller), the reset work tears down +and re-establishes all queues. The socket release using fput() defers +the actual cleanup to task_work delayed_fput workqueue. This deferred +cleanup can race with the subsequent queue re-allocation during reset, +potentially leading to use-after-free or resource conflicts. + +Replace fput() with __fput_sync() to ensure synchronous socket release, +guaranteeing that all socket resources are fully cleaned up before the +function returns. This prevents races during controller reset where +new queue setup may begin before the old socket is fully released. + +* Call chain during reset: + nvme_reset_ctrl_work() + -> nvme_tcp_teardown_ctrl() + -> nvme_tcp_teardown_io_queues() + -> nvme_tcp_free_io_queues() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_teardown_admin_queue() + -> nvme_tcp_free_admin_queue() + -> nvme_tcp_free_queue() <-- fput() -> __fput_sync() + -> nvme_tcp_setup_ctrl() <-- race with deferred fput + +memalloc_noreclaim_save() sets PF_MEMALLOC which is intended for tasks +performing memory reclaim work that need reserve access. While PF_MEMALLOC +prevents the task from entering direct reclaim (causing __need_reclaim() to +return false), it does not strip __GFP_IO from gfp flags. The allocator can +therefore still trigger writeback I/O when __GFP_IO remains set, which is +unsafe when the caller holds block layer locks. + +Switch to memalloc_noio_save() which sets PF_MEMALLOC_NOIO. This causes +current_gfp_context() to strip __GFP_IO|__GFP_FS from every allocation in +the scope, making it safe to allocate memory while holding elevator_lock and +set->srcu. + +* The issue can be reproduced using blktests: + + nvme_trtype=tcp ./check nvme/005 +blktests (master) # nvme_trtype=tcp ./check nvme/005 +nvme/005 (tr=tcp) (reset local loopback target) [failed] + runtime 0.725s ... 0.798s + something found in dmesg: + [ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 + + [...] + ... + (See '/root/blktests/results/nodev_tr_tcp/nvme/005.dmesg' for the entire message) +blktests (master) # cat /root/blktests/results/nodev_tr_tcp/nvme/005.dmesg +[ 108.473940] run blktests nvme/005 at 2025-11-22 16:12:20 +[ 108.526983] loop0: detected capacity change from 0 to 2097152 +[ 108.555606] nvmet: adding nsid 1 to subsystem blktests-subsystem-1 +[ 108.572531] nvmet_tcp: enabling port 0 (127.0.0.1:4420) +[ 108.613061] nvmet: Created nvm controller 1 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.616832] nvme nvme0: creating 48 I/O queues. +[ 108.630791] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.661892] nvme nvme0: new ctrl: NQN "blktests-subsystem-1", addr 127.0.0.1:4420, hostnqn: nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349 +[ 108.746639] nvmet: Created nvm controller 2 for subsystem blktests-subsystem-1 for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349. +[ 108.748466] nvme nvme0: creating 48 I/O queues. +[ 108.802984] nvme nvme0: mapped 48/0/0 default/read/poll queues. +[ 108.829983] nvme nvme0: Removing ctrl: NQN "blktests-subsystem-1" +[ 108.854288] block nvme0n1: no available path - failing I/O +[ 108.854344] block nvme0n1: no available path - failing I/O +[ 108.854373] Buffer I/O error on dev nvme0n1, logical block 1, async page read + +[ 108.891693] ====================================================== +[ 108.895912] WARNING: possible circular locking dependency detected +[ 108.900184] 6.17.0nvme+ #3 Tainted: G N +[ 108.903913] ------------------------------------------------------ +[ 108.908171] nvme/2734 is trying to acquire lock: +[ 108.911957] ffff88810210e610 (set->srcu){.+.+}-{0:0}, at: __synchronize_srcu+0x17/0x170 +[ 108.917587] + but task is already holding lock: +[ 108.921570] ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 108.927361] + which lock already depends on the new lock. + +[ 108.933018] + the existing dependency chain (in reverse order) is: +[ 108.938223] + -> #4 (&q->elevator_lock){+.+.}-{4:4}: +[ 108.942988] __mutex_lock+0xa2/0x1150 +[ 108.945873] elevator_change+0xa8/0x1c0 +[ 108.948925] elv_iosched_store+0xdf/0x140 +[ 108.952043] kernfs_fop_write_iter+0x16a/0x220 +[ 108.955367] vfs_write+0x378/0x520 +[ 108.957598] ksys_write+0x67/0xe0 +[ 108.959721] do_syscall_64+0x76/0xbb0 +[ 108.962052] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 108.965145] + -> #3 (&q->q_usage_counter(io)){++++}-{0:0}: +[ 108.968923] blk_alloc_queue+0x30e/0x350 +[ 108.972117] blk_mq_alloc_queue+0x61/0xd0 +[ 108.974677] scsi_alloc_sdev+0x2a0/0x3e0 +[ 108.977092] scsi_probe_and_add_lun+0x1bd/0x430 +[ 108.979921] __scsi_add_device+0x109/0x120 +[ 108.982504] ata_scsi_scan_host+0x97/0x1c0 +[ 108.984365] async_run_entry_fn+0x2d/0x130 +[ 108.986109] process_one_work+0x20e/0x630 +[ 108.987830] worker_thread+0x184/0x330 +[ 108.989473] kthread+0x10a/0x250 +[ 108.990852] ret_from_fork+0x297/0x300 +[ 108.992491] ret_from_fork_asm+0x1a/0x30 +[ 108.994159] + -> #2 (fs_reclaim){+.+.}-{0:0}: +[ 108.996320] fs_reclaim_acquire+0x99/0xd0 +[ 108.998058] kmem_cache_alloc_node_noprof+0x4e/0x3c0 +[ 109.000123] __alloc_skb+0x15f/0x190 +[ 109.002195] tcp_send_active_reset+0x3f/0x1e0 +[ 109.004038] tcp_disconnect+0x50b/0x720 +[ 109.005695] __tcp_close+0x2b8/0x4b0 +[ 109.007227] tcp_close+0x20/0x80 +[ 109.008663] inet_release+0x31/0x60 +[ 109.010175] __sock_release+0x3a/0xc0 +[ 109.011778] sock_close+0x14/0x20 +[ 109.013263] __fput+0xee/0x2c0 +[ 109.014673] delayed_fput+0x31/0x50 +[ 109.016183] process_one_work+0x20e/0x630 +[ 109.017897] worker_thread+0x184/0x330 +[ 109.019543] kthread+0x10a/0x250 +[ 109.020929] ret_from_fork+0x297/0x300 +[ 109.022565] ret_from_fork_asm+0x1a/0x30 +[ 109.024194] + -> #1 (sk_lock-AF_INET-NVME){+.+.}-{0:0}: +[ 109.026634] lock_sock_nested+0x2e/0x70 +[ 109.028251] tcp_sendmsg+0x1a/0x40 +[ 109.029783] sock_sendmsg+0xed/0x110 +[ 109.031321] nvme_tcp_try_send_cmd_pdu+0x13e/0x260 [nvme_tcp] +[ 109.034263] nvme_tcp_try_send+0xb3/0x330 [nvme_tcp] +[ 109.036375] nvme_tcp_queue_rq+0x342/0x3d0 [nvme_tcp] +[ 109.038528] blk_mq_dispatch_rq_list+0x297/0x800 +[ 109.040448] __blk_mq_sched_dispatch_requests+0x3db/0x5f0 +[ 109.042677] blk_mq_sched_dispatch_requests+0x29/0x70 +[ 109.044787] blk_mq_run_work_fn+0x76/0x1b0 +[ 109.046535] process_one_work+0x20e/0x630 +[ 109.048245] worker_thread+0x184/0x330 +[ 109.049890] kthread+0x10a/0x250 +[ 109.051331] ret_from_fork+0x297/0x300 +[ 109.053024] ret_from_fork_asm+0x1a/0x30 +[ 109.054740] + -> #0 (set->srcu){.+.+}-{0:0}: +[ 109.056850] __lock_acquire+0x1468/0x2210 +[ 109.058614] lock_sync+0xa5/0x110 +[ 109.060048] __synchronize_srcu+0x49/0x170 +[ 109.061802] elevator_switch+0xc9/0x330 +[ 109.063950] elevator_change+0x128/0x1c0 +[ 109.065675] elevator_set_none+0x4c/0x90 +[ 109.067316] blk_unregister_queue+0xa8/0x110 +[ 109.069165] __del_gendisk+0x14e/0x3c0 +[ 109.070824] del_gendisk+0x75/0xa0 +[ 109.072328] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.074365] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.076652] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.078775] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.081009] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.083082] kernfs_fop_write_iter+0x16a/0x220 +[ 109.085009] vfs_write+0x378/0x520 +[ 109.086539] ksys_write+0x67/0xe0 +[ 109.087982] do_syscall_64+0x76/0xbb0 +[ 109.089577] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.091665] + other info that might help us debug this: + +[ 109.095478] Chain exists of: + set->srcu --> &q->q_usage_counter(io) --> &q->elevator_lock + +[ 109.099544] Possible unsafe locking scenario: + +[ 109.101708] CPU0 CPU1 +[ 109.103402] ---- ---- +[ 109.105103] lock(&q->elevator_lock); +[ 109.106530] lock(&q->q_usage_counter(io)); +[ 109.109022] lock(&q->elevator_lock); +[ 109.111391] sync(set->srcu); +[ 109.112586] + *** DEADLOCK *** + +[ 109.114772] 5 locks held by nvme/2734: +[ 109.116189] #0: ffff888101925410 (sb_writers#4){.+.+}-{0:0}, at: ksys_write+0x67/0xe0 +[ 109.119143] #1: ffff88817a914e88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0x10f/0x220 +[ 109.123141] #2: ffff8881046313f8 (kn->active#185){++++}-{0:0}, at: sysfs_remove_file_self+0x26/0x50 +[ 109.126543] #3: ffff88810470e1d0 (&set->update_nr_hwq_lock){++++}-{4:4}, at: del_gendisk+0x6d/0xa0 +[ 109.129891] #4: ffff88813abea198 (&q->elevator_lock){+.+.}-{4:4}, at: elevator_change+0xa8/0x1c0 +[ 109.133149] + stack backtrace: +[ 109.134817] CPU: 6 UID: 0 PID: 2734 Comm: nvme Tainted: G N 6.17.0nvme+ #3 PREEMPT(voluntary) +[ 109.134819] Tainted: [N]=TEST +[ 109.134820] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 +[ 109.134821] Call Trace: +[ 109.134823] +[ 109.134824] dump_stack_lvl+0x75/0xb0 +[ 109.134828] print_circular_bug+0x26a/0x330 +[ 109.134831] check_noncircular+0x12f/0x150 +[ 109.134834] __lock_acquire+0x1468/0x2210 +[ 109.134837] ? __synchronize_srcu+0x17/0x170 +[ 109.134838] lock_sync+0xa5/0x110 +[ 109.134840] ? __synchronize_srcu+0x17/0x170 +[ 109.134842] __synchronize_srcu+0x49/0x170 +[ 109.134843] ? mark_held_locks+0x49/0x80 +[ 109.134845] ? _raw_spin_unlock_irqrestore+0x2d/0x60 +[ 109.134847] ? kvm_clock_get_cycles+0x14/0x30 +[ 109.134853] ? ktime_get_mono_fast_ns+0x36/0xb0 +[ 109.134858] elevator_switch+0xc9/0x330 +[ 109.134860] elevator_change+0x128/0x1c0 +[ 109.134862] ? kernfs_put.part.0+0x86/0x290 +[ 109.134864] elevator_set_none+0x4c/0x90 +[ 109.134866] blk_unregister_queue+0xa8/0x110 +[ 109.134868] __del_gendisk+0x14e/0x3c0 +[ 109.134870] del_gendisk+0x75/0xa0 +[ 109.134872] nvme_ns_remove+0xf2/0x230 [nvme_core] +[ 109.134879] nvme_remove_namespaces+0xf2/0x150 [nvme_core] +[ 109.134887] nvme_do_delete_ctrl+0x71/0x90 [nvme_core] +[ 109.134893] nvme_delete_ctrl_sync+0x3b/0x50 [nvme_core] +[ 109.134899] nvme_sysfs_delete+0x34/0x40 [nvme_core] +[ 109.134905] kernfs_fop_write_iter+0x16a/0x220 +[ 109.134908] vfs_write+0x378/0x520 +[ 109.134911] ksys_write+0x67/0xe0 +[ 109.134913] do_syscall_64+0x76/0xbb0 +[ 109.134915] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 109.134916] RIP: 0033:0x7fd68a737317 +[ 109.134917] Code: 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 109.134919] RSP: 002b:00007ffded1546d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 109.134920] RAX: ffffffffffffffda RBX: 000000000054f7e0 RCX: 00007fd68a737317 +[ 109.134921] RDX: 0000000000000001 RSI: 00007fd68a855719 RDI: 0000000000000003 +[ 109.134921] RBP: 0000000000000003 R08: 0000000030407850 R09: 00007fd68a7cd4e0 +[ 109.134922] R10: 00007fd68a65b130 R11: 0000000000000246 R12: 00007fd68a855719 +[ 109.134923] R13: 00000000304074c0 R14: 00000000304074c0 R15: 0000000030408660 +[ 109.134926] +[ 109.962756] Key type psk unregistered + +Reviewed-by: Christoph Hellwig +Reviewed-by: Sagi Grimberg +Reviewed-by: Hannes Reinecke +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/tcp.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 02c95c32b07e3..15d36d6a728e8 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1438,18 +1438,32 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) + { + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[qid]; +- unsigned int noreclaim_flag; ++ unsigned int noio_flag; + + if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) + return; + + page_frag_cache_drain(&queue->pf_cache); + +- noreclaim_flag = memalloc_noreclaim_save(); +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /** ++ * Prevent memory reclaim from triggering block I/O during socket ++ * teardown. The socket release path fput -> tcp_close -> ++ * tcp_disconnect -> tcp_send_active_reset may allocate memory, and ++ * allowing reclaim to issue I/O could deadlock if we're being called ++ * from block device teardown (e.g., del_gendisk -> elevator cleanup) ++ * which holds locks that the I/O completion path needs. ++ */ ++ noio_flag = memalloc_noio_save(); ++ ++ /** ++ * Release the socket synchronously. During reset in ++ * nvme_reset_ctrl_work(), queue teardown is immediately followed by ++ * re-allocation. fput() defers socket cleanup to delayed_fput_work ++ * in workqueue context, which can race with new queue setup. ++ */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; +- memalloc_noreclaim_restore(noreclaim_flag); ++ memalloc_noio_restore(noio_flag); + + kfree(queue->pdu); + mutex_destroy(&queue->send_mutex); +@@ -1901,8 +1915,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, + err_rcv_pdu: + kfree(queue->pdu); + err_sock: +- /* ->sock will be released by fput() */ +- fput(queue->sock->file); ++ /* Use sync variant - see nvme_tcp_free_queue() for explanation */ ++ __fput_sync(queue->sock->file); + queue->sock = NULL; + err_destroy_mutex: + mutex_destroy(&queue->send_mutex); +-- +2.53.0 + diff --git a/queue-7.0/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch b/queue-7.0/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch new file mode 100644 index 0000000000..5991becb1b --- /dev/null +++ b/queue-7.0/nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch @@ -0,0 +1,48 @@ +From 76bcc54b7dbbde59b8c80aa9e41c34fedf9f5c6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:56:58 -0400 +Subject: nvmet-tcp: check INIT_FAILED before nvmet_req_uninit in digest error + path + +From: Shivam Kumar + +[ Upstream commit 4606467a75cfc16721937272ed29462a750b60c8 ] + +In nvmet_tcp_try_recv_ddgst(), when a data digest mismatch is detected, +nvmet_req_uninit() is called unconditionally. However, if the command +arrived via the nvmet_tcp_handle_req_failure() path, nvmet_req_init() +had returned false and percpu_ref_tryget_live() was never executed. The +unconditional percpu_ref_put() inside nvmet_req_uninit() then causes a +refcount underflow, leading to a WARNING in +percpu_ref_switch_to_atomic_rcu, a use-after-free diagnostic, and +eventually a permanent workqueue deadlock. + +Check cmd->flags & NVMET_TCP_F_INIT_FAILED before calling +nvmet_req_uninit(), matching the existing pattern in +nvmet_tcp_execute_request(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Shivam Kumar +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index dc65894696ad9..f04679461c22f 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -1343,7 +1343,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + queue->idx, cmd->req.cmd->common.command_id, + queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), + le32_to_cpu(cmd->exp_ddgst)); +- nvmet_req_uninit(&cmd->req); ++ if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) ++ nvmet_req_uninit(&cmd->req); + nvmet_tcp_free_cmd_buffers(cmd); + nvmet_tcp_fatal_error(queue); + ret = -EPROTO; +-- +2.53.0 + diff --git a/queue-7.0/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch b/queue-7.0/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch new file mode 100644 index 0000000000..ee6b6ed862 --- /dev/null +++ b/queue-7.0/nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch @@ -0,0 +1,48 @@ +From 627becb5cf6adecc91404c875ef917fcb289964d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 10:48:09 +1000 +Subject: nvmet-tcp: Don't clear tls_key when freeing sq + +From: Alistair Francis + +[ Upstream commit 5fc422951c962cc01e654950fc043ebd8fadd865 ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +A previous attempt to fix this involed not calling nvmet_auth_sq_free() +on successful connections, but that results in memory leaks. Instead we +should not clear `tls_key` in nvmet_auth_sq_free(), as that was +incorrectly wiping the tls keys which are used for the session. + +This patch ensures we correctly free the ephemeral session key on +connection, yet we don't free the TLS key unless closing the connection. + +Reviewed-by: Chris Leech +Reviewed-by: Hannes Reinecke +Signed-off-by: Alistair Francis +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/auth.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c +index 2eadeb7e06f26..3a905124afdee 100644 +--- a/drivers/nvme/target/auth.c ++++ b/drivers/nvme/target/auth.c +@@ -239,9 +239,6 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq) + void nvmet_auth_sq_free(struct nvmet_sq *sq) + { + cancel_delayed_work(&sq->auth_expired_work); +-#ifdef CONFIG_NVME_TARGET_TCP_TLS +- sq->tls_key = NULL; +-#endif + kfree(sq->dhchap_c1); + sq->dhchap_c1 = NULL; + kfree(sq->dhchap_c2); +-- +2.53.0 + diff --git a/queue-7.0/nvmet-tcp-don-t-free-sq-on-authentication-success.patch b/queue-7.0/nvmet-tcp-don-t-free-sq-on-authentication-success.patch new file mode 100644 index 0000000000..e3ddc222fc --- /dev/null +++ b/queue-7.0/nvmet-tcp-don-t-free-sq-on-authentication-success.patch @@ -0,0 +1,59 @@ +From d5a40315061090a865bd8e72c4293afca62e3f89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Dec 2025 15:17:53 +1000 +Subject: nvmet-tcp: Don't free SQ on authentication success + +From: Alistair Francis + +[ Upstream commit 2e6eb6b277f593b98f151ea8eff1beb558bbea3b ] + +Curently after the host sends a REPLACETLSPSK we free the TLS keys as +part of calling nvmet_auth_sq_free() on success. This means when the +host sends a follow up REPLACETLSPSK we return CONCAT_MISMATCH as the +check for !nvmet_queue_tls_keyid(req->sq) fails. + +This patch ensures we don't free the TLS key on success as we might need +it again in the future. + +Signed-off-by: Alistair Francis +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Wilfred Mallawa +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/fabrics-cmd-auth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c +index 5946681cb0e32..96c85579150dd 100644 +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -396,9 +396,10 @@ void nvmet_execute_auth_send(struct nvmet_req *req) + goto complete; + } + /* Final states, clear up variables */ +- nvmet_auth_sq_free(req->sq); +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { ++ nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); ++ } + + complete: + nvmet_req_complete(req, status); +@@ -574,9 +575,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) + status = nvmet_copy_to_sgl(req, 0, d, al); + kfree(d); + done: +- if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) +- nvmet_auth_sq_free(req->sq); +- else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { ++ if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { + nvmet_auth_sq_free(req->sq); + nvmet_ctrl_fatal_error(ctrl); + } +-- +2.53.0 + diff --git a/queue-7.0/objtool-support-clang-rax-drap-sequence.patch b/queue-7.0/objtool-support-clang-rax-drap-sequence.patch new file mode 100644 index 0000000000..4878f19152 --- /dev/null +++ b/queue-7.0/objtool-support-clang-rax-drap-sequence.patch @@ -0,0 +1,113 @@ +From 975dbcab788af1b3ade9e02a8e029b2a01f90014 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 17:47:56 -0700 +Subject: objtool: Support Clang RAX DRAP sequence + +From: Josh Poimboeuf + +[ Upstream commit 96f3b16a9de552538b810f773645d43f3b661b50 ] + +Recent Clang can use RAX as a temporary register for the DRAP stack +alignment sequence. Add support for that. + +Fixes the following warning: + + vmlinux.o: error: objtool: vmw_host_printf+0xd: unknown CFA base reg 0 + +Closes: https://lore.kernel.org/cefefdd1-7b82-406d-8ff4-e4b167e45ee6@app.fastmail.com +Reported-by: Arnd Bergmann +Signed-off-by: Josh Poimboeuf +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/3f33dc720b83dc6d3a2b7094f75a5c90a0b1cbc5.1773708458.git.jpoimboe@kernel.org +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/orc_types.h | 1 + + arch/x86/kernel/unwind_orc.c | 8 ++++++++ + tools/arch/x86/include/asm/orc_types.h | 1 + + tools/objtool/arch/x86/decode.c | 3 +++ + tools/objtool/arch/x86/orc.c | 5 +++++ + 5 files changed, 18 insertions(+) + +diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h +index e0125afa53fb9..b3cc7970fa548 100644 +--- a/arch/x86/include/asm/orc_types.h ++++ b/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c +index f610fde2d5c4b..32f7e918d3d9f 100644 +--- a/arch/x86/kernel/unwind_orc.c ++++ b/arch/x86/kernel/unwind_orc.c +@@ -578,6 +578,14 @@ bool unwind_next_frame(struct unwind_state *state) + } + break; + ++ case ORC_REG_AX: ++ if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) { ++ orc_warn_current("missing AX value at %pB\n", ++ (void *)state->ip); ++ goto err; ++ } ++ break; ++ + default: + orc_warn("unknown SP base reg %d at %pB\n", + orc->sp_reg, (void *)state->ip); +diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h +index e0125afa53fb9..b3cc7970fa548 100644 +--- a/tools/arch/x86/include/asm/orc_types.h ++++ b/tools/arch/x86/include/asm/orc_types.h +@@ -37,6 +37,7 @@ + #define ORC_REG_R13 7 + #define ORC_REG_BP_INDIRECT 8 + #define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_AX 10 + #define ORC_REG_MAX 15 + + #define ORC_TYPE_UNDEFINED 0 +diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c +index c5817829cdfac..5931b2393bd87 100644 +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -896,6 +896,9 @@ int arch_decode_hint_reg(u8 sp_reg, int *base) + case ORC_REG_DX: + *base = CFI_DX; + break; ++ case ORC_REG_AX: ++ *base = CFI_AX; ++ break; + default: + return -1; + } +diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c +index 735e150ca6b73..5494bb450ab55 100644 +--- a/tools/objtool/arch/x86/orc.c ++++ b/tools/objtool/arch/x86/orc.c +@@ -70,6 +70,9 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct + case CFI_DX: + orc->sp_reg = ORC_REG_DX; + break; ++ case CFI_AX: ++ orc->sp_reg = ORC_REG_AX; ++ break; + default: + ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); + return -1; +@@ -138,6 +141,8 @@ static const char *reg_name(unsigned int reg) + return "bp(ind)"; + case ORC_REG_SP_INDIRECT: + return "sp(ind)"; ++ case ORC_REG_AX: ++ return "ax"; + default: + return "?"; + } +-- +2.53.0 + diff --git a/queue-7.0/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch b/queue-7.0/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch new file mode 100644 index 0000000000..afcd750a9b --- /dev/null +++ b/queue-7.0/orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch @@ -0,0 +1,48 @@ +From 39db7a9314158e85e5b6140a253879c7306a37e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 02:08:06 +0000 +Subject: orangefs: add usercopy whitelist to orangefs_op_cache + +From: Ziyi Guo + +[ Upstream commit f855f4ab123b2b9c93465288c03fbb07a5903bb3 ] + +orangefs_op_cache is created with kmem_cache_create(), which provides +no usercopy whitelist. orangefs_devreq_read() copies the tag and upcall +fields directly from slab objects to userspace via copy_to_user(). With +CONFIG_HARDENED_USERCOPY enabled, this triggers usercopy_abort(). + +Switch to kmem_cache_create_usercopy() with a whitelist covering the +tag and upcall fields, matching the pattern already used by +orangefs_inode_cache in super.c. + +Signed-off-by: Ziyi Guo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/orangefs-cache.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c +index e75e173a91862..0bdb99e897447 100644 +--- a/fs/orangefs/orangefs-cache.c ++++ b/fs/orangefs/orangefs-cache.c +@@ -19,10 +19,14 @@ static struct kmem_cache *op_cache; + + int op_cache_initialize(void) + { +- op_cache = kmem_cache_create("orangefs_op_cache", ++ op_cache = kmem_cache_create_usercopy("orangefs_op_cache", + sizeof(struct orangefs_kernel_op_s), + 0, + 0, ++ offsetof(struct orangefs_kernel_op_s, tag), ++ offsetof(struct orangefs_kernel_op_s, upcall) + ++ sizeof(struct orangefs_upcall_s) - ++ offsetof(struct orangefs_kernel_op_s, tag), + NULL); + + if (!op_cache) { +-- +2.53.0 + diff --git a/queue-7.0/orangefs-validate-getxattr-response-length.patch b/queue-7.0/orangefs-validate-getxattr-response-length.patch new file mode 100644 index 0000000000..54f21edcba --- /dev/null +++ b/queue-7.0/orangefs-validate-getxattr-response-length.patch @@ -0,0 +1,41 @@ +From 2620fa6f794da7460f4d08aac6f5d713e128c864 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:34:44 +0900 +Subject: orangefs: validate getxattr response length + +From: HyungJung Joo + +[ Upstream commit 092e0d0e964279feb9f43f81e8d1c52ef080d085 ] + +orangefs_inode_getxattr() trusts the userspace-client-controlled +downcall.resp.getxattr.val_sz and uses it as a memcpy() length +both for the temporary user buffer and the cached xattr buffer. +Reject malformed negative or oversized lengths before copying +response bytes. + +Reported-by: Hyungjung Joo +Signed-off-by: HyungJung Joo +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/xattr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c +index 1b372189cd10b..b6d116302de4e 100644 +--- a/fs/orangefs/xattr.c ++++ b/fs/orangefs/xattr.c +@@ -188,6 +188,10 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, + * Length returned includes null terminator. + */ + length = new_op->downcall.resp.getxattr.val_sz; ++ if (length < 0 || length > ORANGEFS_MAX_XATTR_VALUELEN) { ++ ret = -EIO; ++ goto out_release_op; ++ } + + /* + * Just return the length of the queried attribute. +-- +2.53.0 + diff --git a/queue-7.0/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch b/queue-7.0/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch new file mode 100644 index 0000000000..391ac69822 --- /dev/null +++ b/queue-7.0/orangefs_readahead-don-t-overflow-the-bufmap-slot.patch @@ -0,0 +1,78 @@ +From ee1b4cffc18f986a3287260db59e38d82d99e188 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 18:07:25 -0400 +Subject: orangefs_readahead: don't overflow the bufmap slot. + +From: Mike Marshall + +[ Upstream commit 415e507cdefc510c01de8ab6644163327ee9a5d0 ] + +generic/340 showed that this caller of wait_for_direct_io was +sometimes asking for more than a bufmap slot could hold. This splits +the calls up if needed. + +Signed-off-by: Mike Marshall +Signed-off-by: Sasha Levin +--- + fs/orangefs/inode.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c +index 2d4710d0e05e1..af7c9432e141b 100644 +--- a/fs/orangefs/inode.c ++++ b/fs/orangefs/inode.c +@@ -224,6 +224,8 @@ static void orangefs_readahead(struct readahead_control *rac) + loff_t new_start = readahead_pos(rac); + int ret; + size_t new_len = 0; ++ size_t this_size; ++ size_t remaining; + + loff_t bytes_remaining = inode->i_size - readahead_pos(rac); + loff_t pages_remaining = bytes_remaining / PAGE_SIZE; +@@ -239,17 +241,33 @@ static void orangefs_readahead(struct readahead_control *rac) + offset = readahead_pos(rac); + i_pages = &rac->mapping->i_pages; + +- iov_iter_xarray(&iter, ITER_DEST, i_pages, offset, readahead_length(rac)); ++ iov_iter_xarray(&iter, ITER_DEST, i_pages, ++ offset, readahead_length(rac)); + +- /* read in the pages. */ +- if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, +- &offset, &iter, readahead_length(rac), +- inode->i_size, NULL, NULL, rac->file)) < 0) +- gossip_debug(GOSSIP_FILE_DEBUG, +- "%s: wait_for_direct_io failed. \n", __func__); +- else +- ret = 0; ++ remaining = readahead_length(rac); ++ while (remaining) { ++ if (remaining > 4194304) ++ this_size = 4194304; ++ else ++ this_size = remaining; ++ ++ /* read in the pages. */ ++ if ((ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, ++ &offset, &iter, this_size, ++ inode->i_size, NULL, NULL, rac->file)) < 0) { ++ gossip_debug(GOSSIP_FILE_DEBUG, ++ "%s: wait_for_direct_io failed. :%d: \n", ++ __func__, ret); ++ goto cleanup; ++ } else { ++ ret = 0; ++ } ++ ++ remaining -= this_size; ++ offset += this_size; ++ } + ++cleanup: + /* clean up. */ + while ((folio = readahead_folio(rac))) { + if (!ret) +-- +2.53.0 + diff --git a/queue-7.0/pci-allow-all-bus-devices-to-use-the-same-slot.patch b/queue-7.0/pci-allow-all-bus-devices-to-use-the-same-slot.patch new file mode 100644 index 0000000000..d5fc3161c7 --- /dev/null +++ b/queue-7.0/pci-allow-all-bus-devices-to-use-the-same-slot.patch @@ -0,0 +1,183 @@ +From 979b2ce73f1e7d00df2c8d72f734aeb440ccd8d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 08:08:35 -0800 +Subject: PCI: Allow all bus devices to use the same slot + +From: Keith Busch + +[ Upstream commit 102c8b26b54e363f85c4c86099ca049a0a76bb58 ] + +A PCIe hotplug slot applies to the entire secondary bus. Thus, pciehp only +allocates a single hotplug_slot for the bridge to that bus. The existing +PCI slot, though, would only match to functions on device 0, meaning any +devices beyond that, e.g., ARI functions, are not matched to any slot even +though they share it. A slot reset will break all the missing devices +because the handling skips them. + +For example, ARI devices with more than 8 functions fail because their +state is not properly handled, nor is the attached driver notified of the +reset. In the best case, the device will appear unresponsive to the driver, +resulting in unexpected errors. A worse possibility may panic the kernel if +in-flight transactions trigger hardware reported errors like this real +observation: + + vfio-pci 0000:01:00.0: resetting + vfio-pci 0000:01:00.0: reset done + {1}[Hardware Error]: Error 1, type: fatal + {1}[Hardware Error]: section_type: PCIe error + {1}[Hardware Error]: port_type: 0, PCIe end point + {1}[Hardware Error]: version: 0.2 + {1}[Hardware Error]: command: 0x0140, status: 0x0010 + {1}[Hardware Error]: device_id: 0000:01:01.0 + {1}[Hardware Error]: slot: 0 + {1}[Hardware Error]: secondary_bus: 0x00 + {1}[Hardware Error]: vendor_id: 0x1d9b, device_id: 0x0207 + {1}[Hardware Error]: class_code: 020000 + {1}[Hardware Error]: bridge: secondary_status: 0x0000, control: 0x0000 + {1}[Hardware Error]: aer_cor_status: 0x00008000, aer_cor_mask: 0x00002000 + {1}[Hardware Error]: aer_uncor_status: 0x00010000, aer_uncor_mask: 0x00100000 + {1}[Hardware Error]: aer_uncor_severity: 0x006f6030 + {1}[Hardware Error]: TLP Header: 0a412800 00192080 60000004 00000004 + GHES: Fatal hardware error but panic disabled + Kernel panic - not syncing: GHES: Fatal hardware error + +Allow a slot to be created to claim all devices on a bus, not just a +matching device. This is done by introducing a sentinel value, named +PCI_SLOT_ALL_DEVICES, which then has the PCI slot match to any device on +the bus. This fixes slot resets for pciehp. + +Since 0xff already has special meaning, the chosen value for this new +feature is 0xfe. This will not clash with any actual slot number since they +are limited to 5 bits. + +Signed-off-by: Keith Busch +Signed-off-by: Bjorn Helgaas +Reviewed-by: Dan Williams +Link: https://patch.msgid.link/20260217160836.2709885-3-kbusch@meta.com +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp_core.c | 3 ++- + drivers/pci/slot.c | 31 +++++++++++++++++++++++++++---- + include/linux/pci.h | 10 +++++++++- + 3 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index 1e9158d7bac75..2cafd3b26f344 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -79,7 +79,8 @@ static int init_slot(struct controller *ctrl) + snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); + + retval = pci_hp_initialize(&ctrl->hotplug_slot, +- ctrl->pcie->port->subordinate, 0, name); ++ ctrl->pcie->port->subordinate, ++ PCI_SLOT_ALL_DEVICES, name); + if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); + kfree(ops); +diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c +index 787311614e5b6..e0b7fb43423c9 100644 +--- a/drivers/pci/slot.c ++++ b/drivers/pci/slot.c +@@ -42,6 +42,15 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) + pci_domain_nr(slot->bus), + slot->bus->number); + ++ /* ++ * Preserve legacy ABI expectations that hotplug drivers that manage ++ * multiple devices per slot emit 0 for the device number. ++ */ ++ if (slot->number == PCI_SLOT_ALL_DEVICES) ++ return sysfs_emit(buf, "%04x:%02x:00\n", ++ pci_domain_nr(slot->bus), ++ slot->bus->number); ++ + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, +@@ -73,7 +82,8 @@ static void pci_slot_release(struct kobject *kobj) + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &slot->bus->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + up_read(&pci_bus_sem); + +@@ -166,7 +176,8 @@ void pci_dev_assign_slot(struct pci_dev *dev) + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) +- if (PCI_SLOT(dev->devfn) == slot->number) ++ if (slot->number == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); + } +@@ -188,7 +199,8 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + /** + * pci_create_slot - create or increment refcount for physical PCI slot + * @parent: struct pci_bus of parent bridge +- * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder ++ * @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or ++ * PCI_SLOT_ALL_DEVICES + * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise + * +@@ -222,6 +234,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) + * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the + * %struct pci_bus and bb is the bus number. In other words, the devfn of + * the 'placeholder' slot will not be displayed. ++ * ++ * Bus-wide slots: ++ * For PCIe hotplug, the physical slot encompasses the entire secondary ++ * bus, not just a single device number. If the device supports ARI and ARI ++ * Forwarding is enabled in the upstream bridge, a multi-function device ++ * may include functions that appear to have several different device ++ * numbers, i.e., PCI_SLOT() values. Pass @slot_nr == PCI_SLOT_ALL_DEVICES ++ * to create a slot that matches all devices on the bus. Unlike placeholder ++ * slots, bus-wide slots go through normal slot lookup and reuse existing ++ * slots if present. + */ + struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + const char *name, +@@ -285,7 +307,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &parent->devices, bus_list) +- if (PCI_SLOT(dev->devfn) == slot_nr) ++ if (slot_nr == PCI_SLOT_ALL_DEVICES || ++ PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + up_read(&pci_bus_sem); + +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 57e9463e4347b..05a55907000af 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -72,12 +72,20 @@ + /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ + #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) + ++/* ++ * PCI_SLOT_ALL_DEVICES indicates a slot that covers all devices on the bus. ++ * Used for PCIe hotplug where the physical slot is the entire secondary bus, ++ * and, if ARI Forwarding is enabled, functions may appear to be on multiple ++ * devices. ++ */ ++#define PCI_SLOT_ALL_DEVICES 0xfe ++ + /* pci_slot represents a physical slot */ + struct pci_slot { + struct pci_bus *bus; /* Bus this slot is on */ + struct list_head list; /* Node in list of slots */ + struct hotplug_slot *hotplug; /* Hotplug info (move here) */ +- unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ ++ unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */ + struct kobject kobj; + }; + +-- +2.53.0 + diff --git a/queue-7.0/pci-avoid-flr-for-amd-npu-device.patch b/queue-7.0/pci-avoid-flr-for-amd-npu-device.patch new file mode 100644 index 0000000000..d1d1be8850 --- /dev/null +++ b/queue-7.0/pci-avoid-flr-for-amd-npu-device.patch @@ -0,0 +1,44 @@ +From b038e29e4c2c64277cadb962e11c8bf14d610d0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:25:45 -0800 +Subject: PCI: Avoid FLR for AMD NPU device + +From: Lizhi Hou + +[ Upstream commit 806140e9a33218f22188fe5019c7874aa78d81f8 ] + +The AMD NPU device (PCI Device IDs 0x1502 and 0x17f0) advertises FLR +support. However, triggering an FLR causes the device to hang. + +Signed-off-by: Lizhi Hou +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260226182545.3057330-1-lizhi.hou@amd.com +Signed-off-by: Sasha Levin +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 48946cca4be72..757a296eae411 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5603,6 +5603,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); + * AMD Starship/Matisse HD Audio Controller 0x1487 + * AMD Starship USB 3.0 Host Controller 0x148c + * AMD Matisse USB 3.0 Host Controller 0x149c ++ * AMD Neural Processing Unit 0x1502 0x17f0 + * Intel 82579LM Gigabit Ethernet Controller 0x1502 + * Intel 82579V Gigabit Ethernet Controller 0x1503 + * Mediatek MT7922 802.11ax PCI Express Wireless Network Adapter +@@ -5615,6 +5616,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1502, quirk_no_flr); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x17f0, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MEDIATEK, 0x0616, quirk_no_flr); +-- +2.53.0 + diff --git a/queue-7.0/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch b/queue-7.0/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch new file mode 100644 index 0000000000..9dda5a732a --- /dev/null +++ b/queue-7.0/pci-dpc-hold-pci_dev-reference-during-error-recovery.patch @@ -0,0 +1,42 @@ +From ced844ce02d84b54ebad29b455946962eb59bcac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 14:52:11 -0500 +Subject: PCI/DPC: Hold pci_dev reference during error recovery + +From: Sizhe Liu + +[ Upstream commit a1ed752bc7cb77b740cee671567d9508ae74becd ] + +The AER and EDR error handling paths hold a reference on the pci_dev during +recovery. Hold a reference during the DPC recovery path as well. + +Signed-off-by: Sizhe Liu +[bhelgaas: split to separate patch] +Signed-off-by: Bjorn Helgaas +https://patch.msgid.link/20260214081130.1878424-1-liusizhe5@huawei.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/dpc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index 7605ddd9f0ba8..2b779bd1d861b 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -373,11 +373,13 @@ static irqreturn_t dpc_handler(int irq, void *context) + return IRQ_HANDLED; + } + ++ pci_dev_get(pdev); + dpc_process_error(pdev); + + /* We configure DPC so it only triggers on ERR_FATAL */ + pcie_do_recovery(pdev, pci_channel_io_frozen, dpc_reset_link); + ++ pci_dev_put(pdev); + return IRQ_HANDLED; + } + +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch b/queue-7.0/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch new file mode 100644 index 0000000000..22d2f55deb --- /dev/null +++ b/queue-7.0/pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch @@ -0,0 +1,52 @@ +From d809d50dee1bdce094136b54772e26e387cb7568 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:01:42 +0530 +Subject: PCI: dwc: Proceed with system suspend even if the endpoint doesn't + respond with PME_TO_Ack message + +From: Manivannan Sadhasivam + +[ Upstream commit eed390775470ff0db32cce37a681f3acc2b941c3 ] + +PCIe spec r7.0, sec 5.3.3.2.1, recommends proceeding with L2/L3 sequence +even if one or devices do not respond with PME_TO_Ack message after 10ms +timeout. + +So just print a warning if the timeout happens and proceed with the system +suspend. + +Reported-by: Neil Armstrong +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Tested-by: Neil Armstrong # on SM8650-HDK +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260217113142.9140-1-manivannan.sadhasivam@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 6adde3fc32be9..7b5558561e152 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1256,9 +1256,13 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) + PCIE_PME_TO_L2_TIMEOUT_US/10, + PCIE_PME_TO_L2_TIMEOUT_US, false, pci); + if (ret) { +- /* Only log message when LTSSM isn't in DETECT or POLL */ +- dev_err(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val); +- return ret; ++ /* ++ * Failure is non-fatal since spec r7.0, sec 5.3.3.2.1, ++ * recommends proceeding with L2/L3 sequence even if one or more ++ * devices do not respond with PME_TO_Ack after 10ms timeout. ++ */ ++ dev_warn(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val); ++ ret = 0; + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/pci-prevent-assignment-to-unsupported-bridge-windows.patch b/queue-7.0/pci-prevent-assignment-to-unsupported-bridge-windows.patch new file mode 100644 index 0000000000..fd59ab9218 --- /dev/null +++ b/queue-7.0/pci-prevent-assignment-to-unsupported-bridge-windows.patch @@ -0,0 +1,76 @@ +From e8e9c14ea8f4cab0bcd76dbb34eebeb1afffbbfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 16:53:32 +0000 +Subject: PCI: Prevent assignment to unsupported bridge windows + +From: Ahmed Naseef + +[ Upstream commit 92427ab4378faa168d6953d0f8574b8fc1edcc14 ] + +Previously, pci_read_bridge_io() and pci_read_bridge_mmio_pref() +unconditionally set resource type flags (IORESOURCE_IO or IORESOURCE_MEM | +IORESOURCE_PREFETCH) when reading bridge window registers. For windows that +are not implemented in hardware, this may cause the allocator to assign +space for a window that doesn't exist. + +For example, the EcoNET EN7528 SoC Root Port doesn't support the +prefetchable window, but since a downstream device had a prefetchable BAR, +the allocator mistakenly assigned a prefetchable window: + + pci 0001:00:01.0: [14c3:0811] type 01 class 0x060400 PCIe Root Port + pci 0001:00:01.0: PCI bridge to [bus 01-ff] + pci 0001:00:01.0: bridge window [mem 0x28000000-0x280fffff]: assigned + pci 0001:00:01.0: bridge window [mem 0x28100000-0x282fffff pref]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28100000-0x281fffff 64bit pref]: assigned + +pci_read_bridge_windows() already detects unsupported windows by testing +register writability and sets dev->io_window/pref_window accordingly. + +Check dev->io_window/pref_window so we don't set the resource flags for +unsupported windows, which prevents the allocator from assigning space to +them. + +After this commit, the prefetchable BAR is correctly allocated from the +non-prefetchable window: + + pci 0001:00:01.0: bridge window [mem 0x28000000-0x281fffff]: assigned + pci 0001:01:00.0: BAR 0 [mem 0x28000000-0x280fffff 64bit pref]: assigned + +Suggested-by: Bjorn Helgaas +Link: https://lore.kernel.org/all/20260113210259.GA715789@bhelgaas/ +Signed-off-by: Ahmed Naseef +Signed-off-by: Caleb James DeLisle +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260312165332.569772-4-cjd@cjdns.fr +Signed-off-by: Sasha Levin +--- + drivers/pci/probe.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index b4707640e1021..eb27ec71dc9ea 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -395,6 +395,9 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; + ++ if (!dev->io_window) ++ return; ++ + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; + if (dev->io_window_1k) { +@@ -465,6 +468,9 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, + pci_bus_addr_t base, limit; + struct pci_bus_region region; + ++ if (!dev->pref_window) ++ return; ++ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-assert-clkreq-explicitly-by-default.patch b/queue-7.0/pci-tegra194-assert-clkreq-explicitly-by-default.patch new file mode 100644 index 0000000000..b5210ee02b --- /dev/null +++ b/queue-7.0/pci-tegra194-assert-clkreq-explicitly-by-default.patch @@ -0,0 +1,58 @@ +From f26ad3f93910c4c81a4f59437ff04e2737eded80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:39:52 +0530 +Subject: PCI: tegra194: Assert CLKREQ# explicitly by default + +From: Vidya Sagar + +[ Upstream commit 01d36261ae331583e6bc2034e6aa75c101b83e1d ] + +The Root Port's CLKREQ# signal is shared with a downstream PCIe switch and +the endpoints behind it. By default, APPL_PINMUX_CLKREQ_OVERRIDE only +overrides the CLKREQ# input to the controller (so REFCLK is enabled +internally); it does not drive the CLKREQ# output pin low. Some PCIe +switches (e.g. Broadcom PCIe Gen4) forward the Root Port's CLKREQ# to their +downstream side and expect it to be driven low for REFCLK, even when the +switch does not support CLK-PM or ASPM-L1SS. Without driving the output +pin low, link-up can fail between the switch and endpoints. + +Clear APPL_PINMUX_CLKREQ_DEFAULT_VALUE so the CLKREQ# output pad is +explicitly driven low. That makes the shared CLKREQ# line low on the wire +and avoids link-up issues with such switches. + +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324191000.1095768-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 336d3c759547a..002945de5e117 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -44,6 +44,7 @@ + #define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) + #define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) ++#define APPL_PINMUX_CLKREQ_DEFAULT_VALUE BIT(13) + + #define APPL_CTRL 0x4 + #define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) +@@ -1429,6 +1430,7 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, + val = appl_readl(pcie, APPL_PINMUX); + val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; + val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; ++ val &= ~APPL_PINMUX_CLKREQ_DEFAULT_VALUE; + appl_writel(pcie, val, APPL_PINMUX); + } + +-- +2.53.0 + diff --git a/queue-7.0/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch b/queue-7.0/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch new file mode 100644 index 0000000000..466594cce6 --- /dev/null +++ b/queue-7.0/pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch @@ -0,0 +1,53 @@ +From 41096f3a994bd419a816fdaaaddfc51d43963cf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 02:35:34 +0900 +Subject: PCI/VGA: Pass vga_get_uninterruptible() errors to userspace + +From: Simon Richter + +[ Upstream commit 2a93c9851b2bb38614fadd84aa674b7a5c8181c6 ] + +If VGA routing cannot be established, vga_get_uninterruptible() returns an +error and does not increment the lock count. Return the error to the +caller. + +Return before incrementing uc->io_cnt/mem_cnt so vga_arb_release() won't +call vga_put() when userspace closes the handle. + +Signed-off-by: Simon Richter +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260307173538.763188-2-Simon.Richter@hogyros.de +Signed-off-by: Sasha Levin +--- + drivers/pci/vgaarb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c +index d9383bf541e7c..22b2b6ebdefdb 100644 +--- a/drivers/pci/vgaarb.c ++++ b/drivers/pci/vgaarb.c +@@ -1134,6 +1134,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + char kbuf[64], *curr_pos; + size_t remaining = count; + ++ int err; + int ret_val; + int i; + +@@ -1165,7 +1166,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, + goto done; + } + +- vga_get_uninterruptible(pdev, io_state); ++ err = vga_get_uninterruptible(pdev, io_state); ++ if (err) { ++ ret_val = err; ++ goto done; ++ } + + /* Update the client's locks lists */ + for (i = 0; i < MAX_USER_CARDS; i++) { +-- +2.53.0 + diff --git a/queue-7.0/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch b/queue-7.0/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch new file mode 100644 index 0000000000..22c00709ae --- /dev/null +++ b/queue-7.0/perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch @@ -0,0 +1,99 @@ +From eb8ec472e9f27749ad92ce52c4576c022c265bd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:16 +0000 +Subject: perf/amd/ibs: Avoid race between event add and NMI + +From: Ravi Bangoria + +[ Upstream commit 1b044ff3c17e9d7fd93ffc0ba541ccdeb992d7f5 ] + +Consider the following race: + + -------- + o OP_CTL contains stale value: OP_CTL[Val]=1, OP_CTL[En]=0 + o A new IBS OP event is being added + o [P]: Process context, [N]: NMI context + + [P] perf_ibs_add(event) { + [P] if (test_and_set_bit(IBS_ENABLED, pcpu->state)) + [P] return; + [P] /* pcpu->state = IBS_ENABLED */ + [P] + [P] pcpu->event = event; + [P] + [P] perf_ibs_start(event) { + [P] set_bit(IBS_STARTED, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + [P] clear_bit(IBS_STOPPING, pcpu->state); + [P] /* pcpu->state = IBS_ENABLED | IBS_STARTED */ + + [N] --> NMI due to genuine FETCH event. perf_ibs_handle_irq() + [N] called for OP PMU as well. + [N] + [N] perf_ibs_handle_irq(perf_ibs) { + [N] event = pcpu->event; /* See line 6 */ + [N] + [N] if (!test_bit(IBS_STARTED, pcpu->state)) /* false */ + [N] return 0; + [N] + [N] if (WARN_ON_ONCE(!event)) /* false */ + [N] goto fail; + [N] + [N] if (!(*buf++ & perf_ibs->valid_mask)) /* false due to stale + [N] * IBS_OP_CTL value */ + [N] goto fail; + [N] + [N] ... + [N] + [N] perf_ibs_enable_event() // *Accidentally* enable the event. + [N] } + [N] + [N] /* + [N] * Repeated NMIs may follow due to accidentally enabled IBS OP + [N] * event if the sample period is very low. It could also lead + [N] * to pcpu->state corruption if the event gets throttled due + [N] * to too frequent NMIs. + [N] */ + + [P] perf_ibs_enable_event(); + [P] } + [P] } + -------- + +We cannot safely clear IBS_{FETCH|OP}_CTL while disabling the event, +because the register might be read again later. So, clear the register +in the enable path - before we update pcpu->state and enable the event. +This guarantees that any NMI that lands in the gap finds Val=0 and +bails out cleanly. + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-6-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 004226b52ac79..32e6456cb5e58 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -493,6 +493,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) + } + config |= period >> 4; + ++ /* ++ * Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. ++ * Doing so prevents a race condition in which an NMI due to other ++ * source might accidentally activate the event before we enable ++ * it ourselves. ++ */ ++ perf_ibs_disable_event(perf_ibs, hwc, 0); ++ + /* + * Set STARTED before enabling the hardware, such that a subsequent NMI + * must observe it. +-- +2.53.0 + diff --git a/queue-7.0/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch b/queue-7.0/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch new file mode 100644 index 0000000000..864d9f5ed0 --- /dev/null +++ b/queue-7.0/perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch @@ -0,0 +1,48 @@ +From edcacc27861f22db9727254627f32262fd3cec00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:13 +0000 +Subject: perf/amd/ibs: Limit ldlat->l3missonly dependency to Zen5 + +From: Ravi Bangoria + +[ Upstream commit 898138efc99096c3ee836fea439ba6da3cfafa4d ] + +The ldlat dependency on l3missonly is specific to Zen 5; newer generations +are not affected. This quirk is documented as an erratum in the following +Revision Guide. + + Erratum: 1606 IBS (Instruction Based Sampling) OP Load Latency Filtering + May Capture Unwanted Samples When L3Miss Filtering is Disabled + + Revision Guide for AMD Family 1Ah Models 00h-0Fh Processors, + Pub. 58251 Rev. 1.30 July 2025 + https://bugzilla.kernel.org/attachment.cgi?id=309193 + +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-3-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 7b8eea1d75c10..004226b52ac79 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -359,7 +359,10 @@ static int perf_ibs_init(struct perf_event *event) + ldlat >>= 7; + + config |= (ldlat - 1) << 59; +- config |= IBS_OP_L3MISSONLY | IBS_OP_LDLAT_EN; ++ ++ config |= IBS_OP_LDLAT_EN; ++ if (cpu_feature_enabled(X86_FEATURE_ZEN5)) ++ config |= IBS_OP_L3MISSONLY; + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch b/queue-7.0/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch new file mode 100644 index 0000000000..6df3e1cf21 --- /dev/null +++ b/queue-7.0/phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch @@ -0,0 +1,46 @@ +From 3f6e66e61330ecbb8469497e9c282c8cbe29eb72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:40:32 +0530 +Subject: phy: phy-mtk-tphy: Update names and format of kernel-doc comments + +From: Vinod Koul + +[ Upstream commit 8d869bc943cfe5db08f5aff355b1d8d3abeda865 ] + +mtk_phy_pdata documentation does not use correct tag for struct, while at +it fix one of member wrongly documented. + +Warning: drivers/phy/mediatek/phy-mtk-tphy.c:289 cannot understand function prototype: 'struct mtk_phy_pdata' +Warning: drivers/phy/mediatek/phy-mtk-tphy.c:296 struct member 'slew_ref_clock_mhz' not described in 'mtk_phy_pdata' + +Link: https://patch.msgid.link/20260223071032.408425-1-vkoul@kernel.org +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/mediatek/phy-mtk-tphy.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c +index f6504e0ecd1a7..acf5065295072 100644 +--- a/drivers/phy/mediatek/phy-mtk-tphy.c ++++ b/drivers/phy/mediatek/phy-mtk-tphy.c +@@ -276,14 +276,14 @@ enum mtk_phy_version { + }; + + /** +- * mtk_phy_pdata - SoC specific platform data ++ * struct mtk_phy_pdata - SoC specific platform data + * @avoid_rx_sen_degradation: Avoid TX Sensitivity level degradation (MT6795/8173 only) + * @sw_pll_48m_to_26m: Workaround for V3 IP (MT8195) - switch the 48MHz PLL from + * fractional mode to integer to output 26MHz for U2PHY + * @sw_efuse_supported: Switches off eFuse auto-load from PHY and applies values + * read from different nvmem (usually different eFuse array) + * that is pointed at in the device tree node for this PHY +- * @slew_ref_clk_mhz: Default reference clock (in MHz) for slew rate calibration ++ * @slew_ref_clock_mhz: Default reference clock (in MHz) for slew rate calibration + * @slew_rate_coefficient: Coefficient for slew rate calibration + * @version: PHY IP Version + */ +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-amd-support-new-acpi-id-amdi0033.patch b/queue-7.0/pinctrl-amd-support-new-acpi-id-amdi0033.patch new file mode 100644 index 0000000000..d1cfd5c8df --- /dev/null +++ b/queue-7.0/pinctrl-amd-support-new-acpi-id-amdi0033.patch @@ -0,0 +1,34 @@ +From bd35ad6624ae2204b8bc1deb82c4dd5dfff21b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:36:16 +0530 +Subject: pinctrl: amd: Support new ACPI ID AMDI0033 + +From: Basavaraj Natikar + +[ Upstream commit 127e98c05c46654867faf5f578cb56d375b89092 ] + +Add AMDI0033 to the AMD GPIO ACPI match table. +This lets the driver bind on new AMD platforms that expose this HID. + +Signed-off-by: Basavaraj Natikar +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-amd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 2af94ef564342..e3128b0045d22 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -1274,6 +1274,7 @@ static const struct acpi_device_id amd_gpio_acpi_match[] = { + { "AMD0030", 0 }, + { "AMDI0030", 0}, + { "AMDI0031", 0}, ++ { "AMDI0033", 0}, + { }, + }; + MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-realtek-fix-return-value-and-silence-log-for.patch b/queue-7.0/pinctrl-realtek-fix-return-value-and-silence-log-for.patch new file mode 100644 index 0000000000..c4e7449ceb --- /dev/null +++ b/queue-7.0/pinctrl-realtek-fix-return-value-and-silence-log-for.patch @@ -0,0 +1,47 @@ +From b2d685e674a45c35a22d137554ee9aa45dbc25da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:52:32 +0800 +Subject: pinctrl: realtek: Fix return value and silence log for unsupported + configs + +From: Tzuyi Chang + +[ Upstream commit 6a6b238c66dc69cd784baf03b170c50f7e5f24d9 ] + +Treating unsupported configurations as errors causes upper layers (like the +GPIO subsystem) to interpret optional features as hard failures, aborting +operations or printing unnecessary error logs. + +For example, during gpiod_get(), the GPIO framework attempts to set +PIN_CONFIG_PERSIST_STATE. Since this driver does not support it, false +error reports are generated in dmesg. + +Fix this by returning -ENOTSUPP and demoting the log level to dev_dbg. + +Reviewed-by: Bartosz Golaszewski +Signed-off-by: Tzuyi Chang +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 4c876d1f6ad59..9633d3deaa6f3 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -456,8 +456,8 @@ static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + break; + + default: +- dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param); +- return -EINVAL; ++ dev_dbg(data->dev, "unsupported pinconf: %d\n", (u32)param); ++ return -ENOTSUPP; + } + + ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val); +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch b/queue-7.0/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch new file mode 100644 index 0000000000..2ba5371bdd --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch @@ -0,0 +1,52 @@ +From c01f8e24b243c04128defb6d7463c3072483bf05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:40:39 +0530 +Subject: platform/x86: hp-wmi: Add support for Omen 16-wf1xxx (8C77) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Krishna Chomal + +[ Upstream commit 344bf523d441d44c75c429ea6cdcfa8f12efde4d ] + +The HP Omen 16-wf1xxx (board ID: 8C77) has the same WMI interface as +other Victus S boards, but requires quirks for correctly switching +thermal profile. + +Add the DMI board name to victus_s_thermal_profile_boards[] table and +map it to omen_v1_thermal_params. + +Testing on board 8C77 confirmed that platform profile is registered +successfully and fan RPMs are readable and controllable. + +Tested-by: Thomas Arici +Reported-by: Thomas Arici +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221300 +Signed-off-by: Krishna Chomal +Link: https://patch.msgid.link/20260410191039.125659-5-krishna.chomal108@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 75682bb4cc52a..57d9c09b3e160 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -214,6 +214,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") }, + .driver_data = (void *)&omen_v1_thermal_params, + }, ++ { ++ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C77") }, ++ .driver_data = (void *)&omen_v1_thermal_params, ++ }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, + .driver_data = (void *)&omen_v1_thermal_params, +-- +2.53.0 + diff --git a/queue-7.0/power-supply-sbs-manager-normalize-return-value-of-g.patch b/queue-7.0/power-supply-sbs-manager-normalize-return-value-of-g.patch new file mode 100644 index 0000000000..99db9a20f2 --- /dev/null +++ b/queue-7.0/power-supply-sbs-manager-normalize-return-value-of-g.patch @@ -0,0 +1,39 @@ +From 546a87cf1b93778725913a6fe681fbc8557058db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 12:59:49 -0800 +Subject: power: supply: sbs-manager: normalize return value of gpio_get + +From: Dmitry Torokhov + +[ Upstream commit 5c2ffc0b215a884dbc961d4737f636067348b8bd ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by sbsm_gpio_get_value() is +normalized to the [0, 1] range. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Linus Walleij +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/aZYoL2MnTYU5FuQh@google.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/sbs-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c +index 6fe526222f7f4..343ad4ab4082c 100644 +--- a/drivers/power/supply/sbs-manager.c ++++ b/drivers/power/supply/sbs-manager.c +@@ -199,7 +199,7 @@ static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) + if (ret < 0) + return ret; + +- return ret & BIT(off); ++ return !!(ret & BIT(off)); + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch b/queue-7.0/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch new file mode 100644 index 0000000000..105a859dfb --- /dev/null +++ b/queue-7.0/powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch @@ -0,0 +1,80 @@ +From 1ec0c166a4f0e512624e854bb9d09c820198e03b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 23:44:26 +0530 +Subject: powerpc/64s: Fix _HPAGE_CHG_MASK to include _PAGE_SPECIAL bit + +From: Ritesh Harjani (IBM) + +[ Upstream commit 68b1fa0ed5c84769e4e60d58f6a5af37e7273b51 ] + +commit af38538801c6a ("mm/memory: factor out common code from vm_normal_page_*()"), +added a VM_WARN_ON_ONCE for huge zero pfn. + +This can lead to the following call stack. + + ------------[ cut here ]------------ + WARNING: mm/memory.c:735 at vm_normal_page_pmd+0xf0/0x140, CPU#19: hmm-tests/3366 + NIP [c00000000078d0c0] vm_normal_page_pmd+0xf0/0x140 + LR [c00000000078d060] vm_normal_page_pmd+0x90/0x140 + Call Trace: + [c00000016f56f850] [c00000000078d060] vm_normal_page_pmd+0x90/0x140 (unreliable) + [c00000016f56f8a0] [c0000000008a9e30] change_huge_pmd+0x7c0/0x870 + [c00000016f56f930] [c0000000007b2bc4] change_protection+0x17a4/0x1e10 + [c00000016f56fba0] [c0000000007b3440] mprotect_fixup+0x210/0x4c0 + [c00000016f56fc30] [c0000000007b3c3c] do_mprotect_pkey+0x54c/0x780 + [c00000016f56fdb0] [c0000000007b3ed8] sys_mprotect+0x68/0x90 + [c00000016f56fdf0] [c00000000003ae40] system_call_exception+0x190/0x500 + [c00000016f56fe50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec + +This happens when we call mprotect -> change_huge_pmd() +mprotect() + change_pmd_range() + pmd_modify(oldpmd, newprot) # this clears _PAGE_SPECIAL for zero huge pmd + pmdv = pmd_val(pmd); + pmdv &= _HPAGE_CHG_MASK; # -> gets cleared here + return pmd_set_protbits(__pmd(pmdv), newprot); + can_change_pmd_writable(vma, vmf->address, pmd) + vm_normal_page_pmd(vma, addr, pmd) + __vm_normal_page() + VM_WARN_ON(is_zero_pfn(pfn) || is_huge_zero_pfn(pfn)); # this get hits as _PAGE_SPECIAL for zero huge pmd was cleared. + +It can be easily reproduced with the following testcase: + p = mmap(NULL, 2 * hpage_pmd_size, PROT_READ, MAP_PRIVATE | + MAP_ANONYMOUS, -1, 0); + madvise((void *)p, 2 * hpage_pmd_size, MADV_HUGEPAGE); + aligned = (char*)(((unsigned long)p + hpage_pmd_size - 1) & + ~(hpage_pmd_size - 1)); + (void)(*(volatile char*)aligned); // read fault, installs huge zero PMD + mprotect((void *)aligned, hpage_pmd_size, PROT_READ | PROT_WRITE); + +This patch adds _PAGE_SPECIAL to _HPAGE_CHG_MASK similar to +_PAGE_CHG_MASK, as we don't want to clear this bit when calling +pmd_modify() while changing protection bits. + +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/7416f5cdbcfeaad947860fcac488b483f1287172.1773078178.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/book3s/64/pgtable.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h +index 66a953046a49a..59e24507f2377 100644 +--- a/arch/powerpc/include/asm/book3s/64/pgtable.h ++++ b/arch/powerpc/include/asm/book3s/64/pgtable.h +@@ -107,8 +107,8 @@ + * in here, on radix we expect them to be zero. + */ + #define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \ +- _PAGE_ACCESSED | H_PAGE_THP_HUGE | _PAGE_PTE | \ +- _PAGE_SOFT_DIRTY) ++ _PAGE_ACCESSED | H_PAGE_THP_HUGE | _PAGE_SPECIAL | \ ++ _PAGE_PTE | _PAGE_SOFT_DIRTY) + /* + * user access blocked by key + */ +-- +2.53.0 + diff --git a/queue-7.0/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch b/queue-7.0/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch new file mode 100644 index 0000000000..8834faeab1 --- /dev/null +++ b/queue-7.0/powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch @@ -0,0 +1,48 @@ +From 62024583809bfc2ac6ad0ea57aa5e3175c3a7125 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Nov 2025 19:55:44 +0530 +Subject: powerpc: 82xx: fix uninitialized pointers with free attribute + +From: Ally Heev + +[ Upstream commit acd1e47db03d4b528fd5efb8565dd0de1c79f62a ] + +Uninitialized pointers with `__free` attribute can cause undefined +behavior as the memory allocated to the pointer is freed automatically +when the pointer goes out of scope. + +powerpc/km82xx doesn't have any bugs related to this as of now, but, +it is better to initialize and assign pointers with `__free` attribute +in one statement to ensure proper scope-based cleanup + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/all/aPiG_F5EBQUjZqsl@stanley.mountain/ +Signed-off-by: Ally Heev +Fixes: 4aa5cc1e0012 ("powerpc-km82xx.c: replace of_node_put() with __free") +Reviewed-by: Christophe Leroy (CS GROUP) +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20251116-aheev-uninitialized-free-attr-km82xx-v2-1-4307e2b5300d@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/platforms/82xx/km82xx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c +index 99f0f0f418767..4ad223525e893 100644 +--- a/arch/powerpc/platforms/82xx/km82xx.c ++++ b/arch/powerpc/platforms/82xx/km82xx.c +@@ -27,8 +27,8 @@ + + static void __init km82xx_pic_init(void) + { +- struct device_node *np __free(device_node); +- np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); ++ struct device_node *np __free(device_node) = of_find_compatible_node(NULL, ++ NULL, "fsl,pq2-pic"); + + if (!np) { + pr_err("PIC init: can not find cpm-pic node\n"); +-- +2.53.0 + diff --git a/queue-7.0/powerpc-fix-dead-default-for-guest_state_buffer_test.patch b/queue-7.0/powerpc-fix-dead-default-for-guest_state_buffer_test.patch new file mode 100644 index 0000000000..5608ab76ff --- /dev/null +++ b/queue-7.0/powerpc-fix-dead-default-for-guest_state_buffer_test.patch @@ -0,0 +1,54 @@ +From 6c033cc9c6cbb8078e7eec7aeb90ffd59a0f6f80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 17:15:45 +0100 +Subject: powerpc: fix dead default for GUEST_STATE_BUFFER_TEST + +From: Julian Braha + +[ Upstream commit aef656a0e6c01796190bb5bd2bdba1c644ed7811 ] + +The GUEST_STATE_BUFFER_TEST config option should default +to KUNIT_ALL_TESTS so that if all tests are enabled then +it is included, but currently the 'default KUNIT_ALL_TESTS' +statement is shadowed by 'def_tristate n', +meaning that this second default statement is currently dead code. + +It looks to me like the commit +6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +intended to set the default to KUNIT_ALL_TESTS, but mistakenly +missed the def_tristate. + +This dead code was found by kconfirm, a static analysis tool for Kconfig. + +Fixes: 6ccbbc33f06a ("KVM: PPC: Add helper library for Guest State Buffers") +Signed-off-by: Julian Braha +Tested-by: Gautam Menghani +Reviewed-by: Amit Machhiwal +Reviewed-by: Harsh Prateek Bora +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260405161545.161006-1-julianbraha@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/Kconfig.debug | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug +index f15e5920080ba..e8718bc13eeb1 100644 +--- a/arch/powerpc/Kconfig.debug ++++ b/arch/powerpc/Kconfig.debug +@@ -83,11 +83,10 @@ config MSI_BITMAP_SELFTEST + depends on DEBUG_KERNEL + + config GUEST_STATE_BUFFER_TEST +- def_tristate n ++ def_tristate KUNIT_ALL_TESTS + prompt "Enable Guest State Buffer unit tests" + depends on KUNIT + depends on KVM_BOOK3S_HV_POSSIBLE +- default KUNIT_ALL_TESTS + help + The Guest State Buffer is a data format specified in the PAPR. + It is by hcalls to communicate the state of L2 guests between +-- +2.53.0 + diff --git a/queue-7.0/powerpc-hv-gpci-fix-preempt-count-leak-in-sysfs-show.patch b/queue-7.0/powerpc-hv-gpci-fix-preempt-count-leak-in-sysfs-show.patch new file mode 100644 index 0000000000..e67c57edbb --- /dev/null +++ b/queue-7.0/powerpc-hv-gpci-fix-preempt-count-leak-in-sysfs-show.patch @@ -0,0 +1,163 @@ +From 1cbe4ae85987dabdc650aaa763e9676ec9546db8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:42:56 +0530 +Subject: powerpc/hv-gpci: fix preempt count leak in sysfs show paths + +From: Aboorva Devarajan + +[ Upstream commit dbc30a57bd8e026995e9fa8e8c31cffd18542c01 ] + +Four sysfs show() callbacks in hv-gpci take get_cpu_var(hv_gpci_reqb) +(which calls preempt_disable()) but only call the matching put_cpu_var() +on the error path under the 'out:' label. Every successful read leaks +one preempt_disable(): + + processor_bus_topology_show() + processor_config_show() + affinity_domain_via_virtual_processor_show() + affinity_domain_via_domain_show() + +(affinity_domain_via_partition_show() was already correct.) + +On a CONFIG_PREEMPT=y kernel, repeated reads raise preempt_count and +eventually return to userspace with preemption still disabled. The +next user-mode page fault then hits faulthandler_disabled() == 1, +gets forced to SIGSEGV, and the resulting coredump trips +'BUG: scheduling while atomic' in call_usermodehelper_exec -> +wait_for_completion_state -> schedule: + + BUG: scheduling while atomic: //0x00000004 + ... + __schedule_bug+0x6c/0x90 + __schedule+0x58c/0x13a0 + schedule+0x48/0x1a0 + schedule_timeout+0x104/0x170 + wait_for_completion_state+0x16c/0x330 + call_usermodehelper_exec+0x254/0x2d0 + vfs_coredump+0x1050/0x2590 + get_signal+0xb9c/0xc80 + do_notify_resume+0xf8/0x470 + +Add an out_success label that calls put_cpu_var() before returning +the byte count, mirroring affinity_domain_via_partition_show(). + +Fixes: 71f1c39647d8 ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show processor bus topology information") +Fixes: 1a160c2a13c6 ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show processor config information") +Fixes: 71a7ccb478fc ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show affinity domain via virtual processor information") +Fixes: a69a57cac1ec ("powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show affinity domain via domain information") +Signed-off-by: Aboorva Devarajan +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260508041256.3447113-1-aboorvad@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/perf/hv-gpci.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c +index 5cac2cf3bd1e5..10c82cf8f5b39 100644 +--- a/arch/powerpc/perf/hv-gpci.c ++++ b/arch/powerpc/perf/hv-gpci.c +@@ -210,7 +210,7 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att + 0, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; +@@ -244,12 +244,14 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att + starting_index, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; + } + ++out_success: ++ put_cpu_var(hv_gpci_reqb); + return n; + + out: +@@ -278,7 +280,7 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute + 0, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; +@@ -312,12 +314,14 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute + starting_index, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; + } + ++out_success: ++ put_cpu_var(hv_gpci_reqb); + return n; + + out: +@@ -346,7 +350,7 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, + 0, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; +@@ -382,12 +386,14 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, + starting_index, secondary_index, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; + } + ++out_success: ++ put_cpu_var(hv_gpci_reqb); + return n; + + out: +@@ -416,7 +422,7 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device + 0, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; +@@ -448,12 +454,14 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device + starting_index, 0, buf, &n, arg); + + if (!ret) +- return n; ++ goto out_success; + + if (ret != H_PARAMETER) + goto out; + } + ++out_success: ++ put_cpu_var(hv_gpci_reqb); + return n; + + out: +-- +2.53.0 + diff --git a/queue-7.0/powerpc-time-remove-redundant-preempt_disable-enable.patch b/queue-7.0/powerpc-time-remove-redundant-preempt_disable-enable.patch new file mode 100644 index 0000000000..c409b39f3c --- /dev/null +++ b/queue-7.0/powerpc-time-remove-redundant-preempt_disable-enable.patch @@ -0,0 +1,98 @@ +From 9ded871919bdd99c0296e76e591c7e49ccf5010f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:44:13 +0530 +Subject: powerpc/time: Remove redundant preempt_disable|enable() calls from + arch_irq_work_raise() + +From: Sayali Patil + +[ Upstream commit 31467b23823ffec1f6fff407f8e3ca9af8b7491a ] + +A kernel panic is observed when handling machine check exceptions from +real mode. + + BUG: Unable to handle kernel data access on read at 0xc00000006be21300 + Oops: Kernel access of bad area, sig: 11 [#1] + MSR: 8000000000001003 CR: 88222248 XER: 00000005 + CFAR: c00000000003ffc4 DAR: c00000006be21300 DSISR: 40000000 IRQMASK: 0 + NIP [c000000000029e40] arch_irq_work_raise+0x10/0x70 + LR [c00000000003ffc8] machine_check_queue_event+0xa8/0x150 + Call Trace: + [c0000000179d3c70] [c00000000003ff64] machine_check_queue_event+0x44/0x150 + [c0000000179d3d30] [c0000000000084e0] machine_check_early_common+0x1f0/0x2c0 + +The crash occurs because arch_irq_work_raise() calls preempt_disable() +from machine check exception (MCE) handlers running in real mode. In +this context, accessing the preempt_count can fault, leading to the panic. + +The preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +was originally added by commit 0fe1ac48bef0 ("powerpc/perf_event: Fix +oops due to perf_event_do_pending call") to avoid races while raising +irq work from exception context. + +Later, commit 471ba0e686cb ("irq_work: Do not raise an IPI when +queueing work on the local CPU") added preemption protection in +irq_work_queue() path, while commit 20b876918c06 ("irq_work: Use per +cpu atomics instead of regular atomics") added equivalent +protection in irq_work_queue_on() before reaching arch_irq_work_raise(): + + irq_work_queue() / irq_work_queue_on() + -> preempt_disable() + -> __irq_work_queue_local() + -> irq_work_raise() + -> arch_irq_work_raise() + +As a result, callers other than mce_irq_work_raise() already execute +with preemption disabled, making the additional +preempt_disable()/preempt_enable() pair in arch_irq_work_raise() +redundant. + +The arch_irq_work_raise() function executes in NMI context when called +from MCE handler. Hence we will not be preempted or scheduled out since +we are in NMI context with MSR[EE]=0. Therefore, it is safe to remove +the preempt_disable()/preempt_enable() calls from here. + +Remove it to avoid accessing preempt_count from real mode context. + +Fixes: cc15ff327569 ("powerpc/mce: Avoid using irq_work_queue() in realmode") +Suggested-by: Mahesh Salgaonkar +Acked-by: Shrikanth Hegde +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Sayali Patil +[Maddy: Fixed the commit title] +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260513081413.222490-1-sayalip@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/time.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index 4bbeb8644d3da..b4472288e0d43 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -458,6 +458,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); + + #endif /* 32 vs 64 bit */ + ++/* ++ * Must be called with preemption disabled since it updates ++ * per-CPU irq_work state and programs the local CPU decrementer. ++ */ + void arch_irq_work_raise(void) + { + /* +@@ -471,10 +475,8 @@ void arch_irq_work_raise(void) + * which could get tangled up if we're messing with the same state + * here. + */ +- preempt_disable(); + set_irq_work_pending_flag(); + set_dec(1); +- preempt_enable(); + } + + static void set_dec_or_work(u64 val) +-- +2.53.0 + diff --git a/queue-7.0/ppp-disconnect-channel-before-nullifying-pch-chan.patch b/queue-7.0/ppp-disconnect-channel-before-nullifying-pch-chan.patch new file mode 100644 index 0000000000..47cc92d023 --- /dev/null +++ b/queue-7.0/ppp-disconnect-channel-before-nullifying-pch-chan.patch @@ -0,0 +1,51 @@ +From fa2cb97b8beccfc9c0f0e4d7da2c98f59c395662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:37:30 +0800 +Subject: ppp: disconnect channel before nullifying pch->chan + +From: Qingfang Deng + +[ Upstream commit 6a196e83a1a7e50be93482d1cd4305641f1a9fb1 ] + +In ppp_unregister_channel(), pch->chan is set to NULL before calling +ppp_disconnect_channel(), which removes the channel from ppp->channels +list using list_del_rcu() + synchronize_net(). This creates an +intermediate state where the channel is still connected (on the list) +but already unregistered (pch->chan == NULL). + +Call ppp_disconnect_channel() before setting pch->chan to NULL. After +the synchronize_net(), no new reader on the transmit path will hold a +reference to the channel from the list. + +This eliminates the problematic state, and prepares for removing the +pch->chan NULL checks from the transmit path in a subsequent patch. + +Signed-off-by: Qingfang Deng +Link: https://patch.msgid.link/20260312093732.277254-1-dqfext@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 192a5b94783e3..cc05c8e2517cd 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3026,12 +3026,12 @@ ppp_unregister_channel(struct ppp_channel *chan) + * This ensures that we have returned from any calls into + * the channel's start_xmit or ioctl routine before we proceed. + */ ++ ppp_disconnect_channel(pch); + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + WRITE_ONCE(pch->chan, NULL); + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); +- ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); +-- +2.53.0 + diff --git a/queue-7.0/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch b/queue-7.0/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch new file mode 100644 index 0000000000..798b5eae34 --- /dev/null +++ b/queue-7.0/pstore-fix-ftrace-dump-when-ecc-is-enabled.patch @@ -0,0 +1,69 @@ +From 18c7c7cdb3894272971dfd15d1c5bacd29c0f1d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 21:51:55 +0300 +Subject: pstore: fix ftrace dump, when ECC is enabled + +From: Andrey Skvortsov + +[ Upstream commit 4ef6255cc56343bc90d82420b49dab1b11dee414 ] + +total_size is sum of record->size and record->ecc_notice_size (ECC: No +errors detected). When ECC is not used, then there is no problem. +When ECC is enabled, then ftrace dump is decoded incorrectly after +restart. + +First this affects starting offset calculation, that breaks +reading of all ftrace records. + + CPU:66 ts:51646260179894273 3818ffff80008002 fe00ffff800080f0 0x3818ffff80008002 <- 0xfe00ffff800080f0 + CPU:66 ts:56589664458375169 3818ffff80008002 ff02ffff800080f0 0x3818ffff80008002 <- 0xff02ffff800080f0 + CPU:67 ts:13194139533313 afe4ffff80008002 1ffff800080f0 0xafe4ffff80008002 <- 0x1ffff800080f0 + CPU:67 ts:13194139533313 b7d0ffff80008001 100ffff80008002 0xb7d0ffff80008001 <- 0x100ffff80008002 + CPU:67 ts:51646260179894273 8de0ffff80008001 202ffff80008002 0x8de0ffff80008001 <- 0x202ffff80008002 + +Second ECC notice message is printed like ftrace record and as a +result couple of last records are completely wrong. + +For example, when the starting offset is fixed: + + CPU:0 ts:113 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:0 ts:114 ffffffc00879bd04 ffffffc0080dc08c cpuidle_enter <- do_idle+0x20c/0x290 + CPU:100 ts:28259048229270629 6f4e203a4343450a 2073726f72726520 0x6f4e203a4343450a <- 0x2073726f72726520 + +Signed-off-by: Andrey Skvortsov +Tested-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260215185156.317394-1-andrej.skvortzov@gmail.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/inode.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index 83fa0bb3435ac..d0ca91040591c 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -74,9 +74,9 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos) + if (!data) + return NULL; + +- data->off = ps->total_size % REC_SIZE; ++ data->off = ps->record->size % REC_SIZE; + data->off += *pos * REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return_ptr(data); +@@ -94,7 +94,7 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos) + + (*pos)++; + data->off += REC_SIZE; +- if (data->off + REC_SIZE > ps->total_size) ++ if (data->off + REC_SIZE > ps->record->size) + return NULL; + + return data; +-- +2.53.0 + diff --git a/queue-7.0/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch b/queue-7.0/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch new file mode 100644 index 0000000000..712bdd7f17 --- /dev/null +++ b/queue-7.0/remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch @@ -0,0 +1,85 @@ +From 9f2d90afdf35dfc5be150846060fc0b3b360e5ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:42:43 +0530 +Subject: remoteproc: qcom: Fix minidump out-of-bounds access on subsystems + array + +From: Mukesh Ojha + +[ Upstream commit 743cfae79d2458e241b06ed523c28a09f1449b75 ] + +MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct, +which is a direct overlay on an SMEM item allocated by the firmware. +Newer Qualcomm SoC firmware allocates space for more subsystems, while +older firmware only allocates space for 10. Bumping the constant would +cause Linux to read/write beyond the SMEM item boundary on older +platforms. + +Fix this by converting subsystems[] to a flexible array member and +deriving the actual number of subsystems at runtime from the size +returned by qcom_smem_get(). Add a bounds check on minidump_id against +the derived count before indexing into the array. + +Signed-off-by: Mukesh Ojha +Acked-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/qcom_common.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c +index 6c31140268acb..fd2b6824ad265 100644 +--- a/drivers/remoteproc/qcom_common.c ++++ b/drivers/remoteproc/qcom_common.c +@@ -28,7 +28,6 @@ + #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) + #define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev) + +-#define MAX_NUM_OF_SS 10 + #define MAX_REGION_NAME_LENGTH 16 + #define SBL_MINIDUMP_SMEM_ID 602 + #define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +@@ -80,7 +79,7 @@ struct minidump_global_toc { + __le32 status; + __le32 md_revision; + __le32 enabled; +- struct minidump_subsystem subsystems[MAX_NUM_OF_SS]; ++ struct minidump_subsystem subsystems[]; + }; + + struct qcom_ssr_subsystem { +@@ -151,9 +150,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + int ret; + struct minidump_subsystem *subsystem; + struct minidump_global_toc *toc; ++ unsigned int num_ss; ++ size_t toc_size; + + /* Get Global minidump ToC*/ +- toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL); ++ toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size); + + /* check if global table pointer exists and init is set */ + if (IS_ERR(toc) || !toc->status) { +@@ -161,6 +162,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, + return; + } + ++ /* Derive the number of subsystems from the actual SMEM item size */ ++ num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) / ++ sizeof(struct minidump_subsystem); ++ ++ if (minidump_id >= num_ss) { ++ dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n", ++ minidump_id, num_ss); ++ return; ++ } ++ + /* Get subsystem table of contents using the minidump id */ + subsystem = &toc->subsystems[minidump_id]; + +-- +2.53.0 + diff --git a/queue-7.0/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch b/queue-7.0/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch new file mode 100644 index 0000000000..3b8e12bd8b --- /dev/null +++ b/queue-7.0/ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch @@ -0,0 +1,70 @@ +From b8fe2928f654021091b92eec2e8f98f3e2b5bd45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 06:36:59 +0100 +Subject: ring-buffer: Enforce read ordering of trace_buffer cpumask and + buffers + +From: Vincent Donnefort + +[ Upstream commit 20ad8b0888be392eb2c4c3654805eb8594952373 ] + +On CPU hotplug, if it is the first time a trace_buffer sees a CPU, a +ring_buffer_per_cpu will be allocated and its corresponding bit toggled +in the cpumask. Many readers check this cpumask to know if they can +safely read the ring_buffer_per_cpu but they are doing so without memory +ordering and may observe the cpumask bit set while having NULL buffer +pointer. + +Enforce the memory read ordering by sending an IPI to all online CPUs. +The hotplug path is a slow-path anyway and it saves us from adding read +barriers in numerous call sites. + +Link: https://patch.msgid.link/20260401053659.3458961-1-vdonnefort@google.com +Signed-off-by: Vincent Donnefort +Suggested-by: Steven Rostedt (Google) +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/ring_buffer.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index aad2c7254f62b..a16098ec2a731 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -7469,6 +7469,12 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu) + return 0; + } + ++static void rb_cpu_sync(void *data) ++{ ++ /* Not really needed, but documents what is happening */ ++ smp_rmb(); ++} ++ + /* + * We only allocate new buffers, never free them if the CPU goes down. + * If we were to free the buffer, then the user would lose any trace that was in +@@ -7507,7 +7513,18 @@ int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node) + cpu); + return -ENOMEM; + } +- smp_wmb(); ++ ++ /* ++ * Ensure trace_buffer readers observe the newly allocated ++ * ring_buffer_per_cpu before they check the cpumask. Instead of using a ++ * read barrier for all readers, send an IPI. ++ */ ++ if (unlikely(system_state == SYSTEM_RUNNING)) { ++ on_each_cpu(rb_cpu_sync, NULL, 1); ++ /* Not really needed, but documents what is happening */ ++ smp_wmb(); ++ } ++ + cpumask_set_cpu(cpu, buffer->cpumask); + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/riscv-docs-fix-unmatched-quote-warning.patch b/queue-7.0/riscv-docs-fix-unmatched-quote-warning.patch new file mode 100644 index 0000000000..0392b191ee --- /dev/null +++ b/queue-7.0/riscv-docs-fix-unmatched-quote-warning.patch @@ -0,0 +1,39 @@ +From 60f33156c41ac08baef2942da0c081c02443ee10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 16:23:04 -0700 +Subject: riscv: Docs: fix unmatched quote warning + +From: Randy Dunlap + +[ Upstream commit 50da1c9ccb70fc5250c37ac474b54ee072732ea3 ] + +'make htmldocs' complains about ``prctrl` -- so add a second '`' to +avoid the warning. + +Documentation/arch/riscv/zicfilp.rst:79: WARNING: Inline literal start-string without end-string. [docutils] + +Fixes: 08ee1559052b ("prctl: cfi: change the branch landing pad prctl()s to be more descriptive") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260406232304.1892528-1-rdunlap@infradead.org +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + Documentation/arch/riscv/zicfilp.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/arch/riscv/zicfilp.rst b/Documentation/arch/riscv/zicfilp.rst +index ab7d8e62ddaff..12b35969d17ad 100644 +--- a/Documentation/arch/riscv/zicfilp.rst ++++ b/Documentation/arch/riscv/zicfilp.rst +@@ -78,7 +78,7 @@ the program. + + Per-task indirect branch tracking state can be monitored and + controlled via the :c:macro:`PR_GET_CFI` and :c:macro:`PR_SET_CFI` +-``prctl()` arguments (respectively), by supplying ++``prctl()`` arguments (respectively), by supplying + :c:macro:`PR_CFI_BRANCH_LANDING_PADS` as the second argument. These + are architecture-agnostic, and will return -EINVAL if the underlying + functionality is not supported. +-- +2.53.0 + diff --git a/queue-7.0/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch b/queue-7.0/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch new file mode 100644 index 0000000000..0e7d065064 --- /dev/null +++ b/queue-7.0/riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch @@ -0,0 +1,45 @@ +From 15599f053e66c6db726f62803be9bd8ec66374f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 09:11:39 +0000 +Subject: riscv: errata: Fix bitwise vs logical AND in MIPS errata patching + +From: Michael Neuling + +[ Upstream commit 4d2b03699460b8fd5df34408a03a84a1a7ff8aa1 ] + +The condition checking whether a specific errata needs patching uses +logical AND (&&) instead of bitwise AND (&). Since logical AND only +checks that both operands are non-zero, this causes all errata patches +to be applied whenever any single errata is detected, rather than only +applying the matching one. + +The SiFive errata implementation correctly uses bitwise AND for the same +check. + +Fixes: 0b0ca959d206 ("riscv: errata: Fix the PAUSE Opcode for MIPS P8700") +Signed-off-by: Michael Neuling +Assisted-by: Cursor:claude-4.6-opus-high-thinking +Link: https://patch.msgid.link/20260409091143.1348853-2-mikey@neuling.org +[pjw@kernel.org: fixed checkpatch warning] +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/errata/mips/errata.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c +index e984a8152208c..2c3dc2259e93e 100644 +--- a/arch/riscv/errata/mips/errata.c ++++ b/arch/riscv/errata/mips/errata.c +@@ -57,7 +57,7 @@ void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + } + + tmp = (1U << alt->patch_id); +- if (cpu_req_errata && tmp) { ++ if (cpu_req_errata & tmp) { + mutex_lock(&text_mutex); + patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt), + alt->alt_len); +-- +2.53.0 + diff --git a/queue-7.0/riscv-fix-register-corruption-from-uninitialized-cre.patch b/queue-7.0/riscv-fix-register-corruption-from-uninitialized-cre.patch new file mode 100644 index 0000000000..76f40d08e5 --- /dev/null +++ b/queue-7.0/riscv-fix-register-corruption-from-uninitialized-cre.patch @@ -0,0 +1,64 @@ +From 123d104ecb206c6453773958f26e25890f8a8792 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 May 2026 06:23:20 +0000 +Subject: riscv: Fix register corruption from uninitialized cregs on error + +From: Michael Neuling + +[ Upstream commit 6ebcbb53fc9bc30843054ed99fd60b8e542628f4 ] + +compat_riscv_gpr_set() calls cregs_to_regs() unconditionally, even when +user_regset_copyin() fails. Since cregs is an uninitialized stack +variable, a copyin failure causes uninitialized stack data to be written +into the target task's pt_regs, corrupting its register state and +potentially leaking kernel stack contents. + +compat_restore_sigcontext() has the same issue: it calls cregs_to_regs() +even when __copy_from_user() fails, leading to the same corruption of +the signal-returning task's register state on error. + +Only call cregs_to_regs() when the user copy succeeds. + +Fixes: 4608c159594f ("riscv: compat: ptrace: Add compat_arch_ptrace implement") +Fixes: 7383ee05314b ("riscv: compat: signal: Add rt_frame implementation") +Signed-off-by: Michael Neuling +Assisted-by: Cursor:claude-4.6-opus-high-thinking +Link: https://patch.msgid.link/20260501062320.2339562-1-mikey@neuling.org +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/compat_signal.c | 2 ++ + arch/riscv/kernel/ptrace.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/riscv/kernel/compat_signal.c b/arch/riscv/kernel/compat_signal.c +index 6ec4e34255a9a..cf3eb33a11e46 100644 +--- a/arch/riscv/kernel/compat_signal.c ++++ b/arch/riscv/kernel/compat_signal.c +@@ -107,6 +107,8 @@ static long compat_restore_sigcontext(struct pt_regs *regs, + + /* sc_regs is structured the same as the start of pt_regs */ + err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs)); ++ if (unlikely(err)) ++ return err; + + cregs_to_regs(&cregs, regs); + +diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c +index 93de2e7a30747..793bcee461828 100644 +--- a/arch/riscv/kernel/ptrace.c ++++ b/arch/riscv/kernel/ptrace.c +@@ -577,8 +577,8 @@ static int compat_riscv_gpr_set(struct task_struct *target, + struct compat_user_regs_struct cregs; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1); +- +- cregs_to_regs(&cregs, task_pt_regs(target)); ++ if (!ret) ++ cregs_to_regs(&cregs, task_pt_regs(target)); + + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch b/queue-7.0/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch new file mode 100644 index 0000000000..656288608f --- /dev/null +++ b/queue-7.0/riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch @@ -0,0 +1,87 @@ +From 0b7dc29e3ec5039f012387bb8a220188724d2b5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 00:52:12 -0500 +Subject: riscv: mm: Fixup no5lvl failure when vaddr is invalid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Guo Ren (Alibaba DAMO Academy) + +[ Upstream commit db909bd7986c10da074917af3dae83a60fa65093 ] + +Unlike no4lvl, no5lvl still continues to detect satp, which +requires va=pa mapping. When pa=0x800000000000, no5lvl +would fail in Sv48 mode due to an illegal VA value of +0x800000000000. + +So, prevent detecting the satp flow for no5lvl, when +vaddr is invalid. Add the is_vaddr_valid() function for +checking. + +Fixes: 26e7aacb83df ("riscv: Allow to downgrade paging mode from the command line") +Cc: Alexandre Ghiti +Cc: Björn Töpel +Signed-off-by: Guo Ren (Alibaba DAMO Academy) +Tested-by: Fangyu Yu +Link: https://patch.msgid.link/20260125055212.433163-1-guoren@kernel.org +[pjw@kernel.org: cleaned up commit message] +Signed-off-by: Paul Walmsley +Signed-off-by: Sasha Levin +--- + arch/riscv/mm/init.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 811e03786c560..1b221c3fe2750 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -846,6 +846,27 @@ static void __init set_mmap_rnd_bits_max(void) + mmap_rnd_bits_max = MMAP_VA_BITS - PAGE_SHIFT - 3; + } + ++static bool __init is_vaddr_valid(unsigned long va) ++{ ++ unsigned long up = 0; ++ ++ switch (satp_mode) { ++ case SATP_MODE_39: ++ up = 1UL << 38; ++ break; ++ case SATP_MODE_48: ++ up = 1UL << 47; ++ break; ++ case SATP_MODE_57: ++ up = 1UL << 56; ++ break; ++ default: ++ return false; ++ } ++ ++ return (va < up) || (va >= (ULONG_MAX - up + 1)); ++} ++ + /* + * There is a simple way to determine if 4-level is supported by the + * underlying hardware: establish 1:1 mapping in 4-level page table mode +@@ -887,6 +908,9 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + set_satp_mode_pmd + PMD_SIZE, + PMD_SIZE, PAGE_KERNEL_EXEC); + retry: ++ if (!is_vaddr_valid(set_satp_mode_pmd)) ++ goto out; ++ + create_pgd_mapping(early_pg_dir, + set_satp_mode_pmd, + pgtable_l5_enabled ? +@@ -909,6 +933,7 @@ static __init void set_satp_mode(uintptr_t dtb_pa) + disable_pgtable_l4(); + } + ++out: + memset(early_pg_dir, 0, PAGE_SIZE); + memset(early_p4d, 0, PAGE_SIZE); + memset(early_pud, 0, PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-7.0/rtc-max77686-convert-to-i2c_new_ancillary_device.patch b/queue-7.0/rtc-max77686-convert-to-i2c_new_ancillary_device.patch new file mode 100644 index 0000000000..f6d095a185 --- /dev/null +++ b/queue-7.0/rtc-max77686-convert-to-i2c_new_ancillary_device.patch @@ -0,0 +1,67 @@ +From 5e673b1f3b766b22d455feadd14e4455739801a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 10:52:58 +0200 +Subject: rtc: max77686: convert to i2c_new_ancillary_device + +From: Svyatoslav Ryhel + +[ Upstream commit 0d65a9d93d870ef3d13642f88d0e6d562790c96d ] + +Convert RTC I2C device creation from devm_i2c_new_dummy_device() to +i2c_new_ancillary_device() to enable the use of a device tree-specified +RTC address instead of a hardcoded value. If the device tree does not +provide an address, use hardcoded values as a fallback. + +This addresses an issue with the MAX77663 PMIC, which can have the RTC at +different I2C positions (either 0x48, like the MAX77714, or 0x68, like +the MAX77620). The MAX77620 value is used as the default. The I2C position +of the MAX77663 is factory-set and cannot be detected from the chip +itself. + +Signed-off-by: Svyatoslav Ryhel +Link: https://patch.msgid.link/20260312085258.11431-6-clamor95@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-max77686.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c +index 69ea3ce75b5a5..3cdfd78a07ccc 100644 +--- a/drivers/rtc/rtc-max77686.c ++++ b/drivers/rtc/rtc-max77686.c +@@ -686,6 +686,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) + return ret; + } + ++static void max77686_rtc_release_dev(void *client) ++{ ++ i2c_unregister_device(client); ++} ++ + static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) + { + struct device *parent = info->dev->parent; +@@ -713,12 +718,17 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) + goto add_rtc_irq; + } + +- client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter, +- info->drv_data->rtc_i2c_addr); ++ client = i2c_new_ancillary_device(parent_i2c, "rtc", ++ info->drv_data->rtc_i2c_addr); + if (IS_ERR(client)) + return dev_err_probe(info->dev, PTR_ERR(client), + "Failed to allocate I2C device for RTC\n"); + ++ ret = devm_add_action_or_reset(info->dev, max77686_rtc_release_dev, ++ client); ++ if (ret) ++ return ret; ++ + info->rtc_regmap = devm_regmap_init_i2c(client, + info->drv_data->regmap_config); + if (IS_ERR(info->rtc_regmap)) +-- +2.53.0 + diff --git a/queue-7.0/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch b/queue-7.0/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch new file mode 100644 index 0000000000..78e007609d --- /dev/null +++ b/queue-7.0/rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch @@ -0,0 +1,50 @@ +From ff8a6b57fea1e9004b99635ba0419d46027f29e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 16:47:40 +0530 +Subject: rtc: ti-k3: Add support to resume from IO DDR low power mode + +From: Akashdeep Kaur + +[ Upstream commit 0e9b12ee74c57617bb362deb3c82e35fe49694b5 ] + +Restore the RTC HW context which may be lost when system enters +certain low power mode (IO+DDR mode). +Check if the RTC registers are locked which would indicate loss of +context (reset) and restore the context as needed. + +Signed-off-by: Akashdeep Kaur +Reviewed-by: Vignesh Raghavendra +Link: https://patch.msgid.link/20260313111740.1492519-1-a-kaur@ti.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-ti-k3.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c +index ec759d8f7023c..e801f5b9d7574 100644 +--- a/drivers/rtc/rtc-ti-k3.c ++++ b/drivers/rtc/rtc-ti-k3.c +@@ -640,10 +640,18 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) + static int __maybe_unused ti_k3_rtc_resume(struct device *dev) + { + struct ti_k3_rtc *priv = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (k3rtc_check_unlocked(priv)) { ++ /* RTC locked implies low power mode exit where RTC loses context */ ++ ret = k3rtc_configure(dev); ++ if (ret) ++ return ret; ++ } + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); +- return 0; ++ return ret; + } + + static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume); +-- +2.53.0 + diff --git a/queue-7.0/rtla-handle-pthread_create-failure-properly.patch b/queue-7.0/rtla-handle-pthread_create-failure-properly.patch new file mode 100644 index 0000000000..24af4925f8 --- /dev/null +++ b/queue-7.0/rtla-handle-pthread_create-failure-properly.patch @@ -0,0 +1,46 @@ +From 6e77fa27d6ce69012973d8c50f649c78cdbbc091 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:22 -0300 +Subject: rtla: Handle pthread_create() failure properly + +From: Wander Lairson Costa + +[ Upstream commit d847188bb92b14518a04d7542e44928a22060847 ] + +Add proper error handling when pthread_create() fails to create the +timerlat user-space dispatcher thread. Previously, the code only logged +an error message but continued execution, which could lead to undefined +behavior when the tool later expects the thread to be running. + +When pthread_create() returns an error, the function now jumps to the +out_trace error path to properly clean up resources and exit. This +ensures consistent error handling and prevents the tool from running +in an invalid state without the required user-space thread. + +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-10-wander@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/common.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c +index 839c78c065e12..368476254ec6a 100644 +--- a/tools/tracing/rtla/src/common.c ++++ b/tools/tracing/rtla/src/common.c +@@ -313,8 +313,10 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[]) + params->user.cgroup_name = params->cgroup_name; + + retval = pthread_create(&user_thread, NULL, timerlat_u_dispatcher, ¶ms->user); +- if (retval) ++ if (retval) { + err_msg("Error creating timerlat user-space threads\n"); ++ goto out_trace; ++ } + } + + retval = ops->enable(tool); +-- +2.53.0 + diff --git a/queue-7.0/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch b/queue-7.0/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch new file mode 100644 index 0000000000..2b0af316b8 --- /dev/null +++ b/queue-7.0/s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch @@ -0,0 +1,73 @@ +From 4ec1fcb2fe8af4aedd4ebc687c8f752eae111767 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:10:06 +0100 +Subject: s390/bpf: Do not increment tailcall count when prog is NULL + +From: Ilya Leoshkevich + +[ Upstream commit e4094d56c5592dd90aa619f9480265b0689ed3d9 ] + +Currently tail calling a non-existent prog results in tailcall count +increment. This is what the interpreter is doing, but this is clearly +wrong, so replace load-and-increment and compare-and-jump with load +and compare-and-jump, conditionally followed by increment and store. + +Reported-by: Hari Bathini +Signed-off-by: Ilya Leoshkevich +Link: https://lore.kernel.org/r/20260217161058.101346-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index 10ab247e1994c..c2d761c6af66f 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -1871,20 +1871,21 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + jit->prg); + + /* +- * if (tail_call_cnt++ >= MAX_TAIL_CALL_CNT) ++ * if (tail_call_cnt >= MAX_TAIL_CALL_CNT) + * goto out; ++ * ++ * tail_call_cnt is read into %w0, which needs to be preserved ++ * until it's incremented and flushed. + */ + + off = jit->frame_off + + offsetof(struct prog_frame, tail_call_cnt); +- /* lhi %w0,1 */ +- EMIT4_IMM(0xa7080000, REG_W0, 1); +- /* laal %w1,%w0,off(%r15) */ +- EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); +- /* clij %w1,MAX_TAIL_CALL_CNT-1,0x2,out */ ++ /* ly %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0058, REG_W0, REG_0, REG_15, off); ++ /* clij %w0,MAX_TAIL_CALL_CNT,0xa,out */ + patch_2_clij = jit->prg; +- EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT - 1, +- 2, jit->prg); ++ EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W0, MAX_TAIL_CALL_CNT, ++ 0xa, jit->prg); + + /* + * prog = array->ptrs[index]; +@@ -1903,6 +1904,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + patch_3_brc = jit->prg; + EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); + ++ /* tail_call_cnt++; */ ++ /* ahi %w0,1 */ ++ EMIT4_IMM(0xa70a0000, REG_W0, 1); ++ /* sty %w0,off(%r15) */ ++ EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, REG_0, REG_15, off); ++ + /* + * Restore registers before calling function + */ +-- +2.53.0 + diff --git a/queue-7.0/sched-eevdf-clear-buddies-for-preempt_short.patch b/queue-7.0/sched-eevdf-clear-buddies-for-preempt_short.patch new file mode 100644 index 0000000000..de8d9a92f7 --- /dev/null +++ b/queue-7.0/sched-eevdf-clear-buddies-for-preempt_short.patch @@ -0,0 +1,66 @@ +From 0c5a2ff747524a199021df67d7b20fdeaff906a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 15:23:21 +0200 +Subject: sched/eevdf: Clear buddies for preempt_short + +From: Vincent Guittot + +[ Upstream commit 78cde54ea5f03398f1cf6656de2472068f6da966 ] + +next buddy should not prevent shorter slice preemption. Don't take buddy +into account when checking if shorter slice entity can preempt and clear it +if the entity with a shorter slice can preempt current. + +Test on snapdragon rb5: +hackbench -T -p -l 16000000 -g 2 1> /dev/null & +hackbench runs in cgroup /test-A +cyclictest -t 1 -i 2777 -D 63 --policy=fair --mlock -h 20000 -q +cyclictest runs in cgroup /test-B + + tip/sched/core tip/sched/core +this patch +cyclictest slice (ms) (default)2.8 8 8 +hackbench slice (ms) (default)2.8 20 20 +Total Samples | 22679 22595 22686 +Average (us) | 84 94(-12%) 59( 37%) +Median (P50) (us) | 56 56( 0%) 56( 0%) +90th Percentile (us) | 64 65(- 2%) 63( 3%) +99th Percentile (us) | 1047 1273(-22%) 74( 94%) +99.9th Percentile (us) | 2431 4751(-95%) 663( 86%) +Maximum (us) | 4694 8655(-84%) 3934( 55%) + +Signed-off-by: Vincent Guittot +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260410132321.2897789-1-vincent.guittot@linaro.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index c5fcb24711d97..24f361f8fa6a9 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1024,7 +1024,7 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + /* + * Picking the ->next buddy will affect latency but not fairness. + */ +- if (sched_feat(PICK_BUDDY) && ++ if (sched_feat(PICK_BUDDY) && protect && + cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) { + /* ->next will never be delayed */ + WARN_ON_ONCE(cfs_rq->next->sched_delayed); +@@ -8934,8 +8934,10 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f + return; + + preempt: +- if (preempt_action == PREEMPT_WAKEUP_SHORT) ++ if (preempt_action == PREEMPT_WAKEUP_SHORT) { + cancel_protect_slice(se); ++ clear_buddies(cfs_rq, se); ++ } + + resched_curr_lazy(rq); + } +-- +2.53.0 + diff --git a/queue-7.0/sched-fair-make-hrtick-resched-hard.patch b/queue-7.0/sched-fair-make-hrtick-resched-hard.patch new file mode 100644 index 0000000000..867ca9231d --- /dev/null +++ b/queue-7.0/sched-fair-make-hrtick-resched-hard.patch @@ -0,0 +1,40 @@ +From e0812369cb0e8bae97908315c457af1e4b114f83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:27 +0100 +Subject: sched/fair: Make hrtick resched hard + +From: Peter Zijlstra (Intel) + +[ Upstream commit 5d88e424ec1b3ea7f552bd14d932f510146c45c7 ] + +Since the tick causes hard preemption, the hrtick should too. + +Letting the hrtick do lazy preemption completely defeats the purpose, since +it will then still be delayed until a old tick and be dependent on +CONFIG_HZ. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163428.933894105@kernel.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 3bce48ad0bc5a..c5fcb24711d97 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -5595,7 +5595,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + * validating it and just reschedule. + */ + if (queued) { +- resched_curr_lazy(rq_of(cfs_rq)); ++ resched_curr(rq_of(cfs_rq)); + return; + } + #endif +-- +2.53.0 + diff --git a/queue-7.0/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch b/queue-7.0/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch new file mode 100644 index 0000000000..264c216b12 --- /dev/null +++ b/queue-7.0/sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch @@ -0,0 +1,101 @@ +From 3409b2a85af70d28d189bfb80606236a3eaa90a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 19:59:29 +0800 +Subject: sched: Fix incorrect schedstats for rt and dl thread + +From: Dengjun Su + +[ Upstream commit c0e1832ba6dad7057acf3f485a87e0adccc23141 ] + +For RT and DL thread, only 'set_next_task_(rt/dl)' will call +'update_stats_wait_end_(rt/dl)' to update schedstats information. +However, during the migration process, +'update_stats_wait_start_(rt/dl)' will be called twice, which +will cause the values of wait_max and wait_sum to be incorrect. +The specific output as follows: +$ cat /proc/6046/task/6046/sched | grep wait +wait_start : 0.000000 +wait_max : 496717.080029 +wait_sum : 7921540.776553 + +A complete schedstats information update flow of migrate should be +__update_stats_wait_start() [enter queue A, stage 1] -> +__update_stats_wait_end() [leave queue A, stage 2] -> +__update_stats_wait_start() [enter queue B, stage 3] -> +__update_stats_wait_end() [start running on queue B, stage 4] + + Stage 1: prev_wait_start is 0, and in the end, wait_start records the + time of entering the queue. + Stage 2: task_on_rq_migrating(p) is true, and wait_start is updated to + the waiting time on queue A. + Stage 3: prev_wait_start is the waiting time on queue A, wait_start is + the time of entering queue B, and wait_start is expected to be greater + than prev_wait_start. Under this condition, wait_start is updated to + (the moment of entering queue B) - (the waiting time on queue A). + Stage 4: the final wait time = (time when starting to run on queue B) + - (time of entering queue B) + (waiting time on queue A) = waiting + time on queue B + waiting time on queue A. + +The current problem is that stage 2 does not call __update_stats_wait_end +to update wait_start, which causes the final computed wait time = waiting +time on queue B + the moment of entering queue A, leading to incorrect +wait_max and wait_sum. + +Add 'update_stats_wait_end_(rt/dl)' in 'update_stats_dequeue_(rt/dl)' to +update schedstats information when dequeue_task. + +Signed-off-by: Dengjun Su +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260204115959.3183567-1-dengjun.su@mediatek.com +Signed-off-by: Sasha Levin +--- + kernel/sched/deadline.c | 4 ++++ + kernel/sched/rt.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index af7c1e88e46e7..23bd95cb25b2a 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -2142,10 +2142,14 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, + int flags) + { + struct task_struct *p = dl_task_of(dl_se); ++ struct rq *rq = rq_of_dl_rq(dl_rq); + + if (!schedstat_enabled()) + return; + ++ if (p != rq->curr) ++ update_stats_wait_end_dl(dl_rq, dl_se); ++ + if ((flags & DEQUEUE_SLEEP)) { + unsigned int state; + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 0cbee031858a5..893e54dab13ef 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1302,13 +1302,18 @@ update_stats_dequeue_rt(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, + int flags) + { + struct task_struct *p = NULL; ++ struct rq *rq = rq_of_rt_rq(rt_rq); + + if (!schedstat_enabled()) + return; + +- if (rt_entity_is_task(rt_se)) ++ if (rt_entity_is_task(rt_se)) { + p = rt_task_of(rt_se); + ++ if (p != rq->curr) ++ update_stats_wait_end_rt(rt_rq, rt_se); ++ } ++ + if ((flags & DEQUEUE_SLEEP) && p) { + unsigned int state; + +-- +2.53.0 + diff --git a/queue-7.0/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch b/queue-7.0/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch new file mode 100644 index 0000000000..f1e27c8a11 --- /dev/null +++ b/queue-7.0/scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch @@ -0,0 +1,74 @@ +From ebe965270ff880e486d8a5c8000cc7d8e7bbea2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:57:39 +0100 +Subject: scsi: esas2r: Fix __printf annotation on esas2r_log_master() + +From: Arnd Bergmann + +[ Upstream commit 67557418905b103eaa7bacf81999be83accda334 ] + +clang-22 started warning about functions that take printf format +strings: + +drivers/scsi/esas2r/esas2r_log.c:160:50: error: diagnostic behavior may be improved by adding the 'format(printf, 3, 0)' attribute to the declaration of 'esas2r_log_master' [-Werror,-Wmissing-format-attribute] + 121 | retval = vsnprintf(buffer, buflen, format, args); + | ^ +drivers/scsi/esas2r/esas2r_log.c:121:12: note: 'esas2r_log_master' declared here + 121 | static int esas2r_log_master(const long level, + | ^ + +The warning already got silenced for gcc but not clang in the past. +Rather than modify that hack to turn it off for both, just add the +attribute as suggested and remove the pragma again. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260323100027.1975646-1-arnd@kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/esas2r/esas2r_log.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c +index d6c87a0bae098..46f489b2263cb 100644 +--- a/drivers/scsi/esas2r/esas2r_log.c ++++ b/drivers/scsi/esas2r/esas2r_log.c +@@ -101,11 +101,6 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + } + } + +-#pragma GCC diagnostic push +-#ifndef __clang__ +-#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +-#endif +- + /* + * the master logging function. this function will format the message as + * outlined by the formatting string, the input device information and the +@@ -118,10 +113,9 @@ static const char *translate_esas2r_event_level_to_kernel(const long level) + * + * @return 0 on success, or -1 if an error occurred. + */ +-static int esas2r_log_master(const long level, +- const struct device *dev, +- const char *format, +- va_list args) ++static __printf(3, 0) ++int esas2r_log_master(const long level, const struct device *dev, ++ const char *format, va_list args) + { + if (level <= event_log_level) { + unsigned long flags = 0; +@@ -175,8 +169,6 @@ static int esas2r_log_master(const long level, + return 0; + } + +-#pragma GCC diagnostic pop +- + /* + * formats and logs a message to the system log. + * +-- +2.53.0 + diff --git a/queue-7.0/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch b/queue-7.0/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch new file mode 100644 index 0000000000..d399505457 --- /dev/null +++ b/queue-7.0/scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch @@ -0,0 +1,83 @@ +From 09abde1157969ac1bf9ddaf42315f3b022d501c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:59:27 -0700 +Subject: scsi: lpfc: Add PCI ID support for LPe42100 series adapters + +From: Justin Tee + +[ Upstream commit 49b9f31e52b2125125318cb60fe9f5e7fa9c6755 ] + +Update supported pci_device_id table to include the values for the G8 ASIC +Device ID utilized by LPe42100 series of adapters. The default reporting +string will be "LPe42100". + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260331205928.119833-10-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_hw.h | 3 ++- + drivers/scsi/lpfc/lpfc_ids.h | 4 +++- + drivers/scsi/lpfc/lpfc_init.c | 3 +++ + 3 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h +index b2e353590ebb5..6326f7353dd68 100644 +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * ++ * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * +@@ -1771,6 +1771,7 @@ struct lpfc_fdmi_reg_portattr { + #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 + #define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 + #define PCI_DEVICE_ID_LANCER_G7P_FC 0xf500 ++#define PCI_DEVICE_ID_LANCER_G8_FC 0xd300 + #define PCI_DEVICE_ID_SAT_SMB 0xf011 + #define PCI_DEVICE_ID_SAT_MID 0xf015 + #define PCI_DEVICE_ID_RFLY 0xf095 +diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h +index 0b1616e93cf47..a0a6e2d379b86 100644 +--- a/drivers/scsi/lpfc/lpfc_ids.h ++++ b/drivers/scsi/lpfc/lpfc_ids.h +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * ++ * Copyright (C) 2017-2026 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * +@@ -118,6 +118,8 @@ const struct pci_device_id lpfc_id_table[] = { + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7P_FC, + PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G8_FC, ++ PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index e9d9ac7da485b..f29e4b8fd02f4 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -2752,6 +2752,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) + case PCI_DEVICE_ID_LANCER_G7P_FC: + m = (typeof(m)){"LPe38000", "PCIe", "Fibre Channel Adapter"}; + break; ++ case PCI_DEVICE_ID_LANCER_G8_FC: ++ m = (typeof(m)){"LPe42100", "PCIe", "Fibre Channel Adapter"}; ++ break; + case PCI_DEVICE_ID_SKYHAWK: + case PCI_DEVICE_ID_SKYHAWK_VF: + oneConnect = 1; +-- +2.53.0 + diff --git a/queue-7.0/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch b/queue-7.0/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch new file mode 100644 index 0000000000..be5d57e81c --- /dev/null +++ b/queue-7.0/scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch @@ -0,0 +1,117 @@ +From a3e520af86546ccd6e3cc52c1ad347bde2703468 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:03 -0800 +Subject: scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in + lpfc_sli_abort_ring() + +From: Justin Tee + +[ Upstream commit 2da10bcaa58a389ca60f8e788180e0dca00739bc ] + +When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is +cleared but the phba->txcmplq_cnt is not reset to zero. This can +sometimes result in a phba->txcmplq_cnt that never reaches zero, which +hangs the cleanup process. + +Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also +ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_sli.c | 66 +++++++++++++----------------------- + 1 file changed, 24 insertions(+), 42 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 303523f754b86..ad5b0e60acc5a 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -4572,59 +4572,41 @@ void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { + LIST_HEAD(tx_completions); +- LIST_HEAD(txcmplq_completions); ++ spinlock_t *plock; /* for transmit queue access */ + struct lpfc_iocbq *iocb, *next_iocb; + int offline; + +- if (pring->ringno == LPFC_ELS_RING) { ++ if (phba->sli_rev >= LPFC_SLI_REV4) ++ plock = &pring->ring_lock; ++ else ++ plock = &phba->hbalock; ++ ++ if (pring->ringno == LPFC_ELS_RING) + lpfc_fabric_abort_hba(phba); +- } ++ + offline = pci_channel_offline(phba->pcidev); + +- /* Error everything on txq and txcmplq +- * First do the txq. +- */ +- if (phba->sli_rev >= LPFC_SLI_REV4) { +- spin_lock_irq(&pring->ring_lock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; ++ /* Cancel everything on txq */ ++ spin_lock_irq(plock); ++ list_splice_init(&pring->txq, &tx_completions); ++ pring->txq_cnt = 0; + +- if (offline) { +- list_splice_init(&pring->txcmplq, +- &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&pring->ring_lock); ++ if (offline) { ++ /* Cancel everything on txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; ++ list_splice_init(&pring->txcmplq, &tx_completions); ++ pring->txcmplq_cnt = 0; + } else { +- spin_lock_irq(&phba->hbalock); +- list_splice_init(&pring->txq, &tx_completions); +- pring->txq_cnt = 0; +- +- if (offline) { +- list_splice_init(&pring->txcmplq, &txcmplq_completions); +- } else { +- /* Next issue ABTS for everything on the txcmplq */ +- list_for_each_entry_safe(iocb, next_iocb, +- &pring->txcmplq, list) +- lpfc_sli_issue_abort_iotag(phba, pring, +- iocb, NULL); +- } +- spin_unlock_irq(&phba->hbalock); ++ /* Issue ABTS for everything on the txcmplq */ ++ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) ++ lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + } ++ spin_unlock_irq(plock); + +- if (offline) { +- /* Cancel all the IOCBs from the completions list */ +- lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, +- IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); +- } else { +- /* Make sure HBA is alive */ ++ if (!offline) + lpfc_issue_hb_tmo(phba); +- } ++ + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); +-- +2.53.0 + diff --git a/queue-7.0/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch b/queue-7.0/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch new file mode 100644 index 0000000000..6dc2425942 --- /dev/null +++ b/queue-7.0/scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch @@ -0,0 +1,40 @@ +From 1356b3c4236fa458ea3002de8482f36b3e05fe1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:30:01 -0800 +Subject: scsi: lpfc: Remove unnecessary ndlp kref get in + lpfc_check_nlp_post_devloss + +From: Justin Tee + +[ Upstream commit f6bfb8d149336661bb80e62980da9a45b920403c ] + +When NLP_IN_RECOV_POST_DEV_LOSS is set, the initial node reference +remains held while recovery is in progress. Taking a reference when +NLP_IN_RECOV_POST_DEV_LOSS is cleared results in an additional reference +being held. This causes an extra reference when cleaning up lpfc_vport +instances. Thus, remove the extraneous ndlp kref get in +lpfc_check_nlp_post_devloss. + +Signed-off-by: Justin Tee +Link: https://patch.msgid.link/20260212213008.149873-7-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/lpfc/lpfc_hbadisc.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 8aaf05d7bb0af..d42b911a0aee1 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -425,7 +425,6 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, + { + if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) { + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); +- lpfc_nlp_get(ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, + "8438 Devloss timeout reversed on DID x%x " + "refcnt %d ndlp %p flag x%lx " +-- +2.53.0 + diff --git a/queue-7.0/scsi-storvsc-handle-persistent_reserve_in-truncation.patch b/queue-7.0/scsi-storvsc-handle-persistent_reserve_in-truncation.patch new file mode 100644 index 0000000000..a94bd12479 --- /dev/null +++ b/queue-7.0/scsi-storvsc-handle-persistent_reserve_in-truncation.patch @@ -0,0 +1,96 @@ +From 56ed3c004fc17f7224381fcbd5982c20fb28511f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 09:53:44 +0800 +Subject: scsi: storvsc: Handle PERSISTENT_RESERVE_IN truncation for Hyper-V + vFC + +From: Li Tian + +[ Upstream commit 9cf351b289fb2be22491fa3964f99126db67aa08 ] + +The storvsc driver has become stricter in handling SRB status codes +returned by the Hyper-V host. When using Virtual Fibre Channel (vFC) +passthrough, the host may return SRB_STATUS_DATA_OVERRUN for +PERSISTENT_RESERVE_IN commands if the allocation length in the CDB does +not match the host's expected response size. + +Currently, this status is treated as a fatal error, propagating +Host_status=0x07 [DID_ERROR] to the SCSI mid-layer. This causes +userspace storage utilities (such as sg_persist) to fail with transport +errors, even when the host has actually returned the requested +reservation data in the buffer. + +Refactor the existing command-specific workarounds into a new helper +function, storvsc_host_mishandles_cmd(), and add PERSISTENT_RESERVE_IN +to the list of commands where SRB status errors should be suppressed for +vFC devices. This ensures that the SCSI mid-layer processes the returned +data buffer instead of terminating the command. + +Signed-off-by: Li Tian +Reviewed-by: Long Li +Reviewed-by: Laurence Oberman +Link: https://patch.msgid.link/20260406015344.12566-1-litian@redhat.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index ae1abab97835b..6977ca8a06582 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1131,6 +1131,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, + kfree(payload); + } + ++/* ++ * The current SCSI handling on the host side does not correctly handle: ++ * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, ++ * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. ++ */ ++static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) ++{ ++ switch (opcode) { ++ case INQUIRY: ++ case MODE_SENSE: ++ case MODE_SENSE_10: ++ return true; ++ case MAINTENANCE_IN: ++ case PERSISTENT_RESERVE_IN: ++ return hv_dev_is_fc(device); ++ default: ++ return false; ++ } ++} ++ + static void storvsc_on_io_completion(struct storvsc_device *stor_device, + struct vstor_packet *vstor_packet, + struct storvsc_cmd_request *request) +@@ -1141,22 +1161,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, + stor_pkt = &request->vstor_packet; + + /* +- * The current SCSI handling on the host side does +- * not correctly handle: +- * INQUIRY command with page code parameter set to 0x80 +- * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c +- * MAINTENANCE_IN is not supported by HyperV FC passthrough +- * + * Setup srb and scsi status so this won't be fatal. + * We do this so we can distinguish truly fatal failues + * (srb status == 0x4) and off-line the device in that case. + */ + +- if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || +- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || +- (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && +- hv_dev_is_fc(device))) { ++ if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { + vstor_packet->vm_srb.scsi_status = 0; + vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; + } +-- +2.53.0 + diff --git a/queue-7.0/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch b/queue-7.0/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch new file mode 100644 index 0000000000..3b35f44836 --- /dev/null +++ b/queue-7.0/scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch @@ -0,0 +1,38 @@ +From 7dcb80164fe43c430105af356a4cd7cecb933e62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 13:41:34 -0500 +Subject: scsi: ufs: core: Disable timestamp for Kioxia THGJFJT0E25BAIP + +From: Aaron Kling + +[ Upstream commit e423f1c7195645e18945fba0bd8f0a32e39286e7 ] + +Kioxia has another product that does not support the qTimestamp +attribute. + +Signed-off-by: Aaron Kling +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260403-thgjfjt0e25baip-no-timestamp-v1-1-1ddb34225133@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/core/ufshcd.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 9ceb6d6d479d0..9b77639f04535 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -315,6 +315,9 @@ static const struct ufs_dev_quirk ufs_fixups[] = { + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGLF2G9D8KBADG", + .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE }, ++ { .wmanufacturerid = UFS_VENDOR_TOSHIBA, ++ .model = "THGJFJT0E25BAIP", ++ .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = "THGJFJT1E45BATP", + .quirk = UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT }, +-- +2.53.0 + diff --git a/queue-7.0/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch b/queue-7.0/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch new file mode 100644 index 0000000000..22c348b8da --- /dev/null +++ b/queue-7.0/scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch @@ -0,0 +1,35 @@ +From 49f01029952b6986715c993f93057209c1736279 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 10:58:15 +0200 +Subject: scsi: ufs: ufs-pci: Add support for Intel Nova Lake + +From: Adrian Hunter + +[ Upstream commit 096cd6b7adf21791827a045d464242d93a6fd54e ] + +Add PCI ID to support Intel Nova Lake, same as Intel Meteor Lake (MTL). + +Signed-off-by: Adrian Hunter +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260309085815.55216-1-adrian.hunter@intel.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/ufs/host/ufshcd-pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c +index 5f65dfad1a71a..63f6b36b912fc 100644 +--- a/drivers/ufs/host/ufshcd-pci.c ++++ b/drivers/ufs/host/ufshcd-pci.c +@@ -695,6 +695,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { + { PCI_VDEVICE(INTEL, 0x7747), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0xE447), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4D47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, ++ { PCI_VDEVICE(INTEL, 0xD335), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { } /* terminate list */ + }; + +-- +2.53.0 + diff --git a/queue-7.0/scsi-virtio_scsi-move-init_work-calls-to-virtscsi_pr.patch b/queue-7.0/scsi-virtio_scsi-move-init_work-calls-to-virtscsi_pr.patch new file mode 100644 index 0000000000..c6e4a33342 --- /dev/null +++ b/queue-7.0/scsi-virtio_scsi-move-init_work-calls-to-virtscsi_pr.patch @@ -0,0 +1,84 @@ +From c1d4a137c12f64d26605a437ae0cff8c30f2ffad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:08:56 +0100 +Subject: scsi: virtio_scsi: Move INIT_WORK calls to virtscsi_probe() + +From: Joshua Daley + +[ Upstream commit da3159a3b3fdc05c6bdba2fd4f4802a6718d879a ] + +The last step of virtscsi_handle_event() is to call +virtscsi_kick_event(), which calls INIT_WORK on its own work +item. INIT_WORK resets the work item's data bits to 0. + +If this occurs while the work item is being flushed by +cancel_work_sync(), then kernel/workqueue.c/work_offqd_enable triggers a +kernel warning, as it expects the "disable" bit to be 1: + +[ 21.450115] workqueue: work disable count underflowed +[ 21.450117] WARNING: CPU: 1 PID: 56 at kernel/workqueue.c:4328 enable_work+0x10a/0x120 +... +[ 21.450171] Call Trace: +[ 21.450173] [<000003db2e5bdc3e>] enable_work+0x10e/0x120 +[ 21.450176] ([<000003db2e5bdc3a>] enable_work+0x10a/0x120) +[ 21.450178] [<000003db2e5bdd86>] cancel_work_sync+0x86/0xa0 +[ 21.450181] [<000003daae97d9e4>] virtscsi_remove+0xb4/0xd0 [virtio_scsi] +[ 21.450184] [<000003db2ef3b5ca>] virtio_dev_remove+0x6a/0xd0 +[ 21.450186] [<000003db2ef9106c>] device_release_driver_internal+0x1ac/0x260 +[ 21.450190] [<000003db2ef8edc8>] bus_remove_device+0xf8/0x190 +[ 21.450192] [<000003db2ef88d72>] device_del+0x142/0x340 +[ 21.450194] [<000003db2ef88fa0>] device_unregister+0x30/0xa0 +[ 21.450196] [<000003db2ef3b2fa>] unregister_virtio_device+0x2a/0x40 + +This warning may occur if a controller is detached immediately following +a disk detach. + +Move the INIT_WORK call to prevent this. Don't re-init event list work +items in virtscsi_kick_event(), init them only once in virtscsi_probe() +instead. + +Signed-off-by: Joshua Daley +Reviewed-by: Stefan Hajnoczi +Link: https://patch.msgid.link/20260325180857.3675854-2-jdaley@linux.ibm.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/virtio_scsi.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c +index 0ed8558dad724..64b6c942f5720 100644 +--- a/drivers/scsi/virtio_scsi.c ++++ b/drivers/scsi/virtio_scsi.c +@@ -233,7 +233,6 @@ static void virtscsi_ctrl_done(struct virtqueue *vq) + virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free); + }; + +-static void virtscsi_handle_event(struct work_struct *work); + + static int virtscsi_kick_event(struct virtio_scsi *vscsi, + struct virtio_scsi_event_node *event_node) +@@ -242,7 +241,6 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi, + struct scatterlist sg; + unsigned long flags; + +- INIT_WORK(&event_node->work, virtscsi_handle_event); + sg_init_one(&sg, event_node->event, sizeof(struct virtio_scsi_event)); + + spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); +@@ -984,8 +982,11 @@ static int virtscsi_probe(struct virtio_device *vdev) + + virtio_device_ready(vdev); + +- if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) ++ if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { ++ for (int i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) ++ INIT_WORK(&vscsi->event_list[i].work, virtscsi_handle_event); + virtscsi_kick_event_all(vscsi); ++ } + + scsi_scan_host(shost); + return 0; +-- +2.53.0 + diff --git a/queue-7.0/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch b/queue-7.0/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch new file mode 100644 index 0000000000..b4de24b5a7 --- /dev/null +++ b/queue-7.0/selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch @@ -0,0 +1,69 @@ +From 76aebf42213ad7155e82df66536b9aab1e7db27f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:20 +0800 +Subject: selftests: fib_nexthops: test stale has_v4 on nexthop replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiayuan Chen + +[ Upstream commit 104f082f5ed6d19c5d85ca905ccd4e4d01aef66e ] + +Add test cases that exercise the scenario where an IPv6 nexthop is +replaced with an IPv4 nexthop while being part of a group. The group's +has_v4 flag must be updated so that subsequent IPv6 route additions are +properly rejected. + +Two cases are covered: + 1. Gateway nexthop replaced across families with an existing IPv6 + route on the group (rejected by fib6_check_nh_list). + 2. Blackhole nexthop replaced across families with no existing IPv6 + route on the group (fib6_check_nh_list returns early) — this is + the path that triggers a NULL ptr deref without the kernel fix. + +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/net/fib_nexthops.sh | 22 +++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh +index 6eb7f95e70e15..ac868a7316946 100755 +--- a/tools/testing/selftests/net/fib_nexthops.sh ++++ b/tools/testing/selftests/net/fib_nexthops.sh +@@ -1209,6 +1209,28 @@ ipv6_fcnal_runtime() + run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124" + log_test $? 0 "IPv6 route using a group after replacing v4 gateways" + ++ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4 ++ # for all groups using it, preventing IPv6 routes from referencing the ++ # group after the replace. ++ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1" ++ run_cmd "$IP nexthop add id 125 group 89" ++ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1" ++ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4" ++ ++ # Same scenario but with a blackhole nexthop: the group has no IPv6 ++ # routes yet when the replace happens, so fib6_check_nh_list returns ++ # early without checking. has_v4 must still be updated to block ++ # subsequent IPv6 route additions. ++ run_cmd "$IP nexthop flush >/dev/null 2>&1" ++ run_cmd "$IP -6 nexthop add id 90 blackhole" ++ run_cmd "$IP nexthop add id 125 group 90" ++ run_cmd "$IP nexthop replace id 90 blackhole" ++ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125" ++ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole" ++ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT" ++ log_test $? 2 "Ping unreachable after rejected route" ++ + $IP nexthop flush >/dev/null 2>&1 + + # +-- +2.53.0 + diff --git a/queue-7.0/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch b/queue-7.0/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch new file mode 100644 index 0000000000..63c0f24da5 --- /dev/null +++ b/queue-7.0/selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch @@ -0,0 +1,61 @@ +From 2469715b6ae178f84a3a868788668698aa173bfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 18:19:40 +0800 +Subject: selftests: ublk: cap nthreads to kernel's actual nr_hw_queues + +From: Ming Lei + +[ Upstream commit 87d0740b7c4cc847be1b6f307ab6d8547cb1a726 ] + +dev->nthreads is derived from the user-requested queue count before the +ADD command, but the kernel may reduce nr_hw_queues (capped to +nr_cpu_ids). When the VM has fewer CPUs than requested queues, the +daemon creates more handler threads than there are kernel queues. + +In non-batch mode, the extra threads access uninitialized queues +(q_depth=0), submit zero io_uring SQEs, and block forever in +io_cqring_wait. In batch mode, the extra threads cause similar hangs +during device removal. + +In both cases, the stuck threads prevent the daemon from closing the +char device, holding the last ublk_device reference and causing +ublk_ctrl_del_dev() to hang in wait_event_interruptible(). + +Fix by capping dev->nthreads to the kernel-returned nr_hw_queues after +the ADD command completes. per_io_tasks mode is excluded because threads +interleave across all queues, so nthreads > nr_hw_queues is valid. + +Fixes: abe54c160346 ("selftests: ublk: kublk: decouple ublk_queues from ublk server threads") +Signed-off-by: Ming Lei +Link: https://patch.msgid.link/20260513101941.1373998-1-tom.leiming@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/ublk/kublk.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c +index e1c3b3c55e565..c40aa7952b6eb 100644 +--- a/tools/testing/selftests/ublk/kublk.c ++++ b/tools/testing/selftests/ublk/kublk.c +@@ -1395,6 +1395,17 @@ static int __cmd_dev_add(const struct dev_ctx *ctx) + goto fail; + } + ++ /* ++ * The kernel may reduce nr_hw_queues (e.g. capped to nr_cpu_ids). ++ * Cap nthreads to the actual queue count to avoid creating extra ++ * handler threads that will hang during device removal. ++ * ++ * per_io_tasks mode is excluded: threads interleave across all ++ * queues so nthreads > nr_hw_queues is valid and intentional. ++ */ ++ if (!ctx->per_io_tasks && dev->nthreads > info->nr_hw_queues) ++ dev->nthreads = info->nr_hw_queues; ++ + ret = ublk_start_daemon(ctx, dev); + ublk_dbg(UBLK_DBG_DEV, "%s: daemon exit %d\n", __func__, ret); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-7.0/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch b/queue-7.0/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch new file mode 100644 index 0000000000..7c4ddca05a --- /dev/null +++ b/queue-7.0/serial-qcom-geni-fix-rts-behavior-with-flow-control.patch @@ -0,0 +1,80 @@ +From f5aec51b63046ecdc4c77da0c9c61db8ece40597 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:11:55 +0530 +Subject: serial: qcom-geni: Fix RTS behavior with flow control + +From: Anup Kulkarni + +[ Upstream commit 0b1837c04d2335ec50b9a55b0282dcde7bc12439 ] + +When userspace enables flow control (CRTSCTS), the driver +deasserts RTS even when the receive buffer has space. This prevents the +peer device from transmitting, causing communication to stall. + +The root cause is that the driver unconditionally uses manual RTS control +regardless of flow control mode. When CRTSCTS is set, the hardware should +automatically manage RTS based on buffer status, but the driver overrides +this by setting manual control. + +Fix this by introducing port->manual_flow flag. In set_termios(), disable +manual flow when CRTSCTS is set. In set_mctrl(), only assert +SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and +disabling hardware flow control with stty. + +Signed-off-by: Anup Kulkarni +Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/qcom_geni_serial.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index e6b0a55f0cfb2..9854bb2406e3f 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -146,6 +146,7 @@ struct qcom_geni_serial_port { + int wakeup_irq; + bool rx_tx_swap; + bool cts_rts_swap; ++ bool manual_flow; + + struct qcom_geni_private_data private_data; + const struct qcom_geni_device_data *dev_data; +@@ -250,7 +251,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, + if (mctrl & TIOCM_LOOP) + port->loopback = RX_TX_CTS_RTS_SORTED; + +- if (!(mctrl & TIOCM_RTS) && !uport->suspended) ++ if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) + uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + } +@@ -1401,11 +1402,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, + else + stop_bit_len = TX_STOP_BIT_LEN_1; + +- /* flow control, clear the CTS_MASK bit if using flow control. */ +- if (termios->c_cflag & CRTSCTS) ++ /* Configure flow control based on CRTSCTS flag. ++ * When CRTSCTS is set, use HW/auto flow control mode, where HW ++ * controls the RTS/CTS pin based FIFO state. ++ * When CRTSCTS is clear, the CTS pin value is ignored for TX ++ * path and RTS pin can be set/cleared using registers, for RX ++ * path. ++ */ ++ ++ if (termios->c_cflag & CRTSCTS) { + tx_trans_cfg &= ~UART_CTS_MASK; +- else ++ port->manual_flow = false; ++ } else { + tx_trans_cfg |= UART_CTS_MASK; ++ port->manual_flow = true; ++ } + + if (baud) { + uart_update_timeout(uport, termios->c_cflag, baud); +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series new file mode 100644 index 0000000000..e242ac9a47 --- /dev/null +++ b/queue-7.0/series @@ -0,0 +1,508 @@ +kho-skip-kho-for-crash-kernel.patch +mm-memfd_luo-report-error-when-restoring-a-folio-fai.patch +hid-intel-thc-hid-intel-quickspi-fix-some-error-code.patch +hid-uclogic-fix-regression-of-input-name-assignment.patch +riscv-errata-fix-bitwise-vs-logical-and-in-mips-erra.patch +riscv-fix-register-corruption-from-uninitialized-cre.patch +riscv-mm-fixup-no5lvl-failure-when-vaddr-is-invalid.patch +kunit-config-enable-kunit_debugfs-by-default.patch +kunit-config-kunit_debugfs-should-depend-on-debug_fs.patch +alsa-hda-cs35l56-put-acpi-device-after-setting-compa.patch +alsa-hda-cs35l41-put-acpi-device-on-missing-physical.patch +btrfs-tracepoints-fix-sleep-while-in-atomic-context-.patch +netfilter-x_tables-allow-initial-table-replace-witho.patch +netfilter-x_tables-allocate-hook-ops-while-under-mut.patch +netfilter-x_tables-unregister-the-templates-first.patch +netfilter-x_tables-add-and-use-xt_unregister_table_p.patch +netfilter-x_tables-add-and-use-xtables_unregister_ta.patch +netfilter-ebtables-move-to-two-stage-removal-scheme.patch +netfilter-ebtables-close-dangling-table-module-init-.patch +netfilter-x_tables-close-dangling-table-module-init-.patch +netfilter-bridge-eb_tables-close-module-init-race.patch +netfilter-nf_conntrack_expect-restore-helper-propaga.patch +kprobes-skip-non-symbol-addresses-in-kprobe_add_ksym.patch +test_kprobes-clear-kprobes-between-test-runs.patch +tcp-fix-imbalanced-icsk_accept_queue-count.patch +net-napi-avoid-gro-timer-misfiring-at-end-of-busypol.patch +net-ethtool-fix-null-pointer-dereference-in-phy_repl.patch +net-shaper-reject-reparenting-of-existing-nodes.patch +idpf-fix-read_dev_clk_lock-spinlock-init-in-idpf_ptp.patch +ice-fix-setting-rss-vsi-hash-for-e830.patch +ice-fix-locking-in-ice_dcb_rebuild.patch +ice-dpll-fix-rclk-pin-state-get-for-e810.patch +ice-dpll-fix-misplaced-header-macros.patch +net-lan966x-avoid-unregistering-netdev-on-register-f.patch +net-ti-icssm-prueth-fix-eth_ports_node-leak-in-probe.patch +nfsd-fix-infinite-loop-in-layout-state-revocation.patch +iommu-fix-kdocs-of-pci_dev_reset_iommu_done.patch +fprobe-fix-unregister_fprobe-to-wait-for-rcu-grace-p.patch +fs-statmount-fix-slab-out-of-bounds-write-in-statmou.patch +fs-fix-return-in-jfs_mkdir-and-orangefs_mkdir.patch +irqchip-ath79-cpu-remove-unused-function.patch +fs-fix-forced-iversion-increment-on-lazytime-timesta.patch +ublk-reject-max_sectors-smaller-than-page_sectors-in.patch +nsfs-fix-wrong-error-code-returned-for-pidns-ioctls.patch +irq_work-fix-use-after-free-in-irq_work_single-on-pr.patch +nvme-fix-bio-leak-on-mapping-failure.patch +nvme-pci-fix-use-after-free-in-nvme_free_host_mem.patch +tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch +powerpc-82xx-fix-uninitialized-pointers-with-free-at.patch +powerpc-fix-dead-default-for-guest_state_buffer_test.patch +powerpc-hv-gpci-fix-preempt-count-leak-in-sysfs-show.patch +netfs-fix-cancellation-of-a-dio-and-single-read-subr.patch +netfs-fix-missing-locking-around-retry-adding-new-su.patch +netfs-fix-missing-barriers-when-accessing-stream-sub.patch +netfs-fix-netfs_read_to_pagecache-to-pause-on-subreq.patch +netfs-fix-potential-for-tearing-in-remote_i_size-and.patch +netfs-fix-zeropoint-update-where-i_size-remote_i_siz.patch +netfs-fix-vm_bug_on_folio-issue-in-netfs_write_begin.patch +netfs-fix-overrun-check-in-netfs_extract_user_iter.patch +netfs-fix-netfs_invalidate_folio-to-clear-dirty-bit-.patch +netfs-defer-the-emission-of-trace_netfs_folio.patch +netfs-fix-streaming-write-being-overwritten.patch +netfs-fix-potential-deadlock-in-write-through-mode.patch +netfs-fix-read-gaps-to-remove-netfs_folio-from-fille.patch +netfs-fix-write-streaming-disablement-if-fd-open-o_r.patch +netfs-fix-early-put-of-sink-folio-in-netfs_read_gaps.patch +netfs-fix-leak-of-request-in-netfs_write_begin-error.patch +netfs-fix-potential-uaf-in-netfs_unlock_abandoned_re.patch +netfs-fix-partial-invalidation-of-streaming-write-fo.patch +netfs-fix-folio-private-handling-in-netfs_perform_wr.patch +netfs-fix-netfs_read_folio-to-wait-on-writeback.patch +netfs-afs-fix-write-skipping-in-dir-link-writepages.patch +afs-fix-the-locking-used-by-afs_get_link.patch +net-ethernet-cortina-make-rx-skb-per-port.patch +net-ethernet-cortina-drop-half-assembled-skb.patch +net-ethernet-cortina-carry-over-frag-counter.patch +net-ethernet-cs89x0-remove-stale-config_mach_mx31ads.patch +net-shaper-flip-the-polarity-of-the-valid-flag.patch +net-shaper-fix-trivial-ordering-issue-in-net_shaper_.patch +net-shaper-reject-duplicate-leaves-in-group-request.patch +net-shaper-set-ret-to-enomem-when-genlmsg_new-fails-.patch +net-shaper-fix-undersized-reply-skb-allocation-in-gr.patch +net-shaper-reject-handle-ids-exceeding-internal-bit-.patch +net-shaper-enforce-singleton-netdev-scope-with-id-0.patch +net-shaper-reject-queue-scope-handle-with-missing-id.patch +block-don-t-overwrite-bip_vcnt-in-bio_integrity_copy.patch +block-recompute-nr_integrity_segments-in-blk_insert_.patch +hid-quirks-really-enable-the-intended-work-around-fo.patch +block-bio-integrity-fix-null-ptr-deref-in-bio_integr.patch +accel-qaic-add-overflow-check-to-remap_pfn_range-dur.patch +net-smc-avoid-null-deref-of-conn-lnk-in-smc_msg_even.patch +ethtool-fix-ethnl_bitmap32_not_zero-bit-interval-sem.patch +block-rename-struct-gendisk-zone_wplugs_lock-field.patch +block-allow-submitting-all-zone-writes-from-a-single.patch +block-fix-handling-of-dead-zone-write-plugs.patch +selftests-ublk-cap-nthreads-to-kernel-s-actual-nr_hw.patch +x86-mce-restore-mca-polling-interval-halving.patch +riscv-docs-fix-unmatched-quote-warning.patch +powerpc-time-remove-redundant-preempt_disable-enable.patch +net-smc-reject-chid-0-accept-that-matches-an-empty-i.patch +net-tls-fix-off-by-one-in-sg_chain-entry-count-for-w.patch +net-tls-prevent-chain-after-chain-in-plain-text-sg.patch +net-phy-dp83tc811-add-reading-of-abilities.patch +cifs-client-stage-smb3_reconfigure-updates-and-resto.patch +gcc-plugins-always-define-const_cast_gimple-and-cons.patch +x86-xen-fix-xen_e820_swap_entry_with_ram.patch +vfio-pci-check-bar-resources-before-exporting-a-dmab.patch +iommupt-directly-call-iommupt-s-unmap_range.patch +iommupt-avoid-rewalking-during-map.patch +iommu-fix-loss-of-errno-on-map-failure-for-classic-o.patch +iommu-fix-up-map-unmap-debugging-for-iommupt-domains.patch +iommu-handle-unmap-error-when-iommu_debug-is-enabled.patch +iommupt-check-for-missing-page_size-in-the-pgsize_bi.patch +iommupt-fix-the-end_index-calculation-in-__map_range.patch +alsa-scarlett2-add-missing-error-check-when-initiali.patch +alsa-hda-ca0132-disable-auto-detect-on-manual-output.patch +cachefiles-fix-error-return-when-vfs_mkdir-fails.patch +hwmon-lm90-stop-work-before-releasing-hwmon-device.patch +hwmon-lm90-add-lock-protection-to-lm90_alert.patch +exfat-use-truncate_inode_pages_final-at-evict_inode.patch +exfat-fix-bitwise-operation-having-different-size.patch +block-reject-zero-length-in-bio_add_page.patch +md-raid5-skip-2-failure-compute-when-other-disk-is-r.patch +nvmet-tcp-don-t-free-sq-on-authentication-success.patch +nvme-loop-do-not-cancel-i-o-and-admin-tagset-during-.patch +pstore-fix-ftrace-dump-when-ecc-is-enabled.patch +exfat-fix-s_maxbytes.patch +blk-iocost-fix-busy_level-reset-when-no-ios-complete.patch +io_uring-cancel-validate-opcode-for-ioring_async_can.patch +erofs-ensure-all-folios-are-managed-in-erofs_try_to_.patch +exfat-fix-incorrect-directory-checksum-after-rename-.patch +md-raid0-use-kvzalloc-kvfree-for-strip_zone-and-devl.patch +btrfs-don-t-allow-log-trees-to-consume-global-reserv.patch +btrfs-be-less-aggressive-with-metadata-overcommit-wh.patch +btrfs-zoned-cap-delayed-refs-metadata-reservation-to.patch +btrfs-avoid-gfp_atomic-allocations-in-qgroup-free-pa.patch +btrfs-use-btrfs_fs_update_uuid_tree_gen-flag-for-uui.patch +btrfs-replace-bug_on-with-error-return-in-cache_save.patch +btrfs-fix-silent-io-error-loss-in-encoded-writes-and.patch +affs-bound-hash_pos-before-table-lookup-in-affs_read.patch +hfsplus-fix-generic-642-failure.patch +gpio-tps65086-normalize-return-value-of-gpio_get.patch +gpio-da9055-normalize-return-value-of-gpio_get.patch +gpio-cgbc-normalize-return-value-of-gpio_get.patch +gpio-lp873x-normalize-return-value-of-gpio_get.patch +gpio-bd9571mwv-normalize-return-value-of-gpio_get.patch +gpio-viperboard-normalize-return-value-of-gpio_get.patch +acpi-processor-idle-add-missing-bounds-check-in-flat.patch +acpi-processor-idle-fix-null-pointer-dereference-in-.patch +sched-fix-incorrect-schedstats-for-rt-and-dl-thread.patch +sched-fair-make-hrtick-resched-hard.patch +perf-amd-ibs-limit-ldlat-l3missonly-dependency-to-ze.patch +perf-amd-ibs-avoid-race-between-event-add-and-nmi.patch +hexagon-uapi-fix-structure-alignment-attribute.patch +objtool-support-clang-rax-drap-sequence.patch +edac-amd64-add-support-for-family-19h-models-40h-4fh.patch +sched-eevdf-clear-buddies-for-preempt_short.patch +s390-bpf-do-not-increment-tailcall-count-when-prog-i.patch +bpf-do-not-increment-tailcall-count-when-prog-is-nul.patch +ipv6-discard-fragment-queue-earlier-if-there-is-malf.patch +net-ethernet-mtk_eth_soc-avoid-writing-to-esw-regist.patch +vmxnet3-suppress-page-allocation-warning-for-massive.patch +wifi-mac80211-set-band-information-only-for-non-mld-.patch +wifi-ath12k-set-up-mlo-after-ssr.patch +wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch +net-core-allow-netdev_upper_get_next_dev_rcu-from-bh.patch +gve-advertise-netif_f_gro_hw-instead-of-netif_f_lro.patch +gve-fix-sw-coalescing-when-hw-gro-is-used.patch +wifi-ath12k-fix-the-assignment-of-logical-link-index.patch +net-ethernet-ravb-disable-interrupts-when-closing-de.patch +net-mvneta-support-eprobe_defer-when-reading-mac-add.patch +net-sched-cls_u32-avoid-memcpy-false-positive-warnin.patch +tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch +hinic3-add-msg_send_lock-for-message-sending-concurr.patch +wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch +ipv4-validate-ipv4_devconf-attributes-properly.patch +wifi-rtw89-mac-remove-a-die-off-setting-for-rtl8852c.patch +powerpc-64s-fix-_hpage_chg_mask-to-include-_page_spe.patch +ppp-disconnect-channel-before-nullifying-pch-chan.patch +wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch +net-lan743x-fix-sgmii-detection-on-pci1xxxx-b0-durin.patch +wifi-mt76-mt76x02-wake-queues-after-reconfig.patch +wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch +wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch +wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch +wifi-mt76-mt7925-skip-scan-process-during-suspend.patch +wifi-mac80211-properly-handle-error-in-ieee80211_add.patch +bpf-propagate-kvmemdup_bpfptr-errors-from-bpf_prog_v.patch +wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch +wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch +wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch +wifi-mt76-flush-pending-tx-before-channel-switch.patch +wifi-mt76-avoid-to-set-ack-for-mcu-command-if-wait_r.patch +wifi-mt76-abort-roc-on-chanctx-changes.patch +wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch +wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch +wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch +wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch +wifi-iwlwifi-restrict-top-reset-to-some-devices.patch +wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch +wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch +net-qrtr-fix-endian-handling-of-confirm_rx-field.patch +wifi-rtw89-add-support-for-buffalo-wi-u3-2400xe2.patch +wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch +wifi-rtw89-add-support-for-tp-link-archer-tx50u.patch +wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch +wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch +wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch +net-sfp-add-quirk-for-zoerax-sfp-2.5g-t.patch +wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch +fddi-defxx-rate-limit-memory-allocation-errors.patch +net-mana-hardening-validate-adapter_mtu-from-mana_qu.patch +wifi-rtw89-add-support-for-elecom-wdc-xe2402tu3-b.patch +enic-add-v2-sr-iov-vf-device-id.patch +module-override-eexist-module-return.patch +m68k-fix-task-info-flags-handling-for-68000.patch +net-mlx5e-xsk-increase-size-for-chunk_size-param.patch +wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch +wifi-brcmfmac-of-defer-probe-for-mac-address.patch +wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch +net-hsr-emit-notification-for-prp-slave2-changed-hw-.patch +net-initialize-sk_rx_queue_mapping-in-sk_clone.patch +bluetooth-btusb-mt7922-add-vid-pid-0489-e174.patch +ipv6-move-ifa_f_permanent-percpu-allocation-in-proce.patch +bluetooth-btmtk-improve-mt79xx-firmware-setup-retry-.patch +netfilter-require-ethernet-mac-header-before-using-e.patch +bluetooth-btbcm-add-entry-for-bcm4343a2-uart-bluetoo.patch +bluetooth-btusb-add-lite-on-04ca-3807-for-mediatek-m.patch +bluetooth-btmtk-add-mt7902-mcu-support.patch +bluetooth-btusb-add-new-vid-pid-13d3-3579-for-mt7902.patch +bluetooth-l2cap-coc-disconnect-if-received-packet-si.patch +net-wangxun-reorder-timer-and-work-sync-cancellation.patch +net-hamradio-scc-validate-bufsize-in-siocsccsmem-ioc.patch +net-hamradio-bpqether-validate-frame-length-in-bpq_r.patch +net-rose-reject-truncated-clear_request-frames-in-st.patch +bluetooth-btusb-mediatek-mt7922-add-vid-0489-pid-e11.patch +bluetooth-hci_qca-disable-power-control-for-wcn7850-.patch +bluetooth-hci_ll-enable-broken_enhanced_setup_sync_c.patch +bluetooth-hci_qca-fix-missing-wakeup-during-ssr-memd.patch +drm-panel-edp-add-auo-b116xat04.1-hw-1a.patch +drm-panel-edp-add-cmn-n116bcl-eak-c2.patch +drm-xe-guc-add-wa_14025883347-for-guc-dma-failure-on.patch +nouveau-pci-quiesce-gpu-on-shutdown.patch +asoc-ti-davinci-mcasp-add-system-suspend-resume-supp.patch +mmc-sdhci-esdhc-imx-wait-for-data-transfer-completio.patch +spi-stm32-fix-rx-dma-request-error-handling.patch +asoc-tas2552-allow-audio-enable-gpio-to-sleep.patch +drm-amd-display-exit-ips-w-dc-helper-for-all-dc_set_.patch +drm-amd-display-fix-cursor-pos-at-overlay-plane-edge.patch +drm-amd-display-fix-dcn401_optimize_bandwidth.patch +asoc-sdca-add-cs47l47-to-class-driver.patch +drm-panel-edp-change-boe-nv140wum-n64-timings.patch +pci-dwc-proceed-with-system-suspend-even-if-the-endp.patch +drm-xe-vf-wait-for-all-fixups-before-using-default-l.patch +dm-vdo-indexer-validate-saved-zone-count.patch +dm-vdo-slab-depot-validate-old-zone-count-on-load.patch +dm-cache-prevent-entering-passthrough-mode-after-unc.patch +drm-amdgpu-clear-related-counter-after-ras-eeprom-re.patch +pci-avoid-flr-for-amd-npu-device.patch +drm-bridge-waveshare-dsi-register-and-attach-our-dsi.patch +drm-amd-pm-avoid-overflow-when-sorting-pp_feature-li.patch +drm-amdgpu-userq-remove-queue-from-doorbell-xarray.patch +drm-amdgpu-userq-remove-queue-from-doorbell-xa-durin.patch +drm-amdgpu-check-for-multiplication-overflow-in-chec.patch +drm-amdgpu-userq-defer-queue-publication-until-creat.patch +asoc-sdw_utils-add-cs42l43b-codec-info.patch +alsa-usb-audio-add-studio-1824-support.patch +pci-allow-all-bus-devices-to-use-the-same-slot.patch +fbdev-viafb-check-ioremap-return-value-in-viafb_lcd_.patch +media-stm32-dcmi-stop-the-dma-transfer-on-overrun.patch +media-ccs-pll-fix-pre-pll-divider-calculation-for-ex.patch +media-ipu-bridge-add-ov5675-sensor-config.patch +media-synopsys-hdmirx-support-use-with-sleeping-gpio.patch +media-i2c-imx258-add-missing-mutex-protection-for-fo.patch +media-i2c-mt9p031-check-return-value-of-devm_gpiod_g.patch +media-i2c-ar0521-check-return-value-of-devm_gpiod_ge.patch +drm-amd-display-fix-hwss-v3-fast-path-determination.patch +drm-amdgpu-fix-df-null-pointer-issue-for-soc24.patch +drm-amdgpu-add-default-reset-method-for-soc_v1_0.patch +drm-amdgpu-fix-shift-out-of-bounds-when-updating-umc.patch +drm-amdgpu-fix-array-out-of-bounds-accesses-for-mes-.patch +drm-amdgpu-handle-ih-v7_1-reg-offset-differences.patch +drm-imx-parallel-display-add-drm_display_helper-for-.patch +crypto-tcrypt-clamp-num_mb-to-avoid-divide-by-zero.patch +mmc-core-validate-uhs-ddr-hs200-timing-selection-for.patch +media-pulse8-cec-handle-partial-deinit.patch +asoc-codecs-wcd-clsh-always-update-buck-flyback-on-t.patch +drm-xe-skip-adding-prl-entry-to-null-vma.patch +pci-dpc-hold-pci_dev-reference-during-error-recovery.patch +media-si2168-fw-4.0-11-loses-warm-state-during-sleep.patch +media-cx25840-fix-ntsc-j-pal-n-and-secam-standards.patch +media-em28xx-add-a-variety-of-dualhd-usb-id.patch +media-saa7164-fix-rev2-firmware-filename.patch +media-si2168-fix-i2c-command-timeout-on-embedded-pla.patch +media-em28xx-remove-tuner-type-from-hauppauge-dvb-du.patch +media-rc-fix-race-between-unregister-and-urb-irq-cal.patch +iommu-iova-add-null-check-in-iova_magazine_free.patch +drm-amdgpu-revert-setting-up-retry-based-thrashing-o.patch +drm-amdgpu-fix-amdgpu_userq_evict.patch +drm-amd-display-remove-duplicate-format-modifier.patch +drm-amd-display-fix-number-of-opp.patch +drm-amdgpu-validate-fence_count-in-wait_fences-ioctl.patch +drm-amdgpu-userq-unlock-cancel_delayed_work_sync-for.patch +drm-amd-display-clamp-dc_cursor_position-x_hotspot-t.patch +drm-amdgpu-userq-fix-dma_fence-refcount-underflow-in.patch +drm-panel-edp-add-boe-nv153wum-n42-cmn-n153jca-elk-c.patch +drm-ttm-avoid-invoking-the-oom-killer-when-reading-b.patch +drm-mediatek-mtk_dsi-enable-hs-clock-during-pre-enab.patch +drm-prime-limit-scatter-list-size-with-dedicated-dma.patch +drm-amdgpu-fix-some-more-bug-in-amdgpu_gem_va_ioctl.patch +drm-amdgpu-userq-cleanup-amdgpu_userq_get-put-where-.patch +drm-amd-display-restore-full-update-for-tiling-chang.patch +drm-amdgpu-vcn4.0.3-gate-per-queue-reset-by-psp-sos-.patch +drm-amdgpu-fix-syncobj-leak-for-amdgpu_gem_va_ioctl.patch +media-dw100-fix-kernel-oops-with-preempt_rt-enabled.patch +drm-msm-dpu-fix-vblank-irq-registration-before-atomi.patch +media-renesas-vsp1-rpf-fix-crop-left-and-top-clampin.patch +media-renesas-vsp1-histo-fix-code-enumeration.patch +media-renesas-vsp1-initialize-format-on-all-pads.patch +media-au0828-fix-green-screen-in-analog.patch +pci-vga-pass-vga_get_uninterruptible-errors-to-users.patch +drm-gem-dma-set-vm_dontdump-for-mmap.patch +pci-prevent-assignment-to-unsupported-bridge-windows.patch +iommu-amd-fix-illegal-device-id-access-in-iommu-debu.patch +iommu-amd-fix-illegal-cap-mmio-access-in-iommu-debug.patch +alsa-pcm-use-pcm_lib_apply_appl_ptr-in-x32-sync_ptr.patch +alsa-pcm-serialize-snd_pcm_suspend_all-with-open_mut.patch +alsa-asihpi-detect-truncated-control-names.patch +alsa-usb-audio-add-quirks-for-arturia-af16rig.patch +dm-integrity-fix-mismatched-queue-limits.patch +alsa-hda-cs35l41-fix-boost-type-for-hp-dragonfly-13..patch +alsa-hda-realtek-add-support-for-asus-2026-commercia.patch +drm-amdgpu-guard-atom_context-in-devcoredump-vbios-d.patch +alsa-hda-realtek-add-support-for-hp-laptops.patch +drm-amd-display-bios_parser-fix-gpio-i2c-line-off-by.patch +drm-amd-display-avoid-turning-off-the-phy-when-otg-i.patch +drm-amd-display-merge-pipes-for-validate.patch +drm-amd-display-remove-invalid-dpstreamclk-mask-usag.patch +drm-amdkfd-fix-kernel-crash-on-releasing-null-sysfs-.patch +hwmon-gpd-fan-add-gpd-win-5.patch +hwmon-asus-ec-sensors-add-rog-crosshair-x670e-extrem.patch +hwmon-nct6775-add-asus-x870-w480-to-wmi-monitoring-l.patch +hwmon-pmbus-isl68137-add-support-for-renesas-raa2289.patch +drm-gpu-msm-forbid-mem-reclaim-from-reset.patch +asoc-mxs-sgtl5000-disable-mclk-on-error-paths-of-mxs.patch +alsa-compress-refuse-to-update-timestamps-for-unconf.patch +alsa-aoa-tas-fix-of-node-leak-on-probe-failure.patch +ata-libata-eh-do-not-retry-reset-if-the-device-is-go.patch +alsa-aoa-onyx-fix-of-node-leak-on-probe-failure.patch +iommu-amd-invalidate-irt-cache-for-dma-aliases.patch +asoc-intel-bytcr_rt5640-fix-mclk-leak-on-platform_cl.patch +asoc-intel-cht_bsw_rt5672-fix-mclk-leak-on-platform_.patch +asoc-intel-bytcr_rt5651-fix-mclk-leak-on-platform_cl.patch +asoc-rt5640-handle-0hz-sysclk-during-stream-shutdown.patch +fbdev-omap2-fix-inconsistent-lock-returns-in-omapfb_.patch +alsa-hda-realtek-add-quirk-for-csl-unity-bf24b.patch +pci-tegra194-assert-clkreq-explicitly-by-default.patch +alsa-usb-audio-add-iface-reset-and-delay-quirk-for-h.patch +alsa-usb-audio-add-quirk-flags-for-feaulle-rainbow.patch +arm-xen-validate-hypervisor-compatible-before-parsin.patch +asoc-amd-yc-add-msi-vector-a16-hx-a8whg-to-quirk-tab.patch +spi-rzv2h-rspi-fix-max_speed_hz-advertising-prohibit.patch +spi-tegra210-quad-fix-false-positive-warn-on-interru.patch +hwmon-nct6683-add-customer-id-for-asrock-b650i-light.patch +alsa-hda-realtek-add-quirk-for-acer-pt316-51s-headse.patch +alsa-hda-realtek-add-quirk-for-hp-spectre-x360-14-ea.patch +ext2-replace-bug_on-with-warn_on_once-in-ext2_get_bl.patch +ext2-avoid-drop_nlink-during-unlink-of-zero-nlink-in.patch +virtiofs-add-fuse-protocol-validation.patch +fuse-validate-outarg-offset-and-size-in-notify-store.patch +fuse-mark-dax-inode-releases-as-blocking.patch +rtla-handle-pthread_create-failure-properly.patch +jfs-fix-corrupted-list-in-dbupdatepmap.patch +jfs-add-dtroot-integrity-check-to-prevent-index-out-.patch +jfs-hold-log_lock-on-umount-to-avoid-null-ptr-deref.patch +jfs-set-the-lbmdone-flag-at-the-end-of-lbmiodone.patch +jfs-add-dmapctl-integrity-check-to-prevent-invalid-o.patch +jfs-always-load-filesystem-uuid-during-mount.patch +ring-buffer-enforce-read-ordering-of-trace_buffer-cp.patch +fuse-fix-inode-initialization-race.patch +firmware-qcom-scm-allow-qseecom-on-asus-vivobook-x1p.patch +memory-brcmstb_memc-expand-lpddr4-check-to-cover-for.patch +firmware-qcom-scm-allow-qseecom-on-ecs-liva-qc710.patch +arm64-tegra-fix-snps-blen-properties.patch +firmware-qcom-scm-allow-qseecom-on-lenovo-ideacentre.patch +clk-spear-fix-resource-leak-in-clk_register_vco_pll.patch +smb-client-fix-integer-underflow-in-receive_encrypte.patch +phy-phy-mtk-tphy-update-names-and-format-of-kernel-d.patch +drivers-virt-pkvm-add-kconfig-dependency-on-dma_rest.patch +power-supply-sbs-manager-normalize-return-value-of-g.patch +ima-define-and-use-a-digest_size-field-in-the-ima_al.patch +cxl-pci-hold-memdev-lock-in-cxl_event_trace_record.patch +cxl-region-fix-use-after-free-from-auto-assembly-fai.patch +remoteproc-qcom-fix-minidump-out-of-bounds-access-on.patch +orangefs-add-usercopy-whitelist-to-orangefs_op_cache.patch +orangefs-validate-getxattr-response-length.patch +orangefs_readahead-don-t-overflow-the-bufmap-slot.patch +ext4-unmap-invalidated-folios-from-page-tables-in-mp.patch +hid-quirks-set-always_poll-for-logitech_bolt_receive.patch +hid-logitech-hidpp-check-bounds-when-deleting-force-.patch +hid-logitech-hidpp-fix-race-condition-when-accessing.patch +hid-playstation-validate-num_touch_reports-in-dualsh.patch +bpf-sockmap-annotate-af_unix-sock-sk_state-data-race.patch +pinctrl-realtek-fix-return-value-and-silence-log-for.patch +pinctrl-amd-support-new-acpi-id-amdi0033.patch +ipmi-ssif_bmc-cancel-response-timer-on-remove.patch +i2c-usbio-add-acpi-device-id-for-nvl-platforms.patch +i3c-mipi-i3c-hci-pci-add-support-for-intel-nova-lake.patch +i3c-master-move-bus_init-error-suppression.patch +staging-fbtft-fix-unchecked-write-return-value-in-fb.patch +staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch +ntfs3-reject-inodes-with-zero-non-dos-link-count.patch +thunderbolt-disable-clx-on-titan-ridge-based-devices.patch +usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch +tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch +serial-qcom-geni-fix-rts-behavior-with-flow-control.patch +tty-serial-imx-keep-dma-request-disabled-before-dma-.patch +fs-ntfs3-increase-client_rec-name-field-size.patch +mfd-mt6397-properly-fix-cid-of-mt6328-mt6331-and-mt6.patch +leds-lgm-sso-fix-typo-in-macro-for-src-offset.patch +ecryptfs-set-s_time_gran-to-get-correct-time-granula.patch +mfd-intel-lpss-add-intel-nova-lake-h-pci-ids.patch +nfs-use-nlmclnt_shutdown_rpc_clnt-to-safely-shut-dow.patch +leds-core-implement-fallback-to-software-node-name-f.patch +usb-gadget-bdc-validate-status-report-endpoint-indic.patch +usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch +usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch +usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch +ntfs3-fix-memory-leak-in-indx_create_allocate.patch +tools-power-x86-intel-speed-select-avoid-current-bas.patch +fs-ntfs3-fix-potential-double-iput-on-d_make_root-fa.patch +fs-ntfs3-fix-lxdev-xattr-lookup.patch +ntfs3-fix-oob-write-in-attr_wof_frame_info.patch +platform-x86-hp-wmi-add-support-for-omen-16-wf1xxx-8.patch +scsi-lpfc-fix-incorrect-txcmplq_cnt-during-cleanup-i.patch +scsi-lpfc-remove-unnecessary-ndlp-kref-get-in-lpfc_c.patch +scsi-ufs-ufs-pci-add-support-for-intel-nova-lake.patch +um-avoid-struct-sigcontext-redefinition-with-musl.patch +um-fix-address-of-cmsg_data-rvalue-in-stub.patch +clk-qcom-rcg2-expand-frac-table-for-mdss_pixel_clk_s.patch +scsi-esas2r-fix-__printf-annotation-on-esas2r_log_ma.patch +scsi-virtio_scsi-move-init_work-calls-to-virtscsi_pr.patch +f2fs-fix-to-skip-empty-sections-in-f2fs_get_victim.patch +f2fs-fix-to-freeze-gc-and-discard-threads-quickly.patch +scsi-lpfc-add-pci-id-support-for-lpe42100-series-ada.patch +coda_flag_children-fix-a-uaf.patch +scsi-storvsc-handle-persistent_reserve_in-truncation.patch +scsi-ufs-core-disable-timestamp-for-kioxia-thgjfjt0e.patch +um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch +dt-bindings-arm64-add-marvell-7k-come-boards.patch +selftests-fib_nexthops-test-stale-has_v4-on-nexthop-.patch +smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch +smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch +smb-server-stop-sending-fake-security-descriptors.patch +ksmbd-fix-createoptions-sanitization-clobbering-the-.patch +smb-client-compress-fix-counting-in-lz77-match-findi.patch +ksmbd-fix-o-n-2-dos-in-smb2_lock-via-unbounded-lockc.patch +ipv6-cap-tlv-scan-in-ip6_tnl_parse_tlv_enc_lim.patch +fs-aio-set-vma_dontcopy_bit-in-mmap-to-fix-null-poin.patch +fs-aio-reject-partial-mremap-to-avoid-null-pointer-d.patch +bus-mhi-host-pci_generic-add-qualcomm-sdx35-modem.patch +iio-abi-fix-current_trigger-description.patch +iio-imu-st_lsm6dsx-add-acpi-id-for-shift13mi-gyrosco.patch +bus-mhi-host-pci_generic-add-telit-fe912c04-modem-su.patch +alsa-hda-realtek-add-quirk-for-honor-mrb-xxx-m1020.patch +drm-amdgpu-fix-cper-ring-header-parsing.patch +9p-trans_xen-make-cleanup-idempotent-after-dataring-.patch +alsa-usb-audio-add-quirk-entries-for-nexigo-n930w-we.patch +drm-amd-display-pass-min-page-size-from-soc-bb-to-dm.patch +drm-amd-display-fix-hostvmminpagesize-unit-mismatch-.patch +drm-amd-display-use-overlay-cursor-when-color-pipeli.patch +drm-amdgpu-drop-userq-fence-driver-refs-out-of-fence.patch +drm-amdgpu-or-init_pte_flags-into-invalid-leaf-pte-u.patch +io_uring-rsrc-unify-nospec-indexing-for-direct-descr.patch +io_uring-take-page-references-for-nommu-pbuf_ring-mm.patch +nfs-fix-writeback-in-presence-of-errors.patch +asoc-qcom-x1e80100-limit-speaker-volumes.patch +fbdev-savage-fix-probe-path-edid-cleanup-leaks.patch +rtc-max77686-convert-to-i2c_new_ancillary_device.patch +rtc-ti-k3-add-support-to-resume-from-io-ddr-low-powe.patch +dt-bindings-rtc-microcrystal-rv3028-allow-to-specify.patch +mailbox-cix-add-irqf_no_suspend-to-mailbox-interrupt.patch +nvmet-tcp-check-init_failed-before-nvmet_req_uninit-.patch +nvme-add-quirk-nvme_quirk_ignore_dev_subnqn-for-144d.patch +nvme-core-fix-parameter-name-in-comment.patch +nvme-add-missing-module_alias-for-fabrics-transports.patch +nvme-multipath-put-module-reference-when-delayed-rem.patch +btrfs-fix-wrong-min_objectid-in-btrfs_previous_item-.patch +btrfs-handle-unexpected-free-space-tree-key-types.patch +btrfs-fix-raid-stripe-search-missing-entries-at-leaf.patch +asoc-codecs-wcd937x-fix-aux-pa-sequencing-and-mixer-.patch +btrfs-abort-transaction-in-do_remap_reloc_trans-on-f.patch +btrfs-replace-assert-with-proper-error-handling-in-s.patch +btrfs-apply-first-key-check-for-readahead-when-possi.patch +btrfs-copy-devid-in-btrfs_partially_delete_raid_exte.patch +drm-amdkfd-check-if-vm-ready-in-svm-map-and-unmap-to.patch +nvmet-tcp-don-t-clear-tls_key-when-freeing-sq.patch +btrfs-check-return-value-of-btrfs_partially_delete_r.patch +nvme-tcp-teardown-circular-locking-fixes.patch +btrfs-handle-eagain-from-btrfs_duplicate_item-and-re.patch +alsa-usb-audio-apply-quirk-for-playstation-pdp-riffm.patch +alsa-hda-realtek-enable-mute-led-support-on-thinkboo.patch +asoc-aw88395-fix-kernel-panic-caused-by-invalid-gpio.patch +md-raid5-fix-uaf-on-io-across-the-reshape-position.patch +drm-amd-pm-update-emit-clock-logic.patch +asoc-spacemit-move-hw-constraints-from-hw_params-to-.patch +alsa-hda-avoid-warn_on-for-hdmi-chmap-slot-checks.patch +smb-client-change-allocation-requirements-in-smb2_co.patch diff --git a/queue-7.0/smb-client-change-allocation-requirements-in-smb2_co.patch b/queue-7.0/smb-client-change-allocation-requirements-in-smb2_co.patch new file mode 100644 index 0000000000..cf0e7f6b7e --- /dev/null +++ b/queue-7.0/smb-client-change-allocation-requirements-in-smb2_co.patch @@ -0,0 +1,39 @@ +From 8d343233e8a8552b2c9428ddfe35b6d2936c0154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 14:34:53 -0700 +Subject: smb: client: change allocation requirements in smb2_compound_op + +From: Fredric Cover + +[ Upstream commit 8e13b1b4093e0cbcb3dc2906c13b1fdc95cdf0a0 ] + +Currently, smb2_compound_op() allocates +struct smb2_compound_vars *vars using GFP_ATOMIC, although +smb2_compound_op() can sleep when it calls compound_send_recv() +before vars is freed. + +Allocate vars using GFP_KERNEL. + +Signed-off-by: Fredric Cover +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c +index 3b09cf8ab0f27..66146a84084c2 100644 +--- a/fs/smb/client/smb2inode.c ++++ b/fs/smb/client/smb2inode.c +@@ -213,7 +213,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, + num_rqst = 0; + server = cifs_pick_channel(ses); + +- vars = kzalloc_obj(*vars, GFP_ATOMIC); ++ vars = kzalloc_obj(*vars, GFP_KERNEL); + if (vars == NULL) { + rc = -ENOMEM; + goto out; +-- +2.53.0 + diff --git a/queue-7.0/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch b/queue-7.0/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch new file mode 100644 index 0000000000..04737eb0f5 --- /dev/null +++ b/queue-7.0/smb-client-compress-fix-bad-encoding-on-last-lz77-fl.patch @@ -0,0 +1,37 @@ +From 43b348724310605d60e0287bad80949c4b31b7c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:07 -0300 +Subject: smb: client: compress: fix bad encoding on last LZ77 flag + +From: Enzo Matsumiya + +[ Upstream commit a13e942a03feea211c67a97bc6a57f82aa56e4b6 ] + +End-of-stream flag could lead to UB because of int promotion +(overwriting signed bit). + +Fix it by changing operand from '1' to '1UL'. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index 96e8a8057a772..cdd6b53766b0a 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -221,7 +221,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + } + + flag <<= (32 - flag_count); +- flag |= (1 << (32 - flag_count)) - 1; ++ flag |= (1UL << (32 - flag_count)) - 1; + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-- +2.53.0 + diff --git a/queue-7.0/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch b/queue-7.0/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch new file mode 100644 index 0000000000..61f931f3e7 --- /dev/null +++ b/queue-7.0/smb-client-compress-fix-buffer-overrun-in-lz77_compr.patch @@ -0,0 +1,131 @@ +From 289968ea5209d404b1d4405f6e4c6672ac6234f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:06 -0300 +Subject: smb: client: compress: fix buffer overrun in lz77_compress() + +From: Enzo Matsumiya + +[ Upstream commit 4c221711b23745e2fb961ee517e9ed96ce76f9cb ] + +@dst buffer is allocated with same size as @src, which, for good +compression cases, works fine. + +However, when compression goes bad (e.g. random bytes payloads), the +compressed size can increase significantly, and even by stopping the +main loop at 7/8 of @slen, writing leftover literals could write past +the end of @dst because of LZ77 metadata. + +To fix this, add lz77_compressed_alloc_size() helper to compute the +correct allocation size for @dst, accounting for metadata and worst +cast scenario (all literals). + +While this is overprovisioning memory, it's not only correct, but also +allows lz77_compress() main loop to run without ever checking @dst +limits (i.e. a perf improvement). + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress.c | 6 +----- + fs/smb/client/compress/lz77.c | 14 ++++---------- + fs/smb/client/compress/lz77.h | 28 ++++++++++++++++++++++++++++ + 3 files changed, 33 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c +index 3d1e73f5d9af9..be9023f841e69 100644 +--- a/fs/smb/client/compress.c ++++ b/fs/smb/client/compress.c +@@ -329,11 +329,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s + goto err_free; + } + +- /* +- * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8 +- * of @slen. +- */ +- dlen = slen; ++ dlen = lz77_compressed_alloc_size(slen); + dst = kvzalloc(dlen, GFP_KERNEL); + if (!dst) { + ret = -ENOMEM; +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index cdd6b53766b0a..c1e7fada6e61c 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -137,6 +137,10 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + long flag = 0; + u64 *htable; + ++ /* This is probably a bug, so throw a warning. */ ++ if (WARN_ON_ONCE(*dlen < lz77_compressed_alloc_size(slen))) ++ return -EINVAL; ++ + srcp = src; + end = src + slen; + dstp = dst; +@@ -180,15 +184,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + continue; + } + +- /* +- * Bail out if @dstp reached >= 7/8 of @slen -- already compressed badly, not worth +- * going further. +- */ +- if (unlikely(dstp - dst >= slen - (slen >> 3))) { +- *dlen = slen; +- goto out; +- } +- + dstp = lz77_write_match(dstp, &nib, dist, len); + srcp += len; + +@@ -225,7 +220,6 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + lz77_write32(flag_pos, flag); + + *dlen = dstp - dst; +-out: + kvfree(htable); + + if (*dlen < slen) +diff --git a/fs/smb/client/compress/lz77.h b/fs/smb/client/compress/lz77.h +index cdcb191b48a23..2603eab9e071c 100644 +--- a/fs/smb/client/compress/lz77.h ++++ b/fs/smb/client/compress/lz77.h +@@ -11,5 +11,33 @@ + + #include + ++/** ++ * lz77_compressed_alloc_size() - Compute compressed buffer size. ++ * @size: uncompressed (src) size ++ * ++ * Compute allocation size for the compressed buffer based on uncompressed size. ++ * Accounts for metadata and overprovision for the worst case scenario. ++ * ++ * LZ77 metadata is a 4-byte flag that is written: ++ * - on dst begin (pos 0) ++ * - every 32 literals or matches ++ * - on end-of-stream (possibly, if last write was another flag) ++ * ++ * Worst case scenario is an all-literal compression, which means: ++ * metadata bytes = 4 + ((@size / 32) * 4) + 4, or, simplified, (@size >> 3) + 8 ++ * ++ * The worst case scenario rarely happens, but such overprovisioning also allows lz77_compress() ++ * main loop to run without ever bound checking dst, which is a huge perf improvement, while also ++ * being safe when compression goes bad. ++ * ++ * Return: required (*) allocation size for compressed buffer. ++ * ++ * (*) checked once in the beginning of lz77_compress() ++ */ ++static __always_inline u32 lz77_compressed_alloc_size(const u32 size) ++{ ++ return size + (size >> 3) + 8; ++} ++ + int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen); + #endif /* _SMB_COMPRESS_LZ77_H */ +-- +2.53.0 + diff --git a/queue-7.0/smb-client-compress-fix-counting-in-lz77-match-findi.patch b/queue-7.0/smb-client-compress-fix-counting-in-lz77-match-findi.patch new file mode 100644 index 0000000000..ecd866be0e --- /dev/null +++ b/queue-7.0/smb-client-compress-fix-counting-in-lz77-match-findi.patch @@ -0,0 +1,78 @@ +From 91c1f0bb8ad262dce56edf38566d1a5f21029781 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:07:08 -0300 +Subject: smb: client: compress: fix counting in LZ77 match finding + +From: Enzo Matsumiya + +[ Upstream commit 20d4f9efe008be1b673f43d38d3d99fb1fd4cd68 ] + +- lz77_match_len() increments @cur before checking for equality, + leading to off-by-one match len in some cases. + + Fix by moving pointers increment to inside the loop. + Also rename @wnd arg to @match (more accurate name). +- both lz77_match_len() and lz77_compress() checked for + "buf + step < end" when the correct is "<=" for such cases. + +Signed-off-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/compress/lz77.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/smb/client/compress/lz77.c b/fs/smb/client/compress/lz77.c +index c1e7fada6e61c..61cdf1c146127 100644 +--- a/fs/smb/client/compress/lz77.c ++++ b/fs/smb/client/compress/lz77.c +@@ -48,17 +48,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v) + put_unaligned_le32(v, ptr); + } + +-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end) ++static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end) + { + const void *start = cur; + u64 diff; + + /* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */ + do { +- diff = lz77_read64(cur) ^ lz77_read64(wnd); ++ diff = lz77_read64(cur) ^ lz77_read64(match); + if (!diff) { + cur += LZ77_STEP_SIZE; +- wnd += LZ77_STEP_SIZE; ++ match += LZ77_STEP_SIZE; + + continue; + } +@@ -67,10 +67,13 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons + cur += count_trailing_zeros(diff) >> 3; + + return (cur - start); +- } while (likely(cur + LZ77_STEP_SIZE < end)); ++ } while (likely(cur + LZ77_STEP_SIZE <= end)); + +- while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++)) +- ; ++ /* Fallback to byte-by-byte comparison for last <8 bytes. */ ++ while (cur < end && lz77_read8(cur) == lz77_read8(match)) { ++ cur++; ++ match++; ++ } + + return (cur - start); + } +@@ -195,7 +198,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) + flag_pos = dstp; + dstp += 4; + } +- } while (likely(srcp + LZ77_STEP_SIZE < end)); ++ } while (likely(srcp + LZ77_STEP_SIZE <= end)); + + while (srcp < end) { + u32 c = umin(end - srcp, 32 - flag_count); +-- +2.53.0 + diff --git a/queue-7.0/smb-client-fix-integer-underflow-in-receive_encrypte.patch b/queue-7.0/smb-client-fix-integer-underflow-in-receive_encrypte.patch new file mode 100644 index 0000000000..4198088bfc --- /dev/null +++ b/queue-7.0/smb-client-fix-integer-underflow-in-receive_encrypte.patch @@ -0,0 +1,58 @@ +From 505ea168ef30e1cde04ee75b898aa2ac28097649 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:24:24 +0800 +Subject: smb: client: fix integer underflow in receive_encrypted_read() + +From: Dudu Lu + +[ Upstream commit 6b83b03c07fbe0b57bb729bee91ae44c623c82ff ] + +In receive_encrypted_read(), the length of data to read from the socket +is computed as: + + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + +OriginalMessageSize comes from the server's transform header and is +untrusted. If a malicious server sends a value smaller than +read_rsp_size, the unsigned subtraction wraps to a very large value +(~4GB). This value is then passed to netfs_alloc_folioq_buffer() and +cifs_read_iter_from_socket(), causing either a massive allocation +attempt that fails with -ENOMEM (DoS), or under extreme memory +pressure, potential heap corruption. + +Fix by adding a check that OriginalMessageSize is at least +read_rsp_size before the subtraction. On failure, jump to +discard_data to drain the remaining PDU from the socket, preventing +desync of subsequent reads on the connection. + +Signed-off-by: Dudu Lu +Reviewed-by: Enzo Matsumiya +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/client/smb2ops.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index f4c95cc26db21..0ea3ce1b94ea6 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -4970,6 +4970,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + goto free_dw; + server->total_read += rc; + ++ if (le32_to_cpu(tr_hdr->OriginalMessageSize) < ++ server->vals->read_rsp_size) { ++ cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", ++ le32_to_cpu(tr_hdr->OriginalMessageSize), ++ server->vals->read_rsp_size); ++ rc = -EINVAL; ++ goto discard_data; ++ } + len = le32_to_cpu(tr_hdr->OriginalMessageSize) - + server->vals->read_rsp_size; + dw->len = len; +-- +2.53.0 + diff --git a/queue-7.0/smb-server-stop-sending-fake-security-descriptors.patch b/queue-7.0/smb-server-stop-sending-fake-security-descriptors.patch new file mode 100644 index 0000000000..003b3bd4c0 --- /dev/null +++ b/queue-7.0/smb-server-stop-sending-fake-security-descriptors.patch @@ -0,0 +1,71 @@ +From 1c70d72e21f2cbe3e1f7b0fc2e9fe03783376f4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 10:14:50 +0900 +Subject: smb: server: stop sending fake security descriptors + +From: Marios Makassikis + +[ Upstream commit 5efb579e0d1ee02b85e3ce2da691c88c93111060 ] + +in smb2_get_info_sec, a dummy security descriptor (SD) is returned if +the requested information is not supported. + +the code is currently wrong, as DACL_PROTECTED is set in the type field, +but there is no DACL is present. + +instead of faking a security, report a STATUS_NOT_SUPPORTED error. + +this seems to fix a "Error 0x80090006: Invalid Signature" on file +transfers with Windows 11 clients (25H2, build 26200.8246). + +capturing traffic shows that the client is sending a GET_INFO/SEC_INFO +request, with the additional_info field set to 0x20 +(ATTRIBUTE_SECURITY_INFORMATION). Returning an empty SD +(with only SELF_RELATIVE set) does not fix the error. + +Signed-off-by: Marios Makassikis +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index c3c7688f0fa80..fd38058fa23da 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -5746,20 +5746,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", + addition_info); + +- pntsd = kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), +- KSMBD_DEFAULT_GFP); +- if (!pntsd) +- return -ENOMEM; +- +- pntsd->revision = cpu_to_le16(1); +- pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); +- pntsd->osidoffset = 0; +- pntsd->gsidoffset = 0; +- pntsd->sacloffset = 0; +- pntsd->dacloffset = 0; +- +- secdesclen = sizeof(struct smb_ntsd); +- goto iov_pin; ++ rsp->hdr.Status = STATUS_NOT_SUPPORTED; ++ return -EINVAL; + } + + if (work->next_smb2_rcv_hdr_off) { +@@ -5826,7 +5814,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, + if (rc) + goto err_out; + +-iov_pin: + rsp->OutputBufferLength = cpu_to_le32(secdesclen); + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), + rsp, work->response_buf); +-- +2.53.0 + diff --git a/queue-7.0/spi-rzv2h-rspi-fix-max_speed_hz-advertising-prohibit.patch b/queue-7.0/spi-rzv2h-rspi-fix-max_speed_hz-advertising-prohibit.patch new file mode 100644 index 0000000000..3c9155053a --- /dev/null +++ b/queue-7.0/spi-rzv2h-rspi-fix-max_speed_hz-advertising-prohibit.patch @@ -0,0 +1,62 @@ +From cd755d30128d9a5a14e6ce3c2646fde0975ae31c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 09:05:15 +0100 +Subject: spi: rzv2h-rspi: Fix max_speed_hz advertising prohibited bit rate + +From: Lad Prabhakar + +[ Upstream commit 4e292cbf3890657db2f2692942cb0f168c80167e ] + +On RZ/V2H(P), RZ/G3E and RZ/G3L, RSPI_n_TCLK is fixed at 200MHz. +The max_speed_hz was computed using clk_round_rate(tclk, ULONG_MAX) +with SPR=0 and BRDV=0, resulting in 100Mbps - the exact combination +prohibited on these SoCs. This could cause the SPI framework to request +a speed that rzv2h_rspi_find_rate_fixed() would skip, potentially +leading to a clock selection failure. + +On RZ/T2H and RZ/N2H the max_speed_hz was correctly calculated as +50Mbps for both the variable PCLKSPIn and fixed PCLK clock sources. + +Since the maximum supported bit rate is 50Mbps across all supported SoC +variants, replace the clk_round_rate() based calculation with a define +RSPI_MAX_SPEED_HZ set to 50MHz and use it directly for max_speed_hz. + +Signed-off-by: Lad Prabhakar +Link: https://patch.msgid.link/20260410080517.2405700-2-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rzv2h-rspi.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c +index 53c44799fab71..d4f115ffc1f99 100644 +--- a/drivers/spi/spi-rzv2h-rspi.c ++++ b/drivers/spi/spi-rzv2h-rspi.c +@@ -76,6 +76,8 @@ + + #define RSPI_RESET_NUM 2 + ++#define RSPI_MAX_SPEED_HZ 50000000 ++ + struct rzv2h_rspi_best_clock { + struct clk *clk; + unsigned long clk_rate; +@@ -777,13 +779,7 @@ static int rzv2h_rspi_probe(struct platform_device *pdev) + RSPI_SPBR_SPR_MAX, + RSPI_SPCMD_BRDV_MAX); + +- tclk_rate = clk_round_rate(rspi->tclk, ULONG_MAX); +- if (tclk_rate < 0) +- return tclk_rate; +- +- controller->max_speed_hz = rzv2h_rspi_calc_bitrate(tclk_rate, +- RSPI_SPBR_SPR_MIN, +- RSPI_SPCMD_BRDV_MIN); ++ controller->max_speed_hz = RSPI_MAX_SPEED_HZ; + + controller->dma_tx = devm_dma_request_chan(dev, "tx"); + if (IS_ERR(controller->dma_tx)) { +-- +2.53.0 + diff --git a/queue-7.0/spi-stm32-fix-rx-dma-request-error-handling.patch b/queue-7.0/spi-stm32-fix-rx-dma-request-error-handling.patch new file mode 100644 index 0000000000..5885e81d3e --- /dev/null +++ b/queue-7.0/spi-stm32-fix-rx-dma-request-error-handling.patch @@ -0,0 +1,54 @@ +From 4c2b7c315a641ed31e5e9b948e5df85fdf794852 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 12:49:10 +0100 +Subject: spi: stm32: fix rx DMA request error handling + +From: Alain Volmat + +[ Upstream commit 837f6691d5f39ea6453e4489dded40fb17755c60 ] + +Avoid trying to release the RX DMA channel when an error occurs +during RX dma_request_chan() call. Instead, jump directly to +release the TX channel, if applicable. + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-spi/aYXvY6NH7OlZ-OAF@stanley.mountain/T/#u +Signed-off-by: Alain Volmat +Link: https://patch.msgid.link/20260212-spi-stm32-fix-dma-rx-release-v1-1-53a37c31626b@foss.st.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-stm32.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c +index 33f211e159ef1..6d5eefa41f717 100644 +--- a/drivers/spi/spi-stm32.c ++++ b/drivers/spi/spi-stm32.c +@@ -2505,7 +2505,7 @@ static int stm32_spi_probe(struct platform_device *pdev) + spi->dma_rx = NULL; + } else { + dev_err_probe(&pdev->dev, ret, "failed to request rx dma channel\n"); +- goto err_dma_release; ++ goto err_dma_tx_release; + } + } else { + ctrl->dma_rx = spi->dma_rx; +@@ -2574,11 +2574,11 @@ static int stm32_spi_probe(struct platform_device *pdev) + if (spi->sram_pool) + gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf, + spi->sram_rx_buf_size); +-err_dma_release: +- if (spi->dma_tx) +- dma_release_channel(spi->dma_tx); + if (spi->dma_rx) + dma_release_channel(spi->dma_rx); ++err_dma_tx_release: ++ if (spi->dma_tx) ++ dma_release_channel(spi->dma_tx); + err_clk_disable: + clk_disable_unprepare(spi->clk); + +-- +2.53.0 + diff --git a/queue-7.0/spi-tegra210-quad-fix-false-positive-warn-on-interru.patch b/queue-7.0/spi-tegra210-quad-fix-false-positive-warn-on-interru.patch new file mode 100644 index 0000000000..0028e8f831 --- /dev/null +++ b/queue-7.0/spi-tegra210-quad-fix-false-positive-warn-on-interru.patch @@ -0,0 +1,80 @@ +From 5e53424d0903d235f94b1b7a6ed1e3ddff5d4a87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 06:45:43 -0700 +Subject: spi: tegra210-quad: Fix false positive WARN on interrupt timeout with + transfer complete + +From: Breno Leitao + +[ Upstream commit 5b94c94caafcad3c77cc6b1d213a93bf5dc0a98e ] + +The WARN_ON_ONCE/WARN_ON fired unconditionally on any completion +timeout, including the recoverable case where the interrupt was lost but +the hardware actually finished the transfer. This produced a noisy splat +with a full call trace even though the driver successfully recovered via +tegra_qspi_handle_timeout(). + +Since tegra210 uses threaded interrupts, the transfer completion can be +signaled before the interrupt fires, making this false positive case +common in practice. + +Almost all the hosts I sysadmin in my fleet produce the following splat: + + WARNING: CPU: 47 PID: 844 at drivers/spi/spi-tegra210-quad.c:1226 tegra_qspi_transfer_one_message+0x8a4/0xba8 + .... + tegra-qspi NVDA1513:00: QSPI interrupt timeout, but transfer complete + +Move WARN_ON_ONCE/WARN_ON to fire only on real unrecoverable timeouts, +i.e., when tegra_qspi_handle_timeout() confirms the hardware did NOT +complete. This makes the warning actionable instead of just polluting +the metrics. + +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260408-tegra_warn-v1-1-669a3bc74d77@debian.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-tegra210-quad.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c +index 7ea5aa993596f..05f1753e2bbb1 100644 +--- a/drivers/spi/spi-tegra210-quad.c ++++ b/drivers/spi/spi-tegra210-quad.c +@@ -1223,7 +1223,7 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, + (&tqspi->xfer_completion, + QSPI_DMA_TIMEOUT); + +- if (WARN_ON_ONCE(ret == 0)) { ++ if (ret == 0) { + /* + * Check if hardware completed the transfer + * even though interrupt was lost or delayed. +@@ -1232,6 +1232,7 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, + ret = tegra_qspi_handle_timeout(tqspi); + if (ret < 0) { + /* Real timeout - clean up and fail */ ++ WARN_ON_ONCE(1); + dev_err(tqspi->dev, "transfer timeout\n"); + + /* Abort transfer by resetting pio/dma bit */ +@@ -1340,7 +1341,7 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi, + + ret = wait_for_completion_timeout(&tqspi->xfer_completion, + QSPI_DMA_TIMEOUT); +- if (WARN_ON(ret == 0)) { ++ if (ret == 0) { + /* + * Check if hardware completed the transfer even though + * interrupt was lost or delayed. If so, process the +@@ -1349,6 +1350,7 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi, + ret = tegra_qspi_handle_timeout(tqspi); + if (ret < 0) { + /* Real timeout - clean up and fail */ ++ WARN_ON(1); + dev_err(tqspi->dev, "transfer timeout\n"); + + if (tqspi->is_curr_dma_xfer) +-- +2.53.0 + diff --git a/queue-7.0/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch b/queue-7.0/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch new file mode 100644 index 0000000000..eafed16ab0 --- /dev/null +++ b/queue-7.0/staging-fbtft-fix-unchecked-write-return-value-in-fb.patch @@ -0,0 +1,39 @@ +From 87b143fb9cdf443b9ea810591bdd52e05c93bf61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 22:05:23 +0000 +Subject: staging: fbtft: fix unchecked write return value in fb_agm1264k-fl + +From: Artem Lytkin + +[ Upstream commit f80760f5fc02c1ab384a974097964aa8e6720331 ] + +The second call to par->fbtftops.write() does not capture the return +value, so the subsequent error check tests a stale value from the +first write call. Add the missing assignment so the error check +applies to the correct write operation. + +Signed-off-by: Artem Lytkin +Acked-by: Andy Shevchenko +Link: https://patch.msgid.link/20260207220523.3816-1-iprintercanon@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index af2dbebefc72b..6fc8f4e9c814d 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -376,7 +376,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + /* write bitmap */ + gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */ +- par->fbtftops.write(par, buf, len); ++ ret = par->fbtftops.write(par, buf, len); + if (ret < 0) + dev_err(par->info->device, + "write failed and returned: %d\n", +-- +2.53.0 + diff --git a/queue-7.0/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch b/queue-7.0/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch new file mode 100644 index 0000000000..9cb008ecb5 --- /dev/null +++ b/queue-7.0/staging-octeon-fix-free_irq-dev_id-mismatch-in-cvm_o.patch @@ -0,0 +1,52 @@ +From c76879cdb3d85c3ab69b2af50c83a6392dd3fa55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 22:49:03 +0530 +Subject: staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown + +From: Yuvraj Singh Chauhan + +[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ] + +In cvm_oct_rx_initialize(), request_irq() is called with +&oct_rx_group[i].napi as the dev_id: + + request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", + &oct_rx_group[i].napi); + +However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of +struct net_device pointers) as the dev_id to free_irq(): + + free_irq(oct_rx_group[i].irq, cvm_oct_device); + +Since __free_irq() matches the action to remove by comparing +dev_id pointers, the mismatched cookie means the IRQ handler is +never found, triggering a WARN and leaving the IRQ line permanently +allocated. This prevents proper driver cleanup on module removal. + +Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id +to free_irq(), matching what was used during request_irq(). + +Signed-off-by: Yuvraj Singh Chauhan +Link: https://patch.msgid.link/20260212171903.1417804-1-ysinghcin@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/octeon/ethernet-rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c +index 965330eec80a8..d0b43d50b83ce 100644 +--- a/drivers/staging/octeon/ethernet-rx.c ++++ b/drivers/staging/octeon/ethernet-rx.c +@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void) + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0); + + /* Free the interrupt handler */ +- free_irq(oct_rx_group[i].irq, cvm_oct_device); ++ free_irq(oct_rx_group[i].irq, &oct_rx_group[i].napi); + + netif_napi_del(&oct_rx_group[i].napi); + } +-- +2.53.0 + diff --git a/queue-7.0/tcp-fix-imbalanced-icsk_accept_queue-count.patch b/queue-7.0/tcp-fix-imbalanced-icsk_accept_queue-count.patch new file mode 100644 index 0000000000..07c8672df0 --- /dev/null +++ b/queue-7.0/tcp-fix-imbalanced-icsk_accept_queue-count.patch @@ -0,0 +1,46 @@ +From 0ef9627916381fefb8633590220541095c307df3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 May 2026 03:59:19 +0000 +Subject: tcp: Fix imbalanced icsk_accept_queue count. + +From: Kuniyuki Iwashima + +[ Upstream commit 7eca3292cac7c26dad4c236f51ba225c39a0523f ] + +When TCP socket migration happens in reqsk_timer_handler(), +@sk_listener will be updated with the new listener. + +When we call __inet_csk_reqsk_queue_drop(), the listener must +be the one stored in req->rsk_listener. + +The cited commit accidentally replaced oreq->rsk_listener with +sk_listener, leading to imbalanced icsk_accept_queue count. + +Let's pass the correct listener to __inet_csk_reqsk_queue_drop(). + +Fixes: e8c526f2bdf1 ("tcp/dccp: Don't use timer_pending() in reqsk_queue_unlink().") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506035954.1563147-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index bc987a59a0952..f1988fd503540 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1137,7 +1137,7 @@ static void reqsk_timer_handler(struct timer_list *t) + } + + drop: +- __inet_csk_reqsk_queue_drop(sk_listener, oreq, true); ++ __inet_csk_reqsk_queue_drop(oreq->rsk_listener, oreq, true); + reqsk_put(oreq); + } + +-- +2.53.0 + diff --git a/queue-7.0/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch b/queue-7.0/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch new file mode 100644 index 0000000000..a207d9d429 --- /dev/null +++ b/queue-7.0/tcp-fix-out-of-bounds-access-for-twsk-in-tcp_ao_esta.patch @@ -0,0 +1,52 @@ +From 706fcb3a89d9cdd375dd096dc31ff46b64531855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 12:08:46 +0000 +Subject: tcp: Fix out-of-bounds access for twsk in tcp_ao_established_key(). + +From: Kuniyuki Iwashima + +[ Upstream commit 03cb001ef87b3f8d859cf7f96329acf3d6235d29 ] + +lockdep_sock_is_held() was added in tcp_ao_established_key() +by the cited commit. + +It can be called from tcp_v[46]_timewait_ack() with twsk. + +Since it does not have sk->sk_lock, the lockdep annotation +results in out-of-bound access. + + $ pahole -C tcp_timewait_sock vmlinux | grep size + /* size: 288, cachelines: 5, members: 8 */ + $ pahole -C sock vmlinux | grep sk_lock + socket_lock_t sk_lock; /* 440 192 */ + +Let's not use lockdep_sock_is_held() for TCP_TIME_WAIT. + +Fixes: 6b2d11e2d8fc ("net/tcp: Add missing lockdep annotations for TCP-AO hlist traversals") +Reported-by: Damiano Melotti +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260508120853.4098365-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_ao.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c +index a97cdf3e6af4c..0a4b38b315fed 100644 +--- a/net/ipv4/tcp_ao.c ++++ b/net/ipv4/tcp_ao.c +@@ -116,7 +116,8 @@ struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk, + { + struct tcp_ao_key *key; + +- hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) { ++ hlist_for_each_entry_rcu(key, &ao->head, node, ++ sk_fullsock(sk) && lockdep_sock_is_held(sk)) { + if ((sndid >= 0 && key->sndid != sndid) || + (rcvid >= 0 && key->rcvid != rcvid)) + continue; +-- +2.53.0 + diff --git a/queue-7.0/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch b/queue-7.0/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch new file mode 100644 index 0000000000..880aa2a585 --- /dev/null +++ b/queue-7.0/tcp-use-write_once-for-tsoffset-in-tcp_v6_connect.patch @@ -0,0 +1,48 @@ +From 3eff09bd25eb5aea72665e3787306d9f23aa3748 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 19:26:04 -0600 +Subject: tcp: use WRITE_ONCE() for tsoffset in tcp_v6_connect() + +From: Wesley Atwell + +[ Upstream commit dc9902bbd480aae510b885b67cd30cd04cfce3a8 ] + +Commit dd23c9f1e8d5 ("tcp: annotate data-races around tp->tsoffset") +updated do_tcp_getsockopt() to read tp->tsoffset with READ_ONCE() +for TCP_TIMESTAMP because another CPU may change it concurrently. + +tcp_v6_connect() still stores tp->tsoffset with a plain write. That +store runs under lock_sock() via inet_stream_connect(), but the socket +lock does not serialize a concurrent getsockopt(TCP_TIMESTAMP) from +another task sharing the socket. + +Use WRITE_ONCE() for the tcp_v6_connect() store so the connect-time +writer matches the lockless TCP_TIMESTAMP reader. This also makes the +IPv6 path consistent with tcp_v4_connect(). + +Signed-off-by: Wesley Atwell +Reviewed-by: Eric Dumazet +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260310012604.145661-1-atwellwea@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/tcp_ipv6.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index bb09d5ccf5990..ba7cd7d3d4da0 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -325,7 +325,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr, + inet->inet_dport); + if (!tp->write_seq) + WRITE_ONCE(tp->write_seq, st.seq); +- tp->tsoffset = st.ts_off; ++ WRITE_ONCE(tp->tsoffset, st.ts_off); + } + + if (tcp_fastopen_defer_connect(sk, &err)) +-- +2.53.0 + diff --git a/queue-7.0/test_kprobes-clear-kprobes-between-test-runs.patch b/queue-7.0/test_kprobes-clear-kprobes-between-test-runs.patch new file mode 100644 index 0000000000..21d56f392b --- /dev/null +++ b/queue-7.0/test_kprobes-clear-kprobes-between-test-runs.patch @@ -0,0 +1,128 @@ +From 72678bd1eac3a5dcb4c811575f8084f26cd610fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 09:56:36 +0900 +Subject: test_kprobes: clear kprobes between test runs + +From: Martin Kaiser + +[ Upstream commit ef5581bb30efb939cc2bf093475c6cc85258e5cd ] + +Running the kprobes sanity tests twice makes all tests fail and +eventually crashes the kernel. + +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # Totals: pass:5 fail:0 skip:0 total:5 + ok 1 kprobes_test +[root@martin-riscv-1 ~]# echo 1 > /sys/kernel/debug/kunit/kprobes_test/run +... + # test_kprobe: EXPECTATION FAILED at lib/tests/test_kprobes.c:64 + Expected 0 == register_kprobe(&kp), but + register_kprobe(&kp) == -22 (0xffffffffffffffea) +... + Unable to handle kernel paging request ... + +The testsuite defines several kprobes and kretprobes as static variables +that are preserved across test runs. + +After register_kprobe and unregister_kprobe, a kprobe contains some +leftover data that must be cleared before the kprobe can be registered +again. The tests are setting symbol_name to define the probe location. +Address and flags must be cleared. + +The existing code clears some of the probes between subsequent tests, but +not between two test runs. The leftover data from a previous test run +makes the registrations fail in the next run. + +Move the cleanups for all kprobes into kprobes_test_init, this function +is called before each single test (including the first test of a test +run). + +Link: https://lore.kernel.org/all/20260507134615.1010905-1-martin@kaiser.cx/ + +Fixes: e44e81c5b90f ("kprobes: convert tests to kunit") +Signed-off-by: Martin Kaiser +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +--- + lib/tests/test_kprobes.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/lib/tests/test_kprobes.c b/lib/tests/test_kprobes.c +index b7582010125c3..06e729e4de051 100644 +--- a/lib/tests/test_kprobes.c ++++ b/lib/tests/test_kprobes.c +@@ -12,6 +12,12 @@ + + #define div_factor 3 + ++#define KP_CLEAR(_kp) \ ++do { \ ++ (_kp).addr = NULL; \ ++ (_kp).flags = 0; \ ++} while (0) ++ + static u32 rand1, preh_val, posth_val; + static u32 (*target)(u32 value); + static u32 (*recursed_target)(u32 value); +@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test) + + current_test = test; + +- /* addr and flags should be cleard for reusing kprobe. */ +- kp.addr = NULL; +- kp.flags = 0; +- + KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2)); + preh_val = 0; + posth_val = 0; +@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test) + struct kretprobe *rps[2] = {&rp, &rp2}; + + current_test = test; +- /* addr and flags should be cleard for reusing kprobe. */ +- rp.kp.addr = NULL; +- rp.kp.flags = 0; + KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2)); + + krph_val = 0; +@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test) + unsigned long myretaddr = (unsigned long)__builtin_return_address(0); + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + /* + * Run the stacktrace_driver() to record correct return address in +@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + struct kretprobe *rps[2] = {&rp3, &rp4}; + + current_test = test; +- rp3.kp.addr = NULL; +- rp3.kp.flags = 0; + + //KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver()); + +@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test) + + static int kprobes_test_init(struct kunit *test) + { ++ KP_CLEAR(kp); ++ KP_CLEAR(kp2); ++ KP_CLEAR(kp_missed); ++#ifdef CONFIG_KRETPROBES ++ KP_CLEAR(rp.kp); ++ KP_CLEAR(rp2.kp); ++#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE ++ KP_CLEAR(rp3.kp); ++ KP_CLEAR(rp4.kp); ++#endif ++#endif ++ + target = kprobe_target; + target2 = kprobe_target2; + recursed_target = kprobe_recursed_target; +-- +2.53.0 + diff --git a/queue-7.0/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch b/queue-7.0/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch new file mode 100644 index 0000000000..8ffa5a6fd5 --- /dev/null +++ b/queue-7.0/thunderbolt-disable-clx-on-titan-ridge-based-devices.patch @@ -0,0 +1,53 @@ +From 77b1126b5d3fe8926895bac603578996e2e70fa4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 16:25:57 -0800 +Subject: thunderbolt: Disable CLx on Titan Ridge-based devices with old + firmware + +From: Rene Sapiens + +[ Upstream commit 59b03d12b1f6d14d936a3ebec225f8d914dc3b70 ] + +Thunderbolt 3 devices based on Titan Ridge routers with NVM firmware +version < 0x65 have been observed to become unstable when CL states are +enabled. This can lead to link disconnect events and the device failing +to enumerate. + +Enable CLx on Titan Ridge only when the running NVM firmware version +is >= 0x65. + +Signed-off-by: Rene Sapiens +Signed-off-by: Mika Westerberg +Signed-off-by: Sasha Levin +--- + drivers/thunderbolt/quirks.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c +index e81de9c30eac9..9f7914ac2f48c 100644 +--- a/drivers/thunderbolt/quirks.c ++++ b/drivers/thunderbolt/quirks.c +@@ -23,6 +23,9 @@ static void quirk_dp_credit_allocation(struct tb_switch *sw) + + static void quirk_clx_disable(struct tb_switch *sw) + { ++ if (tb_switch_is_titan_ridge(sw) && sw->nvm && sw->nvm->major >= 0x65) ++ return; ++ + sw->quirks |= QUIRK_NO_CLX; + tb_sw_dbg(sw, "disabling CL states\n"); + } +@@ -61,6 +64,10 @@ static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link }, + { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link }, ++ ++ /* Intel Titan Ridge CLx is unstable on early firmware versions */ ++ { 0x8086, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE, 0x0000, 0x0000, ++ quirk_clx_disable }, + /* + * Intel Goshen Ridge NVM 27 and before report wrong number of + * DP buffers. +-- +2.53.0 + diff --git a/queue-7.0/tools-power-x86-intel-speed-select-avoid-current-bas.patch b/queue-7.0/tools-power-x86-intel-speed-select-avoid-current-bas.patch new file mode 100644 index 0000000000..a5f018c3ae --- /dev/null +++ b/queue-7.0/tools-power-x86-intel-speed-select-avoid-current-bas.patch @@ -0,0 +1,78 @@ +From 87cfc4e5973f9580ea00a4cad7b69f4100101468 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 12:41:08 -0700 +Subject: tools/power/x86/intel-speed-select: Avoid current base freq as + maximum + +From: Srinivas Pandruvada + +[ Upstream commit ae67f582398611b9f67c06961e292e3a2612346d ] + +SST-PP level change results in online/offline of CPUs with -o option. +The Linux intel-pstate driver internally stores the current HWP_REQ MSR +value during offline and restores them during online. + +It is possible that during SST-PP level change, the new HWP_CAP limits +can be updated. So, when a CPU is online, the HWP_REQ MSR should be +updated to new values based on HWP_CAP values. + +This is particularly problematic when either turbo is disabled or the +current HWP_REQ value (stored before online) is less than the base +frequency from the updated HWP_CAP MSR guaranteed value. If the HWP_REQ +MSR is not updated, then the performance will be limited to the value +before perf level change. + +Hence the tool updates cpufreq scaling_max_freq to the newer +base_frequency value in this case. This step is not required when HWP +interrupts are enabled, as the perf level change should result in a new +interrupt with HWP_GUARANTEED_PERF_CHANGE_STATUS and the intel_pstate +driver will update to new limits. + +But the tool needs to handle the case when HWP interrupts are not +enabled but there is no way for the tool to know that HWP interrupts are +enabled or not. So, it has to still update the scaling_max_freq. + +With the QOS changes in the kernel, user space writes to scaling_max_freq +are treated as hard limits. So, when base frequency is increased with +SST-BF enabled, the cpufreq subsystem will still not allow setting to the +SST-BF high priority core frequency. So, the HWP_REQ MSR will still be +capped to the user-set scaling_max_freq after SST-PP level change. + +To address this, instead of setting scaling_max_freq to the current HWP_CAP +highest frequency, set it to the maximum integer value to set the QOS limit +as unconstrained. In this case, the actual HWP_REQ maximum frequency will +still be capped to HWP_CAP highest performance by the intel-pstate driver. +So, it will not result in invalid HWP_REQ values. + +Signed-off-by: Srinivas Pandruvada +Signed-off-by: Sasha Levin +--- + tools/power/x86/intel-speed-select/isst-config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c +index dd9056ddb016e..652ef1f567ad8 100644 +--- a/tools/power/x86/intel-speed-select/isst-config.c ++++ b/tools/power/x86/intel-speed-select/isst-config.c +@@ -1744,6 +1744,9 @@ static int no_turbo(void) + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); + } + ++#define U32_MAX ((unsigned int)~0U) ++#define S32_MAX ((int)(U32_MAX >> 1)) ++ + static void adjust_scaling_max_from_base_freq(int cpu) + { + int base_freq, scaling_max_freq; +@@ -1751,7 +1754,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) +- set_cpufreq_scaling_min_max(cpu, 1, base_freq); ++ set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); + } + + static void adjust_scaling_min_from_base_freq(int cpu) +-- +2.53.0 + diff --git a/queue-7.0/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch b/queue-7.0/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch new file mode 100644 index 0000000000..6dd82cf987 --- /dev/null +++ b/queue-7.0/tty-serial-imx-keep-dma-request-disabled-before-dma-.patch @@ -0,0 +1,57 @@ +From 393773a782764d67e00b5775c3c4057d4cdbf5e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:45:26 +0800 +Subject: tty: serial: imx: keep dma request disabled before dma transfer setup + +From: Robin Gong + +[ Upstream commit 74e0c9f0528bcd597cb1299a027d7be27d1c27d9 ] + +Since sdma hardware configure postpone to transfer phase, have to +disable dma request before dma transfer setup because there is a +hardware limitation on sdma event enable(ENBLn) as below. + +Refer SDMA 2.6.28 Channel Enable RAM (SDMAARMx_CHNENBLn) section: +"It is thus essential for the Arm platform to program them before any +DMA request is triggered to the SDMA, otherwise an unpredictable +combination of channels may be started." + +Signed-off-by: Robin Gong +Signed-off-by: Sherry Sun +Link: https://patch.msgid.link/20260312094526.297348-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/imx.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index c488e5d372ffd..251a50c8aa387 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -1442,9 +1442,9 @@ static void imx_uart_enable_dma(struct imx_port *sport) + + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + +- /* set UCR1 */ ++ /* set UCR1 except TXDMAEN which would be enabled in imx_uart_dma_tx */ + ucr1 = imx_uart_readl(sport, UCR1); +- ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; ++ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); + + sport->dma_is_enabled = 1; +@@ -1567,8 +1567,9 @@ static int imx_uart_startup(struct uart_port *port) + imx_uart_enable_ms(&sport->port); + + if (dma_is_inited) { +- imx_uart_enable_dma(sport); ++ /* Note: enable dma request after transfer start! */ + imx_uart_start_rx_dma(sport); ++ imx_uart_enable_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; +-- +2.53.0 + diff --git a/queue-7.0/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch b/queue-7.0/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch new file mode 100644 index 0000000000..a7e0322b05 --- /dev/null +++ b/queue-7.0/tty-serial-samsung_tty-avoid-dev_dbg-deadlock.patch @@ -0,0 +1,63 @@ +From 3d10795d05ef3dc8493072f6bb973a3312a9af86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 11:28:54 +0000 +Subject: tty: serial: samsung_tty: avoid dev_dbg deadlock + +From: Alyssa Milburn + +[ Upstream commit 43c2b86ff633c34831c8430925ba73d7c20da1ad ] + +commit a05025d0ce72 ("tty: serial: samsung_tty: use standard +debugging macros") changed the debug prints to dev_dbg, which can +result in deadlocks: + +s3c24xx_serial_set_termios can be called with the port lock, and then +calls dev_dbg, which needs the console mutex. At the same time, +s3c24xx_serial_console_write can be called with the console lock +(e.g., inside console_unlock), and needs the port lock. + +To avoid this, move one dev_dbg call and just delete the other. + +Signed-off-by: Alyssa Milburn +Link: https://patch.msgid.link/aXny9km6N1v9eoXU@zall.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/samsung_tty.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index c1fabad6ba1fa..e27806bf2cf3e 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -1562,12 +1562,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + ulcon |= S3C2410_LCON_PNONE; + } + +- uart_port_lock_irqsave(port, &flags); +- + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", + ulcon, quot, udivslot); + ++ uart_port_lock_irqsave(port, &flags); ++ + wr_regl(port, S3C2410_ULCON, ulcon); + wr_regl(port, S3C2410_UBRDIV, quot); + +@@ -1587,12 +1587,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + if (ourport->info->has_divslot) + wr_regl(port, S3C2443_DIVSLOT, udivslot); + +- dev_dbg(port->dev, +- "uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", +- rd_regl(port, S3C2410_ULCON), +- rd_regl(port, S3C2410_UCON), +- rd_regl(port, S3C2410_UFCON)); +- + /* + * Update the per-port timeout. + */ +-- +2.53.0 + diff --git a/queue-7.0/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch b/queue-7.0/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch new file mode 100644 index 0000000000..554d8030b9 --- /dev/null +++ b/queue-7.0/ublk-reject-max_sectors-smaller-than-page_sectors-in.patch @@ -0,0 +1,52 @@ +From ac337977e3ab2742d5856cc4dad5632b42f72ec5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 May 2026 22:48:43 +0800 +Subject: ublk: reject max_sectors smaller than PAGE_SECTORS in parameter + validation + +From: Ming Lei + +[ Upstream commit 1860c2f85922917d8a46f16a6f4bd2298ffa0fb5 ] + +blk_validate_limits() requires max_hw_sectors >= PAGE_SECTORS and fires +a WARN_ON_ONCE if this invariant is violated. ublk_validate_params() +only checked the upper bound of max_sectors against max_io_buf_bytes, +allowing userspace to pass small values (including zero) that trigger +the warning when blk_mq_alloc_disk() is called from +ublk_ctrl_start_dev(). + +Before 494ea040bcb5, ublk used blk_queue_max_hw_sectors() which silently +clamped small values up to PAGE_SECTORS. The conversion to passing +queue_limits directly to blk_mq_alloc_disk() lost that clamping and now +hits blk_validate_limits()'s WARN_ON_ONCE instead. + +Validate that max_sectors is at least PAGE_SECTORS in +ublk_validate_params() so invalid values are rejected early with +-EINVAL instead of reaching the block layer. + +Fixes: 494ea040bcb5 ("ublk: pass queue_limits to blk_mq_alloc_disk") +Signed-off-by: Ming Lei +Link: https://patch.msgid.link/20260510144843.769031-1-tom.leiming@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 0bdb804fca839..e5f4942d99113 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -868,6 +868,9 @@ static int ublk_validate_params(const struct ublk_device *ub) + if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9)) + return -EINVAL; + ++ if (p->max_sectors < PAGE_SECTORS) ++ return -EINVAL; ++ + if (ublk_dev_is_zoned(ub) && !p->chunk_sectors) + return -EINVAL; + } else +-- +2.53.0 + diff --git a/queue-7.0/um-avoid-struct-sigcontext-redefinition-with-musl.patch b/queue-7.0/um-avoid-struct-sigcontext-redefinition-with-musl.patch new file mode 100644 index 0000000000..6fbc2397dc --- /dev/null +++ b/queue-7.0/um-avoid-struct-sigcontext-redefinition-with-musl.patch @@ -0,0 +1,62 @@ +From 5fe73bb0b49b91265225b98413a286f8b808e5c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:28:03 +0800 +Subject: um: avoid struct sigcontext redefinition with musl + +From: Marcel W. Wysocki + +[ Upstream commit d46dfb369a4627d90efc2c2ffbe29e38e3e74286 ] + +mcontext.c includes both and . +With musl libc, this causes a struct sigcontext redefinition error: + + pulls in musl's , which defines + struct sigcontext directly. The kernel's then + provides a second, conflicting definition of the same struct. + +With glibc this does not conflict because glibc's signal headers +source their struct sigcontext from the kernel's own UAPI headers, +so the include guard in makes the second +inclusion a no-op. + +mcontext.c does not actually use struct sigcontext by name -- it +only needs the FP-state types (_fpstate, _xstate, etc.) that are +defined in independently of the sigcontext +struct. + +Temporarily rename sigcontext to __kernel_sigcontext during the +inclusion of so that the kernel's definition +does not collide with musl's. The #undef restores normal name +resolution immediately afterward. + +No functional change with glibc; fixes the build with musl. + +Signed-off-by: Marcel W. Wysocki +Link: https://patch.msgid.link/20260215142803.1455757-2-maci.stgn@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/x86/um/os-Linux/mcontext.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c +index a21403df66637..b1580df80b3fc 100644 +--- a/arch/x86/um/os-Linux/mcontext.c ++++ b/arch/x86/um/os-Linux/mcontext.c +@@ -4,7 +4,13 @@ + #include + #include + #include ++/* ++ * musl defines struct sigcontext in . Rename the kernel's ++ * copy to avoid redefinition while keeping the FP-state types available. ++ */ ++#define sigcontext __kernel_sigcontext + #include ++#undef sigcontext + #include + #include + #include +-- +2.53.0 + diff --git a/queue-7.0/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch b/queue-7.0/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch new file mode 100644 index 0000000000..b26f2a141b --- /dev/null +++ b/queue-7.0/um-disable-gcov_profile_all-on-32-bit-uml-with-clang.patch @@ -0,0 +1,60 @@ +From d207052114358150f069757ae57b7e8b65a96b1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:20:42 -0700 +Subject: um: Disable GCOV_PROFILE_ALL on 32-bit UML with Clang 20/21 + +From: Kees Cook + +[ Upstream commit 6522fe5c1b007c376fc5f2de1016c99a18b0af8e ] + +Clang 20 and 21 miscompute __builtin_object_size() when -fprofile-arcs +is active on 32-bit UML targets, which passes incorrect object size +calculations for local variables through always_inline copy_to_user() +and check_copy_size(), causing spurious compile-time errors: + + include/linux/ucopysize.h:52:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small + +The regression was introduced in LLVM commit 02b8ee281947 ("[llvm] +Improve llvm.objectsize computation by computing GEP, alloca and malloc +parameters bound"), which shipped in Clang 20. It was fixed in LLVM +by commit 45b697e610fd ("[MemoryBuiltins] Consider index type size +when aggregating gep offsets"), which was backported to the LLVM 22.x +release branch. + +The bug requires 32-bit UML + GCOV_PROFILE_ALL (which uses -fprofile-arcs), +though the exact trigger depends on optimizer decisions influenced by other +enabled configs. + +Prevent the bad combination by disabling UML's ARCH_HAS_GCOV_PROFILE_ALL +on 32-bit when using Clang 20.x or 21.x. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604030531.O6FveVgn-lkp@intel.com/ +Suggested-by: Nathan Chancellor +Assisted-by: Claude:claude-opus-4-6[1m] +Signed-off-by: Kees Cook +Link: https://patch.msgid.link/20260409052038.make.995-kees@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/Kconfig | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/um/Kconfig b/arch/um/Kconfig +index 098cda44db225..d9541d13d9eb0 100644 +--- a/arch/um/Kconfig ++++ b/arch/um/Kconfig +@@ -11,7 +11,9 @@ config UML + select ARCH_HAS_CACHE_LINE_SIZE + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +- select ARCH_HAS_GCOV_PROFILE_ALL ++ # Clang 20 & 21 miscompute __builtin_object_size() under -fprofile-arcs ++ # on 32-bit, causing spurious compile-time errors in check_copy_size(). ++ select ARCH_HAS_GCOV_PROFILE_ALL if !(!64BIT && CLANG_VERSION >= 200000 && CLANG_VERSION < 220100) + select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER +-- +2.53.0 + diff --git a/queue-7.0/um-fix-address-of-cmsg_data-rvalue-in-stub.patch b/queue-7.0/um-fix-address-of-cmsg_data-rvalue-in-stub.patch new file mode 100644 index 0000000000..1eb62acc64 --- /dev/null +++ b/queue-7.0/um-fix-address-of-cmsg_data-rvalue-in-stub.patch @@ -0,0 +1,66 @@ +From 6a888a715d9c28d6659e7bd284e7b8a79b3ec9e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 22:28:02 +0800 +Subject: um: fix address-of CMSG_DATA() rvalue in stub + +From: Marcel W. Wysocki + +[ Upstream commit 4076f7329832074196e050def49d22265fce2021 ] + +The UML stub takes the address of CMSG_DATA(fd_msg): + + fd_map = (void *)&CMSG_DATA(fd_msg); + +CMSG_DATA() is specified by POSIX to return unsigned char *. Taking +its address is semantically wrong -- the intent is to get a pointer +to the control message data, which is exactly what CMSG_DATA() +already returns. + +This happens to compile with glibc because glibc's primary +CMSG_DATA definition accesses a flexible array member: + + #define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data) + +An array lvalue can have its address taken, and &array yields the +same address as array. However, glibc also has an alternative +definition that uses pointer arithmetic (returning an rvalue), and +musl's definition always uses pointer arithmetic: + + /* musl */ + #define CMSG_DATA(cmsg) \ + ((unsigned char *)(((struct cmsghdr *)(cmsg)) + 1)) + +Taking the address of an rvalue is a hard error in C, so the +current code fails to compile with musl libc. + +Remove the erroneous & operator. The resulting code is correct +regardless of the CMSG_DATA implementation -- it simply assigns the +data pointer, which is what the subsequent code (fd_map[--num_fds]) +expects. + +No functional change with glibc; fixes the build with musl. + +Signed-off-by: Marcel W. Wysocki +Link: https://patch.msgid.link/20260215142803.1455757-1-maci.stgn@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/kernel/skas/stub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c +index 67cab46a602cf..e09216a20cb57 100644 +--- a/arch/um/kernel/skas/stub.c ++++ b/arch/um/kernel/skas/stub.c +@@ -146,7 +146,7 @@ stub_signal_interrupt(int sig, siginfo_t *info, void *p) + /* Receive the FDs */ + num_fds = 0; + fd_msg = msghdr.msg_control; +- fd_map = (void *)&CMSG_DATA(fd_msg); ++ fd_map = (void *)CMSG_DATA(fd_msg); + if (res == iov.iov_len && msghdr.msg_controllen > sizeof(struct cmsghdr)) + num_fds = (fd_msg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + +-- +2.53.0 + diff --git a/queue-7.0/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch b/queue-7.0/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch new file mode 100644 index 0000000000..701d89dd66 --- /dev/null +++ b/queue-7.0/usb-dwc3-support-usb3340x-ulpi-phy-high-speed-negoti.patch @@ -0,0 +1,155 @@ +From 1aeec916e6c944a3a1e419e04871e7edc1c66e56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 13:14:52 +0100 +Subject: usb: dwc3: Support USB3340x ULPI PHY high-speed negotiation. + +From: Ingo Rohloff + +[ Upstream commit a28de63356575612954d4e5d5f48a2488f50e16d ] + +The Microchip USB3340x ULPI PHY requires a delay when switching to the +high-speed transmitter. See: + http://ww1.microchip.com/downloads/en/DeviceDoc/80000645A.pdf + Module 2 "Device Enumeration Failure with Link IP Systems" + +For details on the behavior and fix, refer to the AMD (formerly Xilinx) +forum post: "USB stuck in full speed mode with USB3340 ULPI PHY, ZynqMP." + +This patch uses the USB PHY Vendor-ID and Product-ID to detect the +USB3340 PHY and then applies the necessary fix if this PHY is found. + +Signed-off-by: Ingo Rohloff +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260305121452.54082-2-ingo.rohloff@lauterbach.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/core.c | 20 ++++++++++++++++++++ + drivers/usb/dwc3/core.h | 4 ++++ + drivers/usb/dwc3/ulpi.c | 25 +++++++++++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 0d3c7e7b2262f..1b983a5ece986 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -782,6 +782,24 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + return 0; + } + ++static void dwc3_ulpi_setup(struct dwc3 *dwc) ++{ ++ int index; ++ u32 reg; ++ ++ /* Don't do anything if there is no ULPI PHY */ ++ if (!dwc->ulpi) ++ return; ++ ++ if (dwc->enable_usb2_transceiver_delay) { ++ for (index = 0; index < dwc->num_usb2_ports; index++) { ++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); ++ reg |= DWC3_GUSB2PHYCFG_XCVRDLY; ++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); ++ } ++ } ++} ++ + /** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -1357,6 +1375,8 @@ int dwc3_core_init(struct dwc3 *dwc) + dwc->ulpi_ready = true; + } + ++ dwc3_ulpi_setup(dwc); ++ + if (!dwc->phys_ready) { + ret = dwc3_core_get_phy(dwc); + if (ret) +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index a35b3db1f9f3e..a39bf284c763f 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -302,6 +302,7 @@ + #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) + #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) + #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) ++#define DWC3_GUSB2PHYCFG_XCVRDLY BIT(9) + #define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3) + #define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) + #define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10) +@@ -1161,6 +1162,8 @@ struct dwc3_glue_ops { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @enable_usb2_transceiver_delay: Set to insert a delay before the ++ * assertion of the TxValid signal during a HS Chirp. + * @sys_wakeup: set if the device may do system wakeup. + * @wakeup_configured: set if the device is configured for remote wakeup. + * @suspended: set to track suspend event due to U3/L2. +@@ -1403,6 +1406,7 @@ struct dwc3 { + unsigned dis_metastability_quirk:1; + + unsigned dis_split_quirk:1; ++ unsigned enable_usb2_transceiver_delay:1; + unsigned async_callbacks:1; + unsigned sys_wakeup:1; + unsigned wakeup_configured:1; +diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c +index 57daad15f502d..a256b7f5d78b4 100644 +--- a/drivers/usb/dwc3/ulpi.c ++++ b/drivers/usb/dwc3/ulpi.c +@@ -10,10 +10,13 @@ + #include + #include + #include ++#include + + #include "core.h" + #include "io.h" + ++#define USB_VENDOR_MICROCHIP 0x0424 ++ + #define DWC3_ULPI_ADDR(a) \ + ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \ + DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ +@@ -83,6 +86,26 @@ static const struct ulpi_ops dwc3_ulpi_ops = { + .write = dwc3_ulpi_write, + }; + ++static void dwc3_ulpi_detect_config(struct dwc3 *dwc) ++{ ++ struct ulpi *ulpi = dwc->ulpi; ++ ++ switch (ulpi->id.vendor) { ++ case USB_VENDOR_MICROCHIP: ++ switch (ulpi->id.product) { ++ case 0x0009: ++ /* Microchip USB3340 ULPI PHY */ ++ dwc->enable_usb2_transceiver_delay = true; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ + int dwc3_ulpi_init(struct dwc3 *dwc) + { + /* Register the interface */ +@@ -92,6 +115,8 @@ int dwc3_ulpi_init(struct dwc3 *dwc) + return PTR_ERR(dwc->ulpi); + } + ++ dwc3_ulpi_detect_config(dwc); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/usb-gadget-bdc-validate-status-report-endpoint-indic.patch b/queue-7.0/usb-gadget-bdc-validate-status-report-endpoint-indic.patch new file mode 100644 index 0000000000..4b6eabd73f --- /dev/null +++ b/queue-7.0/usb-gadget-bdc-validate-status-report-endpoint-indic.patch @@ -0,0 +1,46 @@ +From 78147882f27d2e6577faf4b67e1c021d73bdba89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:17:30 +0800 +Subject: usb: gadget: bdc: validate status-report endpoint indices + +From: Pengpeng Hou + +[ Upstream commit a402532ab855620e02a16950aea86fc621c6f87c ] + +bdc_sr_xsf() decodes a 5-bit endpoint number from the hardware status +report and uses it to index bdc->bdc_ep_array[] directly. The array is +only allocated to bdc->num_eps for the current controller instance, so a +status report can carry an endpoint number that still fits the 5-bit +field but does not fit the runtime-sized endpoint table. + +Reject status reports whose endpoint number is outside bdc->num_eps +before indexing the endpoint array. + +Signed-off-by: Pengpeng Hou +Reviewed-by: Florian Fainelli +Tested-by: Justin Chen +Link: https://patch.msgid.link/20260323121730.75245-1-pengpeng@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c +index c0ab3347059a0..a7a22e5ec47ba 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c +@@ -1647,6 +1647,10 @@ void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport) + u8 ep_num; + + ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f; ++ if (ep_num >= bdc->num_eps) { ++ dev_err(bdc->dev, "xsf for invalid ep %u\n", ep_num); ++ return; ++ } + ep = bdc->bdc_ep_array[ep_num]; + if (!ep || !(ep->flags & BDC_EP_ENABLED)) { + dev_err(bdc->dev, "xsf for ep not enabled\n"); +-- +2.53.0 + diff --git a/queue-7.0/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch b/queue-7.0/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch new file mode 100644 index 0000000000..cf56ffcf20 --- /dev/null +++ b/queue-7.0/usb-usbip-fix-integer-overflow-in-usbip_recv_iso.patch @@ -0,0 +1,83 @@ +From 661cf5e4451e01b9504bbeee76790a7c5cb0ab3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:38 +0300 +Subject: usb: usbip: fix integer overflow in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 1897852293faca4c2be51e0a19f739622f771623 ] + +usbip_recv_iso() computes the iso descriptor buffer size as: + + int size = np * sizeof(*iso); + +where np comes straight from the wire (urb->number_of_packets, set by +usbip_pack_ret_submit() before we get here). With np = 0x10000001 and +sizeof(*iso) == 16 the product is 0x100000010 which truncates to 16 on +a 32-bit int. kzalloc(16) succeeds but the following receive loop +writes np * 16 bytes into it - game over. + +USBIP_MAX_ISO_PACKETS (1024) already exists in usbip_common.h for the +submit path but was never enforced on the receive side. + +Clamp np to [1, USBIP_MAX_ISO_PACKETS] and switch to kcalloc() so +the allocator itself can catch overflows in the future. Fold the +existing np == 0 early return into the new bounds check. + +usbip_pack_ret_submit() already copied the bogus np into +urb->number_of_packets before we run, so just returning -EPROTO is +not enough - processcompl() in the HCD will still iterate that many +iso_frame_desc entries when it completes the failed URB. Zero out +urb->number_of_packets before bailing to prevent that secondary crash +(confirmed on 6.12.0, processcompl+0x63 with CR2 in unmapped slab). + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-1-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8f47a3b87871..f8d1d1167ef4b 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -674,7 +674,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + void *buff; + struct usbip_iso_packet_descriptor *iso; + int np = urb->number_of_packets; +- int size = np * sizeof(*iso); ++ int size; + int i; + int ret; + u32 total_length = 0; +@@ -682,11 +682,21 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + if (!usb_pipeisoc(urb->pipe)) + return 0; + +- /* my Bluetooth dongle gets ISO URBs which are np = 0 */ +- if (np == 0) +- return 0; ++ if (np <= 0 || np > USBIP_MAX_ISO_PACKETS) { ++ dev_err(&urb->dev->dev, ++ "recv iso: invalid number_of_packets %d\n", np); ++ /* ++ * usbip_pack_ret_submit() already set urb->number_of_packets ++ * from the wire. Zero it so processcompl() does not iterate ++ * OOB descriptors on the way out. ++ */ ++ urb->number_of_packets = 0; ++ return -EPROTO; ++ } ++ ++ size = np * sizeof(*iso); + +- buff = kzalloc(size, GFP_KERNEL); ++ buff = kcalloc(np, sizeof(*iso), GFP_KERNEL); + if (!buff) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-7.0/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch b/queue-7.0/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch new file mode 100644 index 0000000000..cd70a361a5 --- /dev/null +++ b/queue-7.0/usb-usbip-fix-oob-read-write-in-usbip_pad_iso.patch @@ -0,0 +1,87 @@ +From e4b775d2d34f580aa52fe0b8baad30af6496b781 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:40 +0300 +Subject: usb: usbip: fix OOB read/write in usbip_pad_iso() + +From: Kelvin Mbogo + +[ Upstream commit 74a2287209a858470d15e2996ead2337bd293ff4 ] + +usbip_pad_iso() repositions ISO frame data within the transfer buffer +via memmove(). Neither the source offset (actualoffset, derived by +subtracting wire-supplied actual_length values) nor the destination +offset (iso_frame_desc[i].offset, taken directly from the wire) is +bounds-checked. + +If a crafted actual_length wraps actualoffset negative through the +subtraction (see patch 2/3 for the root cause), the memmove source +points before the allocation - slab OOB read, data returned to +userspace. + +Independently, iso_frame_desc[i].offset is never validated against +transfer_buffer_length. Setting offset past the end of the buffer +gives a fully controlled OOB write into whatever sits next in the +slab - confirmed with offset=400 on a 392-byte buffer, 64-byte write. + +Add bounds checks for both the source and destination ranges before +each memmove call. Use unsigned comparisons after the sign check on +actualoffset to avoid signed/unsigned conversion surprises. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-3-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 36 ++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index f8d1d1167ef4b..a5837c0feb058 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -782,6 +782,42 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; ++ ++ /* ++ * Validate source range: actualoffset can go negative ++ * via crafted actual_length values from the wire. ++ */ ++ if (actualoffset < 0 || ++ (unsigned int)actualoffset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ (unsigned int)actualoffset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad src off=%d len=%u bufsz=%d\n", ++ actualoffset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ ++ /* ++ * Validate destination range: iso_frame_desc[i].offset ++ * is wire-supplied and must not exceed the buffer. ++ */ ++ if (urb->iso_frame_desc[i].offset > ++ (unsigned int)urb->transfer_buffer_length || ++ urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length - ++ urb->iso_frame_desc[i].offset) { ++ dev_err(&urb->dev->dev, ++ "pad_iso: bad dst off=%u len=%u bufsz=%d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ return; ++ } ++ + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); +-- +2.53.0 + diff --git a/queue-7.0/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch b/queue-7.0/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch new file mode 100644 index 0000000000..a46d5af46a --- /dev/null +++ b/queue-7.0/usb-usbip-validate-iso-frame-actual_length-in-usbip_.patch @@ -0,0 +1,76 @@ +From f25f631d396b799e4aa56d316f0ac237dea84af9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 13:36:39 +0300 +Subject: usb: usbip: validate iso frame actual_length in usbip_recv_iso() + +From: Kelvin Mbogo + +[ Upstream commit 591c1d972d8f19862ecd7279c7ef4df48b0a9b33 ] + +usbip_recv_iso() sums each frame's actual_length into an int +accumulator without checking the individual values first: + + total_length += urb->iso_frame_desc[i].actual_length; + +A malicious server can send actual_length = 0xFFFFFFFC for one frame +and a small value for the other, making the signed sum wrap around to +match urb->actual_length. The sanity check passes, and usbip_pad_iso() +later computes a negative actualoffset, feeding it to memmove() as a +source pointer - reads before the allocation, leaked to userspace via +USBDEVFS_REAPURB. + +Reject any frame whose actual_length exceeds transfer_buffer_length +(one frame can't carry more data than the whole buffer), and widen the +accumulator to u32 so that many moderately-large frames can't wrap it +either. + +Signed-off-by: Kelvin Mbogo +Link: https://patch.msgid.link/20260325103640.8090-2-addcontent08@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/usbip/usbip_common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c +index ba9e7c616e129..f8f47a3b87871 100644 +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -677,7 +677,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + int size = np * sizeof(*iso); + int i; + int ret; +- int total_length = 0; ++ u32 total_length = 0; + + if (!usb_pipeisoc(urb->pipe)) + return 0; +@@ -708,14 +708,23 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) + for (i = 0; i < np; i++) { + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); ++ if (urb->iso_frame_desc[i].actual_length > ++ (unsigned int)urb->transfer_buffer_length) { ++ dev_err(&urb->dev->dev, ++ "recv iso: frame actual_length %u exceeds buffer %d\n", ++ urb->iso_frame_desc[i].actual_length, ++ urb->transfer_buffer_length); ++ kfree(buff); ++ return -EPROTO; ++ } + total_length += urb->iso_frame_desc[i].actual_length; + } + + kfree(buff); + +- if (total_length != urb->actual_length) { ++ if (total_length != (u32)urb->actual_length) { + dev_err(&urb->dev->dev, +- "total length of iso packets %d not equal to actual length of buffer %d\n", ++ "total length of iso packets %u not equal to actual length of buffer %d\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) +-- +2.53.0 + diff --git a/queue-7.0/vfio-pci-check-bar-resources-before-exporting-a-dmab.patch b/queue-7.0/vfio-pci-check-bar-resources-before-exporting-a-dmab.patch new file mode 100644 index 0000000000..390f9f7719 --- /dev/null +++ b/queue-7.0/vfio-pci-check-bar-resources-before-exporting-a-dmab.patch @@ -0,0 +1,46 @@ +From b665e5e5fc3d6f79d06a6899008f003c6d94791d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 May 2026 07:58:24 -0700 +Subject: vfio/pci: Check BAR resources before exporting a DMABUF + +From: Matt Evans + +[ Upstream commit 702809dabdecca807bdd50cfdcc1c980feb2ba62 ] + +A DMABUF exports access to BAR resources and, although they are +requested at startup time, we need to ensure they really were reserved +before exporting. Otherwise, it's possible to access unreserved +resources through the export. + +Add a check to the DMABUF-creation path. + +Fixes: 5d74781ebc86c ("vfio/pci: Add dma-buf export support for MMIO regions") +Signed-off-by: Matt Evans +Link: https://lore.kernel.org/r/20260511145829.2993601-3-mattev@meta.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_dmabuf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c +index b1d658b8f7b51..05385b63e2baf 100644 +--- a/drivers/vfio/pci/vfio_pci_dmabuf.c ++++ b/drivers/vfio/pci/vfio_pci_dmabuf.c +@@ -232,9 +232,11 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, + return -EINVAL; + + /* +- * For PCI the region_index is the BAR number like everything else. ++ * For PCI the region_index is the BAR number like everything ++ * else. Check that PCI resources have been claimed for it. + */ +- if (get_dma_buf.region_index >= VFIO_PCI_ROM_REGION_INDEX) ++ if (get_dma_buf.region_index >= VFIO_PCI_ROM_REGION_INDEX || ++ vfio_pci_core_setup_barmap(vdev, get_dma_buf.region_index)) + return -ENODEV; + + dma_ranges = memdup_array_user(&arg->dma_ranges, get_dma_buf.nr_ranges, +-- +2.53.0 + diff --git a/queue-7.0/virtiofs-add-fuse-protocol-validation.patch b/queue-7.0/virtiofs-add-fuse-protocol-validation.patch new file mode 100644 index 0000000000..8666707909 --- /dev/null +++ b/queue-7.0/virtiofs-add-fuse-protocol-validation.patch @@ -0,0 +1,86 @@ +From ae97cc0bbbfdd5419638034b375ee38527f01537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 07:31:58 +0000 +Subject: virtiofs: add FUSE protocol validation + +From: Yuto Ohnuki + +[ Upstream commit 68b69fa0edb241a946cd4c850110990f30705164 ] + +Add virtio_fs_verify_response() to validate that the server properly +follows the FUSE protocol by checking: + +- Response length is at least sizeof(struct fuse_out_header). +- oh.len matches the actual response length. +- oh.unique matches the request's unique identifier. + +On validation failure, set error to -EIO and normalize oh.len to prevent +underflow in copy_args_from_argbuf(). + +Addresses the TODO comment in virtio_fs_request_complete(). + +Signed-off-by: Yuto Ohnuki +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/virtio_fs.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c +index 057e65b51b99d..2f7485ffac527 100644 +--- a/fs/fuse/virtio_fs.c ++++ b/fs/fuse/virtio_fs.c +@@ -758,6 +758,27 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) + req->argbuf = NULL; + } + ++/* Verify that the server properly follows the FUSE protocol */ ++static bool virtio_fs_verify_response(struct fuse_req *req, unsigned int len) ++{ ++ struct fuse_out_header *oh = &req->out.h; ++ ++ if (len < sizeof(*oh)) { ++ pr_warn("virtio-fs: response too short (%u)\n", len); ++ return false; ++ } ++ if (oh->len != len) { ++ pr_warn("virtio-fs: oh.len mismatch (%u != %u)\n", oh->len, len); ++ return false; ++ } ++ if (oh->unique != req->in.h.unique) { ++ pr_warn("virtio-fs: oh.unique mismatch (%llu != %llu)\n", ++ oh->unique, req->in.h.unique); ++ return false; ++ } ++ return true; ++} ++ + /* Work function for request completion */ + static void virtio_fs_request_complete(struct fuse_req *req, + struct virtio_fs_vq *fsvq) +@@ -767,10 +788,6 @@ static void virtio_fs_request_complete(struct fuse_req *req, + unsigned int len, i, thislen; + struct folio *folio; + +- /* +- * TODO verify that server properly follows FUSE protocol +- * (oh.uniq, oh.len) +- */ + args = req->args; + copy_args_from_argbuf(args, req); + +@@ -824,6 +841,10 @@ static void virtio_fs_requests_done_work(struct work_struct *work) + virtqueue_disable_cb(vq); + + while ((req = virtqueue_get_buf(vq, &len)) != NULL) { ++ if (!virtio_fs_verify_response(req, len)) { ++ req->out.h.error = -EIO; ++ req->out.h.len = sizeof(struct fuse_out_header); ++ } + spin_lock(&fpq->lock); + list_move_tail(&req->list, &reqs); + spin_unlock(&fpq->lock); +-- +2.53.0 + diff --git a/queue-7.0/vmxnet3-suppress-page-allocation-warning-for-massive.patch b/queue-7.0/vmxnet3-suppress-page-allocation-warning-for-massive.patch new file mode 100644 index 0000000000..860c407d8f --- /dev/null +++ b/queue-7.0/vmxnet3-suppress-page-allocation-warning-for-massive.patch @@ -0,0 +1,76 @@ +From bfdfea8c69b4d4dd7aafc0067d52cb02bc583f27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:31:21 -0500 +Subject: vmxnet3: Suppress page allocation warning for massive Rx Data ring + +From: Aaron Tomlin + +[ Upstream commit c31770c49348fb019167fa95119f330597c99193 ] + +The vmxnet3 driver supports an Rx Data ring (rx-mini) to optimise the +processing of small packets. The size of this ring's DMA-coherent memory +allocation is determined by the product of the primary Rx ring size and +the data ring descriptor size: + + sz = rq->rx_ring[0].size * rq->data_ring.desc_size; + +When a user configures the maximum supported parameters via ethtool +(rx_ring[0].size = 4096, data_ring.desc_size = 2048), the required +contiguous memory allocation reaches 8 MB (8,388,608 bytes). + +In environments lacking Contiguous Memory Allocator (CMA), +dma_alloc_coherent() falls back to the standard zone buddy allocator. An +8 MB allocation translates to a page order of 11, which strictly exceeds +the default MAX_PAGE_ORDER (10) on most architectures. + +Consequently, __alloc_pages_noprof() catches the oversize request and +triggers a loud kernel warning stack trace: + + WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp) + +This warning is unnecessary and alarming to system administrators because +the vmxnet3 driver already handles this allocation failure gracefully. +If dma_alloc_coherent() returns NULL, the driver safely disables the +Rx Data ring (adapter->rxdataring_enabled = false) and falls back to +standard, streaming DMA packet processing. + +To resolve this, append the __GFP_NOWARN flag to the dma_alloc_coherent() +gfp_mask. This instructs the page allocator to silently fail the +allocation if it exceeds order limits or memory is too fragmented, +preventing the spurious warning stack trace. + +Furthermore, enhance the subsequent netdev_err() fallback message to +include the requested allocation size. This provides critical debugging +context to the administrator (e.g., revealing that an 8 MB allocation +was attempted and failed) without making hardcoded assumptions about +the state of the system's configurations. + +Reviewed-by: Jijie Shao +Signed-off-by: Aaron Tomlin +Link: https://patch.msgid.link/20260226163121.4045808-1-atomlin@atomlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 0572f6a9bdb62..40522afc05320 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -2268,10 +2268,10 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) + rq->data_ring.base = + dma_alloc_coherent(&adapter->pdev->dev, sz, + &rq->data_ring.basePA, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!rq->data_ring.base) { + netdev_err(adapter->netdev, +- "rx data ring will be disabled\n"); ++ "failed to allocate %zu bytes, rx data ring will be disabled\n", sz); + adapter->rxdataring_enabled = false; + } + } else { +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch b/queue-7.0/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch new file mode 100644 index 0000000000..b15dfa5ee1 --- /dev/null +++ b/queue-7.0/wifi-ath12k-fix-the-assignment-of-logical-link-index.patch @@ -0,0 +1,109 @@ +From 8856d6aa6fbfdfd26a4f8ebc24984d3c36ac561f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 09:49:11 +0530 +Subject: wifi: ath12k: Fix the assignment of logical link index + +From: Manish Dharanenthiran + +[ Upstream commit aecb569d7fb689e3e5b0005ca7bd0a2ef28915e8 ] + +Per-link logical index is assigned from the global counter, +ahsta->num_peer. This logical index is sent to firmware during peer +association. If there is a failure in creating a link station, +ath12k_mac_free_unassign_link_sta() clears the link, but does not decrement +the logical link index. This will result in a higher logical link index for +the next link station created. Also, if there is a leak in logical link +index as we assign the incremented num_peer, then the index can exceed the +maximum valid value of 15. + +As an example, let's say we have a 2 GHz + 5 GHz + 6 GHz MLO setup. So the +logical link indices that they have are 0, 1 and 2, respectively. If the +5 GHz link is removed, logical link index 1 becomes available, and num_peer +is not reduced to 2 and still remains at 3. If a new 5 GHz link is added +later, it gets the index 3, instead of reusing link index 1. Also, +num_peer is increased to 4, though only 3 links are present. + +To resolve these, create a bitmap, free_logical_link_idx, that tracks the +available logical link indices. When a link station is created, select the +first free logical index and when a link station is removed, mark its +logical link index as available by setting the bit. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manish Dharanenthiran +Signed-off-by: Roopni Devanathan +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260226041911.2434999-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/core.h | 2 +- + drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++++++++-- + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h +index 990934ec92fca..5498ff285102b 100644 +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -522,7 +522,7 @@ struct ath12k_sta { + u16 links_map; + u8 assoc_link_id; + u16 ml_peer_id; +- u8 num_peer; ++ u16 free_logical_link_idx_map; + + enum ieee80211_sta_state state; + }; +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index fa36e984c74b2..a32334bbd0943 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -6791,6 +6791,8 @@ static void ath12k_mac_free_unassign_link_sta(struct ath12k_hw *ah, + return; + + ahsta->links_map &= ~BIT(link_id); ++ ahsta->free_logical_link_idx_map |= BIT(arsta->link_idx); ++ + rcu_assign_pointer(ahsta->link[link_id], NULL); + synchronize_rcu(); + +@@ -7109,6 +7111,7 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta); + struct ieee80211_link_sta *link_sta; + struct ath12k_link_vif *arvif; ++ int link_idx; + + lockdep_assert_wiphy(ah->hw->wiphy); + +@@ -7127,8 +7130,16 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, + + ether_addr_copy(arsta->addr, link_sta->addr); + +- /* logical index of the link sta in order of creation */ +- arsta->link_idx = ahsta->num_peer++; ++ if (!ahsta->free_logical_link_idx_map) ++ return -ENOSPC; ++ ++ /* ++ * Allocate a logical link index by selecting the first available bit ++ * from the free logical index map ++ */ ++ link_idx = __ffs(ahsta->free_logical_link_idx_map); ++ ahsta->free_logical_link_idx_map &= ~BIT(link_idx); ++ arsta->link_idx = link_idx; + + arsta->link_id = link_id; + ahsta->links_map |= BIT(arsta->link_id); +@@ -7637,6 +7648,7 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, + if (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) { + memset(ahsta, 0, sizeof(*ahsta)); ++ ahsta->free_logical_link_idx_map = U16_MAX; + + arsta = &ahsta->deflink; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath12k-set-up-mlo-after-ssr.patch b/queue-7.0/wifi-ath12k-set-up-mlo-after-ssr.patch new file mode 100644 index 0000000000..62871156f5 --- /dev/null +++ b/queue-7.0/wifi-ath12k-set-up-mlo-after-ssr.patch @@ -0,0 +1,69 @@ +From 6801d4c2ed0c3be621a99347bce376122a25291a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:41:27 +0530 +Subject: wifi: ath12k: Set up MLO after SSR + +From: Ramya Gnanasekar + +[ Upstream commit f33a8e41826831fc8ceb5f62833488cd9388ed59 ] + +During recovery of an MLO setup from a core reset, +ATH12K_GROUP_FLAG_REGISTERED is set because ath12k_mac_unregister is not +called during core reset. So, when an MLO setup is recovering from a core +reset, ath12k_core_mlo_setup() is skipped. Hence, the firmware will not +have information about partner links. This makes MLO association fail +after recovery. + +To resolve this, call ath12k_core_mlo_setup() during recovery, to set up +MLO. Also, if MLO setup fails during recovery, call +ath12k_mac_unregister() and ath12k_mac_destroy() to unregister mac and +then tear down the mac structures. + +Also, initiate MLO teardown in the hardware group stop sequence to align +with the hardware group start sequence. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Ramya Gnanasekar +Signed-off-by: Roopni Devanathan +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260227041127.3265879-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c +index 4ed608ba3c304..a1834985bb63b 100644 +--- a/drivers/net/wireless/ath/ath12k/core.c ++++ b/drivers/net/wireless/ath/ath12k/core.c +@@ -1006,6 +1006,8 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag) + + ath12k_mac_unregister(ag); + ++ ath12k_mac_mlo_teardown(ag); ++ + for (i = ag->num_devices - 1; i >= 0; i--) { + ab = ag->ab[i]; + if (!ab) +@@ -1123,8 +1125,14 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag) + + lockdep_assert_held(&ag->mutex); + +- if (test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags)) ++ if (test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags)) { ++ ret = ath12k_core_mlo_setup(ag); ++ if (WARN_ON(ret)) { ++ ath12k_mac_unregister(ag); ++ goto err_mac_destroy; ++ } + goto core_pdev_create; ++ } + + ret = ath12k_mac_allocate(ag); + if (WARN_ON(ret)) +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch b/queue-7.0/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch new file mode 100644 index 0000000000..91dbacb9f7 --- /dev/null +++ b/queue-7.0/wifi-ath12k-skip-adding-inactive-partner-vdev-info.patch @@ -0,0 +1,49 @@ +From 528a09a43b8147381e448391d797452bb51258a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 09:37:32 +0530 +Subject: wifi: ath12k: Skip adding inactive partner vdev info + +From: Avula Sri Charan + +[ Upstream commit 7d7dc26f72abb7a76abb4a68ebad75d5ab7b375e ] + +Currently, a vdev that is created is considered active for partner link +population. In case of an MLD station, non-associated link vdevs can be +created but not started. Yet, they are added as partner links. This leads +to the creation of stale FW partner entries which accumulate and cause +assertions. + +To resolve this issue, check if the vdev is started and operating on a +chosen frequency, i.e., arvif->is_started, instead of checking if the vdev +is created, i.e., arvif->is_created. This determines if the vdev is active +or not and skips adding it as a partner link if it's inactive. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Avula Sri Charan +Signed-off-by: Roopni Devanathan +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260330040732.1847263-1-roopni.devanathan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index a32334bbd0943..9e5900d4e1628 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -11129,7 +11129,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif, + if (arvif == arvif_p) + continue; + +- if (!arvif_p->is_created) ++ if (!arvif_p->is_started) + continue; + + link_conf = wiphy_dereference(ahvif->ah->hw->wiphy, +-- +2.53.0 + diff --git a/queue-7.0/wifi-brcmfmac-of-defer-probe-for-mac-address.patch b/queue-7.0/wifi-brcmfmac-of-defer-probe-for-mac-address.patch new file mode 100644 index 0000000000..aa34f7cbab --- /dev/null +++ b/queue-7.0/wifi-brcmfmac-of-defer-probe-for-mac-address.patch @@ -0,0 +1,39 @@ +From e56a3833e5bb8f0a76a9fea4534a794ee77ea523 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:27:39 -0800 +Subject: wifi: brcmfmac: of: defer probe for MAC address + +From: Rosen Penev + +[ Upstream commit 084863593243c5dce0f2eef44e23de8c53ebf4a2 ] + +of_get_mac_address can return EPROBE_DEFER if the specific nvmem driver +has not been loaded yet. + +Signed-off-by: Rosen Penev +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260220022739.41755-1-rosenp@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +index 1681ad00f82ec..03efae36a0b2d 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -128,7 +128,9 @@ int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + if (err) + brcmf_err("failed to get OF country code map (err=%d)\n", err); + +- of_get_mac_address(np, settings->mac); ++ err = of_get_mac_address(np, settings->mac); ++ if (err == -EPROBE_DEFER) ++ return err; + + if (bus_type != BRCMF_BUSTYPE_SDIO) + return 0; +-- +2.53.0 + diff --git a/queue-7.0/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch b/queue-7.0/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch new file mode 100644 index 0000000000..74ab4c2918 --- /dev/null +++ b/queue-7.0/wifi-iwlwifi-mld-always-assign-a-fw-id-to-a-vif.patch @@ -0,0 +1,58 @@ +From c233c0bf5b604ec9c1465fa6c70b911dc7e312fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 19:29:14 +0200 +Subject: wifi: iwlwifi: mld: always assign a fw id to a vif + +From: Miri Korenblit + +[ Upstream commit 4f1da5cf31cf6345f145e914a0158c2e114bbe27 ] + +We used to have a fw id assignment in iwl_mld_init_vif since all interface +types that were added to the driver was immediately added to the FW as +well. +Since NAN was introduced, this is no longer the case - the NAN interface +is not added to the fw until a local schedule is configured. + +For this vif we don't assign a fw id so it is 0 by default. +But later, when the vif is removed from the driver, we think that it has +a valid fw id (0) and we point fw_id_to_vif[0] to NULL. +fw_id_to_vif[0] might actually point to another vif with a valid fw id +0. In this case, we end up messing fw_id_to_vif. + +Fix this by initializing a vif with a special invalid fw id, and by +exiting iwl_mld_rm_vif early for NAN interfaces. + +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260321192637.f3b5cc59098f.I3d1dbe66bd224cbb786c2b0ab3d1c9f7ec9003e4@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mld/iface.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c +index 9215fc7e2eca7..fb56e59894726 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c +@@ -434,6 +434,7 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) + lockdep_assert_wiphy(mld->wiphy); + + mld_vif->mld = mld; ++ mld_vif->fw_id = IWL_MLD_INVALID_FW_ID; + mld_vif->roc_activity = ROC_NUM_ACTIVITIES; + + if (!mld->fw_status.in_hw_restart) { +@@ -481,6 +482,10 @@ void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) + + lockdep_assert_wiphy(mld->wiphy); + ++ /* NAN interface type is not known to FW */ ++ if (vif->type == NL80211_IFTYPE_NAN) ++ return; ++ + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); + + if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) +-- +2.53.0 + diff --git a/queue-7.0/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch b/queue-7.0/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch new file mode 100644 index 0000000000..4e76a513b9 --- /dev/null +++ b/queue-7.0/wifi-iwlwifi-mvm-zero-iwl_geo_tx_power_profiles_cmd-.patch @@ -0,0 +1,45 @@ +From 5a25d876c964a219ba609584aa2e15b0cf464503 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:43 +0200 +Subject: wifi: iwlwifi: mvm: zero iwl_geo_tx_power_profiles_cmd before sending + +From: Emmanuel Grumbach + +[ Upstream commit 5562b3bbeede8be25092064720e4a942e9fd3e3e ] + +Otherwise we may send garbage. + +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.2d494b0f4692.I9afd0fa6b2ea5a27118144ac4e3bbbedc2089c10@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index 6cc78661116e5..cfe2bb6c1d90a 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -907,7 +907,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) + + int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + { +- union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; ++ union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; + struct iwl_geo_tx_power_profiles_resp *resp; + u16 len; + int ret; +@@ -959,7 +959,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) + { + u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); +- union iwl_geo_tx_power_profiles_cmd cmd; ++ union iwl_geo_tx_power_profiles_cmd cmd = {}; + u16 len; + u32 n_bands; + u32 n_profiles; +-- +2.53.0 + diff --git a/queue-7.0/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch b/queue-7.0/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch new file mode 100644 index 0000000000..ae40022cbf --- /dev/null +++ b/queue-7.0/wifi-iwlwifi-pcie-don-t-dump-on-reset-handshake-in-d.patch @@ -0,0 +1,72 @@ +From b975f4d33e9d8ec1224f38e0f0b1f23459ae7b64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 10:09:16 +0200 +Subject: wifi: iwlwifi: pcie: don't dump on reset handshake in dump + +From: Johannes Berg + +[ Upstream commit 4a481720106d6bad1521d0e0322fd74fa2f6c464 ] + +When a FW dump happens, possibly even because of a reset handshake +timeout, there's no point in attempting to dump again. Since all the +callers of the function outside the transport itself are from the FW +dump infrastructure, just split the internal function and make the +external one not dump on timeout. + +Signed-off-by: Johannes Berg +Reviewed-by: Emmanuel Grumbach +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260320100746.f36ba3893899.I063ccc3a037ae6dabcde61941acb162c4b33f127@changeid +Signed-off-by: Sasha Levin +--- + .../wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +index b15c5d4865277..a50e845cea421 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +@@ -95,7 +95,9 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + } + +-void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) ++static void ++_iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans, ++ bool dump_on_timeout) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; +@@ -133,7 +135,7 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) + "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n", + inta_hw, reset_done); + +- if (!reset_done) { ++ if (!reset_done && dump_on_timeout) { + struct iwl_fw_error_dump_mode mode = { + .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT, + .context = IWL_ERR_CONTEXT_FROM_OPMODE, +@@ -147,6 +149,11 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) + trans_pcie->fw_reset_state = FW_RESET_IDLE; + } + ++void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) ++{ ++ _iwl_trans_pcie_fw_reset_handshake(trans, false); ++} ++ + static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +@@ -163,7 +170,7 @@ static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) + * should assume that the firmware is already dead. + */ + trans->state = IWL_TRANS_NO_FW; +- iwl_trans_pcie_fw_reset_handshake(trans); ++ _iwl_trans_pcie_fw_reset_handshake(trans, true); + } + + trans_pcie->is_down = true; +-- +2.53.0 + diff --git a/queue-7.0/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch b/queue-7.0/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch new file mode 100644 index 0000000000..1aedd72bfc --- /dev/null +++ b/queue-7.0/wifi-iwlwifi-restrict-top-reset-to-some-devices.patch @@ -0,0 +1,98 @@ +From 654231674df2e6509f3c63095fb3aa6b25b005f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 20:48:42 +0200 +Subject: wifi: iwlwifi: restrict TOP reset to some devices + +From: Johannes Berg + +[ Upstream commit f473f609164ee9907497ac55934689110c248e23 ] + +Due to the Bluetooth implementation needing to match, not all +devices can actually do TOP reset. Restrict it to Sc2/Sc2f or +later, with Wh RF or later. + +Signed-off-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260319204647.6c4479f4e49d.I5023d70cb33f1e18f7cb15981fc3acfbb00862b7@changeid +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 10 +++++----- + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 18 ++++++++++++++++++ + .../wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 2 +- + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +index 89901786fd687..16b2c313e72b2 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +@@ -138,7 +138,7 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) + IWL_RESET_MODE_FUNC_RESET, + IWL_RESET_MODE_PROD_RESET, + }; +- static const enum iwl_reset_mode escalation_list_sc[] = { ++ static const enum iwl_reset_mode escalation_list_top[] = { + IWL_RESET_MODE_SW_RESET, + IWL_RESET_MODE_REPROBE, + IWL_RESET_MODE_REPROBE, +@@ -159,14 +159,14 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) + + if (trans->request_top_reset) { + trans->request_top_reset = 0; +- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) ++ if (iwl_trans_is_top_reset_supported(trans)) + return IWL_RESET_MODE_TOP_RESET; + return IWL_RESET_MODE_PROD_RESET; + } + +- if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { +- escalation_list = escalation_list_sc; +- escalation_list_size = ARRAY_SIZE(escalation_list_sc); ++ if (iwl_trans_is_top_reset_supported(trans)) { ++ escalation_list = escalation_list_top; ++ escalation_list_size = ARRAY_SIZE(escalation_list_top); + } else { + escalation_list = escalation_list_old; + escalation_list_size = ARRAY_SIZE(escalation_list_old); +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +index 688f9fee28210..797e20a008d41 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +@@ -1258,4 +1258,22 @@ bool iwl_trans_is_pm_supported(struct iwl_trans *trans); + + bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); + ++static inline bool iwl_trans_is_top_reset_supported(struct iwl_trans *trans) ++{ ++ /* not supported before Sc family */ ++ if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) ++ return false; ++ ++ /* for Sc family only supported for Sc2/Sc2f */ ++ if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC && ++ CSR_HW_REV_TYPE(trans->info.hw_rev) == IWL_CFG_MAC_TYPE_SC) ++ return false; ++ ++ /* so far these numbers are increasing - not before Pe */ ++ if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) < IWL_CFG_RF_TYPE_PE) ++ return false; ++ ++ return true; ++} ++ + #endif /* __iwl_trans_h__ */ +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +index 4560d92d76fe0..a05f60f9224b4 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +@@ -3197,7 +3197,7 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file, + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + return -EINVAL; + if (mode == IWL_RESET_MODE_TOP_RESET) { +- if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) ++ if (!iwl_trans_is_top_reset_supported(trans)) + return -EINVAL; + trans->request_top_reset = 1; + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch b/queue-7.0/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch new file mode 100644 index 0000000000..46ae5222b0 --- /dev/null +++ b/queue-7.0/wifi-mac80211-properly-handle-error-in-ieee80211_add.patch @@ -0,0 +1,64 @@ +From 09b9050ddaeaa09596aab576e1995f0508aeff75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 14:13:46 +0200 +Subject: wifi: mac80211: properly handle error in + ieee80211_add_virtual_monitor + +From: Miri Korenblit + +[ Upstream commit 876565d4a826f3f04ef36f1cef6123ed4b150aa3 ] + +In case of an error in ieee80211_add_virtual_monitor, +SDATA_STATE_RUNNING should be cleared as it was set in this function. +Do it there instead of in the error path of ieee80211_do_open. + +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260320141312.5546126313b1.I689dba2f54069b259702e8d246cedf79a73b82c6@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/iface.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 676b2a43c9f2f..989e60d4b721d 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1222,14 +1222,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local, + } + } + +- set_bit(SDATA_STATE_RUNNING, &sdata->state); +- + ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); + if (ret) { + kfree(sdata); + return ret; + } + ++ set_bit(SDATA_STATE_RUNNING, &sdata->state); ++ + mutex_lock(&local->iflist_mtx); + rcu_assign_pointer(local->monitor_sdata, sdata); + mutex_unlock(&local->iflist_mtx); +@@ -1242,6 +1242,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local, + mutex_unlock(&local->iflist_mtx); + synchronize_net(); + drv_remove_interface(local, sdata); ++ clear_bit(SDATA_STATE_RUNNING, &sdata->state); + kfree(sdata); + return ret; + } +@@ -1550,8 +1551,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) + sdata->bss = NULL; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + list_del(&sdata->u.vlan.list); +- /* might already be clear but that doesn't matter */ +- clear_bit(SDATA_STATE_RUNNING, &sdata->state); + return res; + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch b/queue-7.0/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch new file mode 100644 index 0000000000..c75ad22fcc --- /dev/null +++ b/queue-7.0/wifi-mac80211-remove-deleted-sta-links-in-ieee80211_.patch @@ -0,0 +1,53 @@ +From 642ee746cb0d4b2b6f482e23f20178460782c311 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:28:28 +0100 +Subject: wifi: mac80211: Remove deleted sta links in + ieee80211_ml_reconf_work() + +From: Lorenzo Bianconi + +[ Upstream commit 84674b03d8bf3a850f023a98136c27909f0a2b61 ] + +Delete stale station links announced in the reconfiguration IE +transmitted by the AP in the beacon frames. + +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260309-mac80211-reconf-remove-sta-link-v2-1-1582aac720c6@kernel.org +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 53bd98646e33e..ba5f185469919 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -7002,6 +7002,7 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + container_of(work, struct ieee80211_sub_if_data, + u.mgd.ml_reconf_work.work); + u16 new_valid_links, new_active_links, new_dormant_links; ++ struct sta_info *sta; + int ret; + + if (!sdata->u.mgd.removed_links) +@@ -7037,6 +7038,16 @@ static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + } + } + ++ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); ++ if (sta) { ++ unsigned long removed_links = sdata->u.mgd.removed_links; ++ unsigned int link_id; ++ ++ for_each_set_bit(link_id, &removed_links, ++ IEEE80211_MLD_MAX_NUM_LINKS) ++ ieee80211_sta_free_link(sta, link_id); ++ } ++ + new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links; + + ret = ieee80211_vif_set_links(sdata, new_valid_links, +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-set-band-information-only-for-non-mld-.patch b/queue-7.0/wifi-mac80211-set-band-information-only-for-non-mld-.patch new file mode 100644 index 0000000000..9817b4c1c5 --- /dev/null +++ b/queue-7.0/wifi-mac80211-set-band-information-only-for-non-mld-.patch @@ -0,0 +1,78 @@ +From f355f37fac804e47f840915a9c468d399cd991e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 15:31:25 +0530 +Subject: wifi: mac80211: set band information only for non-MLD when probing + stations using NULL frame + +From: Suraj P Kizhakkethil + +[ Upstream commit 73e7df69edb6f1271ea0fa876794761e6c73e76a ] + +Currently, when sending a NULL frame to probe a station, the band +information is derived from the chanctx_conf in the mac80211 vif's +bss_conf. However, for AP MLD, chanctx_conf is not assigned to the +vif's bss_conf; instead it is assigned on a per-link basis. As a result, +for AP MLD, sending a NULL packet to probe will trigger a warning. + +WARNING: net/mac80211/cfg.c:4635 at ieee80211_probe_client+0x1a8/0x1d8 [mac80211], CPU#2: hostapd/244 +Call trace: + ieee80211_probe_client+0x1a8/0x1d8 [mac80211] (P) + nl80211_probe_client+0xac/0x170 [cfg80211] + genl_family_rcv_msg_doit+0xc8/0x134 + genl_rcv_msg+0x200/0x280 + netlink_rcv_skb+0x38/0xf0 + genl_rcv+0x34/0x48 + netlink_unicast+0x314/0x3a0 + netlink_sendmsg+0x150/0x390 + ____sys_sendmsg+0x1f4/0x21c + ___sys_sendmsg+0x98/0xc0 + __sys_sendmsg+0x74/0xcc + __arm64_sys_sendmsg+0x20/0x34 + invoke_syscall.constprop.0+0x4c/0xd0 + do_el0_svc+0x3c/0xd0 + el0_svc+0x28/0xc0 + el0t_64_sync_handler+0x98/0xdc + el0t_64_sync+0x154/0x158 +---[ end trace 0000000000000000 ]--- + +For NULL packets sent to probe stations, set the band information only +for non-MLD, since MLD transmissions does not rely on band. + +Signed-off-by: Suraj P Kizhakkethil +Link: https://patch.msgid.link/20260213100126.1414398-2-suraj.kizhakkethil@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/cfg.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index b85375ceb575d..85b18f59a7821 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4629,12 +4629,17 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, + + qos = sta->sta.wme; + +- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- ret = -EINVAL; +- goto unlock; ++ if (ieee80211_vif_is_mld(&sdata->vif)) { ++ /* MLD transmissions must not rely on the band */ ++ band = 0; ++ } else { ++ chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ ret = -EINVAL; ++ goto unlock; ++ } ++ band = chanctx_conf->def.chan->band; + } +- band = chanctx_conf->def.chan->band; + + if (qos) { + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch b/queue-7.0/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch new file mode 100644 index 0000000000..d523d4b7a0 --- /dev/null +++ b/queue-7.0/wifi-mac80211-use-ap_addr-for-4-address-null-frame-d.patch @@ -0,0 +1,51 @@ +From 0fe9826209a8581f83ed06cdfaa78c293e65ac6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:17:22 +0530 +Subject: wifi: mac80211: use ap_addr for 4-address NULL frame destination + +From: Tamizh Chelvam Raja + +[ Upstream commit 594be50a3f0a6b7389f40f7acbf0dd731beb5204 ] + +Currently ieee80211_send_4addr_nullfunc() uses deflink.u.mgd.bssid +for addr1 and addr3 fields. In MLO configurations, deflink.u.mgd.bssid +represents link 0's BSSID and is not updated when link 0 is not an +assoc link. This causes 4-address NULL frames to be sent to the +wrong address, preventing WDS AP_VLAN interface creation on the peer AP. + +To fix this use sdata->vif.cfg.ap_addr instead, which contains the AP's MLD +address populated during authentication/association and remains +valid regardless of which links are active. + +This ensures 4-address NULL frames reach the correct AP, allowing +proper WDS operation over MLO connections. + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Tamizh Chelvam Raja +Link: https://patch.msgid.link/20260326164723.553927-3-tamizh.raja@oss.qualcomm.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index ba5f185469919..f213146a04ef0 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2496,9 +2496,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + nullfunc->frame_control = fc; +- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); ++ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN); + memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-abort-roc-on-chanctx-changes.patch b/queue-7.0/wifi-mt76-abort-roc-on-chanctx-changes.patch new file mode 100644 index 0000000000..b10ac6e546 --- /dev/null +++ b/queue-7.0/wifi-mt76-abort-roc-on-chanctx-changes.patch @@ -0,0 +1,41 @@ +From 754cb45fb3cdf74e46fef16c67ade71117f32322 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:24 +0000 +Subject: wifi: mt76: abort ROC on chanctx changes + +From: Felix Fietkau + +[ Upstream commit de62b24224ac1533c17b3d5bae77164a82ae2e49 ] + +mt76_change_chanctx() calls mt76_phy_update_channel() which switches +the hardware channel. If ROC is active on the same phy, this switches +away from the ROC channel and clears offchannel, but leaves ROC state +intact. Mac80211 still thinks the phy is on the ROC channel. + +Abort any active ROC before proceeding, matching the pattern already +used in add, remove, assign, unassign, and switch chanctx functions. + +Link: https://patch.msgid.link/20260309060730.87840-5-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/channel.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c +index d9f8529db7ed4..b056bf3ddfee9 100644 +--- a/drivers/net/wireless/mediatek/mt76/channel.c ++++ b/drivers/net/wireless/mediatek/mt76/channel.c +@@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw, + IEEE80211_CHANCTX_CHANGE_RADAR))) + return; + ++ if (phy->roc_vif) ++ mt76_abort_roc(phy); ++ + cancel_delayed_work_sync(&phy->mac_work); + + mutex_lock(&dev->mutex); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch b/queue-7.0/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch new file mode 100644 index 0000000000..c5c9ef42c5 --- /dev/null +++ b/queue-7.0/wifi-mt76-add-missing-lock-protection-in-mt76_sta_st.patch @@ -0,0 +1,51 @@ +From 3af2a79dd685d83b42bac657a3d8213b3b2604eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 03:52:10 +0000 +Subject: wifi: mt76: add missing lock protection in mt76_sta_state for + sta_event callback + +From: Ziyi Guo + +[ Upstream commit f0168f2f9a1eca55d3ae09d8250b94e82b67cac3 ] + +mt76_sta_state() calls the sta_event callback without holding dev->mutex. +However, mt7915_mac_sta_event() (MT7915 implementation of this callback) +calls mt7915_mac_twt_teardown_flow() which has +lockdep_assert_held(&dev->mt76.mutex) indicating that callers must +hold this lock. + +The locking pattern in mt76_sta_state() is inconsistent: +- mt76_sta_add() acquires dev->mutex before calling dev->drv->sta_add +- mt76_sta_remove() acquires dev->mutex before calling __mt76_sta_remove +- But sta_event callback is called without acquiring the lock + +Add mutex_lock()/mutex_unlock() around the mt7915_mac_twt_teardown_flow +invocation to fix the missing lock protection and maintain consistency +with the existing locking pattern. + +Signed-off-by: Ziyi Guo +Link: https://patch.msgid.link/20260131035210.2198259-1-n7l8m4@u.northwestern.edu +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index 0892291616ead..e1d83052aa6dd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -852,8 +852,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); + + case MT76_STA_EVENT_DISASSOC: ++ mutex_lock(&dev->mt76.mutex); + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); ++ mutex_unlock(&dev->mt76.mutex); + + mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-avoid-to-set-ack-for-mcu-command-if-wait_r.patch b/queue-7.0/wifi-mt76-avoid-to-set-ack-for-mcu-command-if-wait_r.patch new file mode 100644 index 0000000000..b3f6435c35 --- /dev/null +++ b/queue-7.0/wifi-mt76-avoid-to-set-ack-for-mcu-command-if-wait_r.patch @@ -0,0 +1,72 @@ +From 2f103626ce2cf2d33802e3065983dc5bfbb03938 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:31 +0800 +Subject: wifi: mt76: avoid to set ACK for MCU command if wait_resp is not set + +From: StanleyYP Wang + +[ Upstream commit 169c83d3df95b57e787174454332e01eb1b823ed ] + +When wait_resp is not set but the ACK option is enabled in the MCU TXD, +the ACK event is enqueued to the MCU event queue without being dequeued +by the original MCU command request. + +Any orphaned ACK events will only be removed from the queue when another +MCU command requests a response. Due to sequence index mismatches, these +events are discarded one by one until a matching sequence index is found. + +However, if several MCU commands that do not require a response continue +to fill up the event queue, there is a risk that when an MCU command with +wait_resp enabled is issued, it may dequeue the wrong event skb, +especially if the queue contains events with all possible sequence +indices. + +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-3-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mcu.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 11 +++++------ + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c +index 535c3d8a9cc0d..cbfb3bbec5031 100644 +--- a/drivers/net/wireless/mediatek/mt76/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mcu.c +@@ -98,7 +98,7 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, + /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ + if (orig_skb) + skb_get(orig_skb); +- ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); ++ ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, wait_resp ? &seq : NULL); + if (ret < 0) + goto out; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 30ddc40901ecc..435347bc4f5e1 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -322,13 +322,12 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + uni_txd->pkt_type = MCU_PKT_ID; + uni_txd->seq = seq; + +- if (cmd & __MCU_CMD_FIELD_QUERY) +- uni_txd->option = MCU_CMD_UNI_QUERY_ACK; +- else +- uni_txd->option = MCU_CMD_UNI_EXT_ACK; ++ uni_txd->option = MCU_CMD_UNI; ++ if (!(cmd & __MCU_CMD_FIELD_QUERY)) ++ uni_txd->option |= MCU_CMD_SET; + +- if (mcu_cmd == MCU_UNI_CMD_SDO) +- uni_txd->option &= ~MCU_CMD_ACK; ++ if (wait_seq) ++ uni_txd->option |= MCU_CMD_ACK; + + if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) + uni_txd->s2d_index = MCU_S2D_H2CN; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch b/queue-7.0/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch new file mode 100644 index 0000000000..de804a641f --- /dev/null +++ b/queue-7.0/wifi-mt76-don-t-return-txq-when-exceeding-max-non-aq.patch @@ -0,0 +1,79 @@ +From 49a198953691c7ae592ea8ba5181bd5568debec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 00:23:20 +0100 +Subject: wifi: mt76: don't return TXQ when exceeding max non-AQL packets + +From: David Bauer + +[ Upstream commit 964f870e090e9c88a41e2890333421204cc0bdf4 ] + +mt76_txq_send_burst does check if the number of non-AQL frames exceeds +the maximum. In this case the queue is returned to ieee80211_return_txq +when iterating over the scheduled TXQs in mt76_txq_schedule_list. + +This has the effect of inserting said TXQ at the head of the list. This +means the loop will get the same TXQ again, which will terminate the +scheduling round. TXQs following in the list thus never get scheduled +for transmission. + +This can manifest in high latency low throughput or broken connections +for said STAs. + +Check if the non-AQL packet count exceeds the limit and not return the +TXQ in this case. +Schedule all TXQs for the STA in case the non-AQL limit can be satisfied +again. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20260129232321.276575-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/tx.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 9ec6d0b53a84a..0753acf2eccb8 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -227,7 +227,9 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + struct sk_buff *skb) + { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_sta *sta; + int pending; ++ int i; + + if (!wcid || info->tx_time_est) + return; +@@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); ++ ++ sta = wcid_to_sta(wcid); ++ if (!sta || pending != MT_MAX_NON_AQL_PKT - 1) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { ++ if (!sta->txq[i]) ++ continue; ++ ++ ieee80211_schedule_txq(dev->hw, sta->txq[i]); ++ } + } + + void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, +@@ -542,6 +555,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) + if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) + continue; + ++ if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) ++ continue; ++ + phy = mt76_dev_phy(dev, wcid->phy_idx); + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + continue; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch b/queue-7.0/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch new file mode 100644 index 0000000000..2b84ed3b51 --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-list-corruption-in-mt76_wcid_cleanup.patch @@ -0,0 +1,54 @@ +From 6d2c4b8c1ea062dbd0b7247b4c2cd27a8890ad8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:10:32 -0800 +Subject: wifi: mt76: fix list corruption in mt76_wcid_cleanup + +From: Zac Bowling + +[ Upstream commit 34163942195410372fb138bea806c9b34e2f5257 ] + +mt76_wcid_cleanup() was not removing wcid entries from sta_poll_list +before mt76_reset_device() reinitializes the master list. This leaves +stale pointers in wcid->poll_list, causing list corruption when +mt76_wcid_add_poll() later checks list_empty() and tries to add the +entry back. + +The fix adds proper cleanup of poll_list in mt76_wcid_cleanup(), +matching how tx_list is already handled. This is similar to what +mt7996_mac_sta_deinit_link() already does correctly. + +Fixes list corruption warnings like: + list_add corruption. prev->next should be next (ffffffff...) + +Signed-off-by: Zac Bowling +Link: https://patch.msgid.link/20260120201043.38225-3-zac@zacbowling.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 4d041f88155c2..3c539c263238c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1717,6 +1717,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) + + idr_destroy(&wcid->pktid); + ++ /* Remove from sta_poll_list to prevent list corruption after reset. ++ * Without this, mt76_reset_device() reinitializes sta_poll_list but ++ * leaves wcid->poll_list with stale pointers, causing list corruption ++ * when mt76_wcid_add_poll() checks list_empty(). ++ */ ++ spin_lock_bh(&dev->sta_poll_lock); ++ if (!list_empty(&wcid->poll_list)) ++ list_del_init(&wcid->poll_list); ++ spin_unlock_bh(&dev->sta_poll_lock); ++ + spin_lock_bh(&phy->tx_lock); + + if (!list_empty(&wcid->tx_list)) +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-flush-pending-tx-before-channel-switch.patch b/queue-7.0/wifi-mt76-flush-pending-tx-before-channel-switch.patch new file mode 100644 index 0000000000..d8c30a28b5 --- /dev/null +++ b/queue-7.0/wifi-mt76-flush-pending-tx-before-channel-switch.patch @@ -0,0 +1,74 @@ +From 4d61ebab23b401c4c6d35a4623e992f4e1010b9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:27 +0000 +Subject: wifi: mt76: flush pending TX before channel switch + +From: Felix Fietkau + +[ Upstream commit 0dcef1cbae27d806cd29c296cc03ad6e8ece771d ] + +mt76_tx() queues frames on wcid->tx_pending for async processing by +tx_worker. In __mt76_set_channel(), the worker gets disabled before it +may have run, and the subsequent wait only checks DMA ring queues, not +the software pending list. This means frames like nullfunc PS frames +from mt76_offchannel_notify() may never be transmitted on the correct +channel. + +Fix this by running mt76_txq_schedule_pending() synchronously after +disabling the tx_worker but before setting MT76_RESET, which would +otherwise cause mt76_txq_schedule_pending_wcid() to bail out. + +Link: https://patch.msgid.link/20260309060730.87840-8-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++-- + drivers/net/wireless/mediatek/mt76/mt76.h | 1 + + drivers/net/wireless/mediatek/mt76/tx.c | 2 +- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 3c539c263238c..b2e2cafcdcc36 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -1031,9 +1031,10 @@ int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + int timeout = HZ / 5; + int ret; + +- set_bit(MT76_RESET, &phy->state); +- + mt76_worker_disable(&dev->tx_worker); ++ mt76_txq_schedule_pending(phy); ++ ++ set_bit(MT76_RESET, &phy->state); + wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); + mt76_update_survey(phy); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index df93ab79c5b48..0c7a0f4189c3e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -1520,6 +1520,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, + void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); + void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); + void mt76_txq_schedule_all(struct mt76_phy *phy); ++void mt76_txq_schedule_pending(struct mt76_phy *phy); + void mt76_tx_worker_run(struct mt76_dev *dev); + void mt76_tx_worker(struct mt76_worker *w); + void mt76_release_buffered_frames(struct ieee80211_hw *hw, +diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c +index 0753acf2eccb8..ab62591b7a260 100644 +--- a/drivers/net/wireless/mediatek/mt76/tx.c ++++ b/drivers/net/wireless/mediatek/mt76/tx.c +@@ -660,7 +660,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, + return ret; + } + +-static void mt76_txq_schedule_pending(struct mt76_phy *phy) ++void mt76_txq_schedule_pending(struct mt76_phy *phy) + { + LIST_HEAD(tx_list); + int ret = 0; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch b/queue-7.0/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch new file mode 100644 index 0000000000..28df6ccaf0 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt76x02-wake-queues-after-reconfig.patch @@ -0,0 +1,42 @@ +From 2e7309faf3752b040d0ea039d22651a6deeea712 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Nov 2025 03:39:02 +0100 +Subject: wifi: mt76: mt76x02: wake queues after reconfig + +From: David Bauer + +[ Upstream commit 524ef4b42b40bf1cf634663e746ace0af3fce45c ] + +The shared reset procedure of MT7610 and MT7612 stop all queues before +starting the reset sequence. + +They however never restart these like other supported mt76 chips +do in the reconfig_complete call. This leads to TX not continuing +after the reset. + +Restart queues in the reconfig_complete callback to restore +functionality after the reset. + +Signed-off-by: David Bauer +Link: https://patch.msgid.link/20251129023904.288484-1-mail@david-bauer.net +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +index dd71c1c95cc9b..dc7c03d231238 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +@@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); ++ ieee80211_wake_queues(hw); + } + EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch b/queue-7.0/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch new file mode 100644 index 0000000000..1f65e7c548 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-resolve-link-after-acquiring-mt76-m.patch @@ -0,0 +1,42 @@ +From b4ec68434354cadedbac3779d97ba2d9f2c77035 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 17:22:30 -0600 +Subject: wifi: mt76: mt7925: resolve link after acquiring mt76 mutex + +From: Sean Wang + +[ Upstream commit beec58f36983f826fe90287a90edff46b32e8a89 ] + +mt792x_sta_to_link() uses rcu_dereference_protected() and therefore +expects mt76.mutex to be held. Move the lookup after +mt792x_mutex_acquire() to make the locking explicit and correct. + +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20260306232238.2039675-12-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 8ddae156cf25b..23f82f9126f0b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1034,11 +1034,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + ++ mt792x_mutex_acquire(dev); ++ + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + +- mt792x_mutex_acquire(dev); +- + if (ieee80211_vif_is_mld(vif)) { + link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); + } else { +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch b/queue-7.0/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch new file mode 100644 index 0000000000..28f02af857 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-skip-scan-process-during-suspend.patch @@ -0,0 +1,49 @@ +From 30c8e98fd24fd2fbcc24b2c6089692996ad8e6bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 19:40:07 +0800 +Subject: wifi: mt76: mt7925: Skip scan process during suspend. + +From: Michael Lo + +[ Upstream commit 8c7e19612b01567f641d3ffe21e47fa21c331171 ] + +We are experiencing command timeouts because an upper layer triggers +an unexpected scan while the system/device is in suspend. +The upper layer should not initiate scans until the NIC has fully resumed. +We want to prevent scans during suspend and avoid timeouts without harming +power management or user experience. + +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260112114007.2115873-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index fec54d5f4eaf1..8ddae156cf25b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1327,10 +1327,18 @@ void mt7925_mlo_pm_work(struct work_struct *work) + void mt7925_scan_work(struct work_struct *work) + { + struct mt792x_phy *phy; ++ struct mt792x_dev *dev; ++ struct mt76_connac_pm *pm; + + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + scan_work.work); + ++ dev = phy->dev; ++ pm = &dev->pm; ++ ++ if (pm->suspended) ++ return; ++ + while (true) { + struct sk_buff *skb; + struct tlv *tlv; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch b/queue-7.0/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch new file mode 100644 index 0000000000..a295d1b52d --- /dev/null +++ b/queue-7.0/wifi-mt76-mt792x-fix-a-potential-deadlock-in-high-lo.patch @@ -0,0 +1,49 @@ +From f5c773995fcb1aff3b1e212493e8e5798ce11820 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:22:31 +0800 +Subject: wifi: mt76: mt792x: Fix a potential deadlock in high-load situations + +From: Leon Yen + +[ Upstream commit bb2f07819d063a58756186cac6465341956ac0a4 ] + +A deadlock may occur between two works, ps_work and mac_work, if their work +functions run simultaneously as they attempt to cancel each other by +calling cancel_delayed_work_sync(). + +mt792x_mac_work() -> ... -> cancel_delayed_work_sync(&pm->ps_work); +mt792x_pm_power_save_work() -> cancel_delayed_work_sync(&mphy->mac_work); + +In high-load situations, they are queued but may not have chance to be +executed until the CPUs are released. Once the CPUs are available, there +is a high possibility that the ps_work function and mac_work function will +be executed simultaneously, resulting in a possible deadlock. + +This patch replaces cancel_delayed_work_sync() with cancel_delayed_work() +in ps_work to eliminate the deadlock and make the code easier to maintain. + +Signed-off-by: Leon Yen +Tested-by: Chia-Lin Kao (AceLan) +Link: https://patch.msgid.link/20251215122231.3180648-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +index 71dec93094ebd..888e5a5056731 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +@@ -375,7 +375,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) + } + + if (!mt792x_mcu_fw_pmctrl(dev)) { +- cancel_delayed_work_sync(&mphy->mac_work); ++ cancel_delayed_work(&mphy->mac_work); + return; + } + out: +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch b/queue-7.0/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch new file mode 100644 index 0000000000..e2d5e82edc --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-disable-rx-hdr_trans-in-monitor-mod.patch @@ -0,0 +1,50 @@ +From d3482324873e116d76277b8a576aaa1caadc5ed3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 00:00:29 -0800 +Subject: wifi: mt76: mt7996: Disable Rx hdr_trans in monitor mode + +From: Ryder Lee + +[ Upstream commit 947d63d8cd3b03c7be16875ca90273edbdbe7ce5 ] + +Ensure raw frames are captured without header modification. + +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/04008426d6cd5de3995beefb98f9d13f35526c25.1770969275.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 ++ + drivers/net/wireless/mediatek/mt76/mt7996/regs.h | 3 +++ + 2 files changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index ff3050c2344ab..96dda5b6de6d0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -482,6 +482,8 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) + + mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), + MT_DMA_DCR0_RXD_G5_EN, enabled); ++ mt76_rmw_field(dev, MT_MDP_DCR0, ++ MT_MDP_DCR0_RX_HDR_TRANS_EN, !enabled); + mt7996_phy_set_rxfilter(phy); + mt7996_mcu_set_sniffer_mode(phy, enabled); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +index e48e0e575b646..393faae2d52b6 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +@@ -159,6 +159,9 @@ enum offs_rev { + #define MT_MDP_BASE 0x820cc000 + #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + ++#define MT_MDP_DCR0 MT_MDP(0x800) ++#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) ++ + #define MT_MDP_DCR2 MT_MDP(0x8e8) + #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch b/queue-7.0/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch new file mode 100644 index 0000000000..5e6d3eb7aa --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-frequency-separation-for-statio.patch @@ -0,0 +1,36 @@ +From 7dab2d8aef7c6ad1c6dcbecc506daa9cef02c635 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 12:44:27 +0100 +Subject: wifi: mt76: mt7996: fix frequency separation for station STR mode + +From: Peter Chiu + +[ Upstream commit 59a295335021f6973a34566554b2b9371f1c6f7d ] + +Fix frequency separation field for STR in MLD capabilities to get the +correct chip capability. + +Signed-off-by: Peter Chiu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260316-mt7996-sta-str-v1-1-666814e6ab2d@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index fca2d84493b9b..be434a9a869da 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -99,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { + .extended_capabilities_mask = if_types_ext_capa_ap, + .extended_capabilities_len = sizeof(if_types_ext_capa_ap), + .mld_capa_and_ops = ++ FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) | + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, + MT7996_MAX_RADIOS - 1), + }, +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch b/queue-7.0/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch new file mode 100644 index 0000000000..bafb9ead3f --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-queue-pause-after-scan-due-to-w.patch @@ -0,0 +1,49 @@ +From c003b6d34c2de9abbcc7db9912464e2f4fd7fe11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:32 +0800 +Subject: wifi: mt76: mt7996: fix queue pause after scan due to wrong channel + switch reason + +From: StanleyYP Wang + +[ Upstream commit 1f9017d19db38ad2cb9bedb5b078f6f4f60afa94 ] + +Previously, we used the IEEE80211_CONF_IDLE flag to avoid setting the +parking channel with the CH_SWITCH_NORMAL reason, which could trigger TX +emission before bootup CAC. + +However, we found that this flag can be set after triggering scanning on a +connected station interface, and the reason CH_SWITCH_SCAN_BYPASS_DPD will +be used when switching back to the operating channel, which makes the +firmware failed to resume paused AC queues. + +Seems that we should avoid relying on this flag after switching to single +multi-radio architecture. Instead, use the existence of chanctx as the +condition. + +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-4-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 435347bc4f5e1..c501054e06df7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -3756,8 +3756,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) + + if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) + req.switch_reason = CH_SWITCH_NORMAL; +- else if (phy->mt76->offchannel || +- phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) ++ else if (phy->mt76->offchannel || !phy->mt76->chanctx) + req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; + else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, + NL80211_IFTYPE_AP)) +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch b/queue-7.0/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch new file mode 100644 index 0000000000..1bd21b3b34 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-reset-device-after-mcu-message-time.patch @@ -0,0 +1,66 @@ +From ade719ede4dd75fd59fa6d77bb0b7b04921e2426 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:24:00 +0000 +Subject: wifi: mt76: mt7996: reset device after MCU message timeout + +From: Chad Monroe + +[ Upstream commit d2b860454ea2df8f336e9b859da7ffb27f43444d ] + +Trigger a full reset after MCU message timeout. + +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/6e05ed063f3763ad3457633c56b60a728a49a6f0.1765203753.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 +++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index fc08ef94df637..90cb7a49bcaf4 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2745,6 +2745,11 @@ void mt7996_reset(struct mt7996_dev *dev) + return; + } + ++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { ++ set_bit(MT76_MCU_RESET, &dev->mphy.state); ++ wake_up(&dev->mt76.mcu.wait); ++ } ++ + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 20ade7ae7da95..30ddc40901ecc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -209,6 +209,7 @@ static int + mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) + { ++ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_mcu_rxd *rxd; + struct mt7996_mcu_uni_event *event; + int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); +@@ -217,6 +218,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + if (!skb) { + dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", + cmd, seq); ++ ++ if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { ++ dev->recovery.restart = true; ++ wake_up(&dev->mt76.mcu.wait); ++ queue_work(dev->mt76.wq, &dev->reset_work); ++ wake_up(&dev->reset_wait); ++ } ++ + return -ETIMEDOUT; + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch b/queue-7.0/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch new file mode 100644 index 0000000000..1060463c6c --- /dev/null +++ b/queue-7.0/wifi-rsi_91x_usb-do-not-pause-rfkill-polling-when-st.patch @@ -0,0 +1,90 @@ +From c6ea16eed4bb62cfc04edde5a7bf14b7fdc141d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:19:12 +0200 +Subject: wifi: rsi_91x_usb: do not pause rfkill polling when stopping mac80211 + +From: Ville Nummela + +[ Upstream commit 777d8ba5aada960c666f810d5d820ab55ebb64c3 ] + +Removing rsi_91x USB adapter could cause rtnetlink to lock up. +When rsi_mac80211_stop is called, wiphy_lock is locked. Call to +wiphy_rfkill_stop_polling would wait until the work queue has +finished, but because the work queue waits for wiphy_lock, that +would never happen. + +Moving the call to rsi_disconnect avoids the lock up. + +Signed-off-by: Ville Nummela +Link: https://patch.msgid.link/20260318081912.87744-1-ville.nummela@kempower.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 ++++++++++++++++- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 ++ + drivers/net/wireless/rsi/rsi_common.h | 1 + + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index c7ae8031436ae..3faf2235728be 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -325,6 +325,22 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) + } + EXPORT_SYMBOL_GPL(rsi_mac80211_detach); + ++/** ++ * rsi_mac80211_rfkill_exit() - This function is used to stop rfkill polling ++ * when the device is removed. ++ * @adapter: Pointer to the adapter structure. ++ * ++ * Return: None. ++ */ ++void rsi_mac80211_rfkill_exit(struct rsi_hw *adapter) ++{ ++ struct ieee80211_hw *hw = adapter->hw; ++ ++ if (hw) ++ wiphy_rfkill_stop_polling(hw->wiphy); ++} ++EXPORT_SYMBOL_GPL(rsi_mac80211_rfkill_exit); ++ + /** + * rsi_indicate_tx_status() - This function indicates the transmit status. + * @adapter: Pointer to the adapter structure. +@@ -422,7 +438,6 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw, bool suspend) + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); + mutex_lock(&common->mutex); + common->iface_down = true; +- wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index d83204701e27e..8765cac6f875b 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -877,6 +877,8 @@ static void rsi_disconnect(struct usb_interface *pfunction) + if (!adapter) + return; + ++ rsi_mac80211_rfkill_exit(adapter); ++ + rsi_mac80211_detach(adapter); + + if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index c40f8101febcb..3cdf9ded876d9 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -78,6 +78,7 @@ static inline void rsi_kill_thread(struct rsi_thread *handle) + } + + void rsi_mac80211_detach(struct rsi_hw *hw); ++void rsi_mac80211_rfkill_exit(struct rsi_hw *hw); + u16 rsi_get_connected_channel(struct ieee80211_vif *vif); + struct rsi_hw *rsi_91x_init(u16 oper_mode); + void rsi_91x_deinit(struct rsi_hw *adapter); +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch b/queue-7.0/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch new file mode 100644 index 0000000000..94604e70a3 --- /dev/null +++ b/queue-7.0/wifi-rtw88-add-quirks-to-disable-pci-aspm-and-deep-l.patch @@ -0,0 +1,118 @@ +From 0eb53ae3ff23e8c967543bd5aa8b80f36989842a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:56:35 +0800 +Subject: wifi: rtw88: add quirks to disable PCI ASPM and deep LPS for HP + P3S95EA#ACB + +From: Ping-Ke Shih + +[ Upstream commit b2bf9d61e14af4129362aeb9c10034229a6d8f08 ] + +On an HP laptop (P3S95EA#ACB) equipped with a Realtek RTL8821CE 802.11ac +PCIe adapter (PCI ID: 10ec:c821), the system experiences a hard lockup +(complete freeze of the UI and kernel, sysrq doesn't work, requires +holding the power button) when the WiFi adapter enters the power +saving state. Disable PCI ASPM to avoid system freeze. + +In addition, driver throws messages periodically. Though this doesn't +always cause unstable connection, missing H2C commands might cause +unpredictable results. Disable deep LPS to avoid this as well. + + rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state + rtw88_8821ce 0000:13:00.0: failed to send h2c command + rtw88_8821ce 0000:13:00.0: failed to send h2c command + +Tested on HP Notebook P3S95EA#ACB (kernel 6.19.7-1-cachyos): + + - No hard freeze observed during idle or active usage. + - Zero h2c or lps errors in dmesg across idle (10 min), + load stress (100MB download), and suspend/resume cycle. + - Both quirk flags confirmed active via sysfs without any + manual modprobe parameters. + +Reported-by: Oleksandr Havrylov +Closes: https://lore.kernel.org/linux-wireless/CALdGYqSQ1Ko2TTBhUizMu_FvLMUAuQfFrVwS10n_C-LSQJQQkQ@mail.gmail.com/ +Signed-off-by: Ping-Ke Shih +Tested-by: Oleksandr Havrylov +Link: https://patch.msgid.link/20260316035635.16550-1-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/main.h | 5 ++++ + drivers/net/wireless/realtek/rtw88/pci.c | 31 +++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h +index 1ab70214ce36e..55b794d4584c4 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.h ++++ b/drivers/net/wireless/realtek/rtw88/main.h +@@ -432,6 +432,11 @@ enum rtw_wow_flags { + RTW_WOW_FLAG_MAX, + }; + ++enum rtw_quirk_dis_caps { ++ QUIRK_DIS_CAP_PCI_ASPM, ++ QUIRK_DIS_CAP_LPS_DEEP, ++}; ++ + /* the power index is represented by differences, which cck-1s & ht40-1s are + * the base values, so for 1s's differences, there are only ht20 & ofdm + */ +diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c +index ec0a45bfb670e..bba370ad510cf 100644 +--- a/drivers/net/wireless/realtek/rtw88/pci.c ++++ b/drivers/net/wireless/realtek/rtw88/pci.c +@@ -2,6 +2,7 @@ + /* Copyright(c) 2018-2019 Realtek Corporation + */ + ++#include + #include + #include + #include "main.h" +@@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = { + }; + EXPORT_SYMBOL(rtw_pci_err_handler); + ++static int rtw_pci_disable_caps(const struct dmi_system_id *dmi) ++{ ++ uintptr_t dis_caps = (uintptr_t)dmi->driver_data; ++ ++ if (dis_caps & BIT(QUIRK_DIS_CAP_PCI_ASPM)) ++ rtw_pci_disable_aspm = true; ++ ++ if (dis_caps & BIT(QUIRK_DIS_CAP_LPS_DEEP)) ++ rtw_disable_lps_deep_mode = true; ++ ++ return 1; ++} ++ ++static const struct dmi_system_id rtw_pci_quirks[] = { ++ { ++ .callback = rtw_pci_disable_caps, ++ .ident = "HP Notebook - P3S95EA#ACB", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"), ++ }, ++ .driver_data = (void *)(BIT(QUIRK_DIS_CAP_PCI_ASPM) | ++ BIT(QUIRK_DIS_CAP_LPS_DEEP)), ++ }, ++ {} ++}; ++ + int rtw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { +@@ -1771,6 +1800,8 @@ int rtw_pci_probe(struct pci_dev *pdev, + rtwpci = (struct rtw_pci *)rtwdev->priv; + atomic_set(&rtwpci->link_usage, 1); + ++ dmi_check_system(rtw_pci_quirks); ++ + ret = rtw_core_init(rtwdev); + if (ret) + goto err_release_hw; +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch b/queue-7.0/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch new file mode 100644 index 0000000000..a6f2b9fdde --- /dev/null +++ b/queue-7.0/wifi-rtw88-coex-ignore-bt-info-byte-5-from-rtl8821a.patch @@ -0,0 +1,46 @@ +From 6cea67f58b9f3f449953fad4375b783ae3e80240 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:27:15 +0200 +Subject: wifi: rtw88: coex: Ignore BT info byte 5 from RTL8821A + +From: Bitterblue Smith + +[ Upstream commit 658e3c836969e1624a7572c75684f54ec503c2ed ] + +Sometimes while watching a Youtube video with Bluetooth headphones the +audio has a lot of interruptions, because the 5th byte of the BT info +sent by RTL8821AU has strange values, which result in +coex_stat->bt_hid_pair_num being 2 or 3. When this happens +rtw_coex_freerun_check() returns true, which causes +rtw_coex_action_wl_connected() to call rtw_coex_action_freerun() instead +of rtw_coex_action_bt_a2dp(). + +The RTL8821AU vendor driver doesn't do anything with the 5th byte of the +BT info, so ignore it here as well. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/bbf06c83-d2ee-4205-8fbb-829e2347586f@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/coex.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c +index b4dc6ff2c1750..97fc7392b48a8 100644 +--- a/drivers/net/wireless/realtek/rtw88/coex.c ++++ b/drivers/net/wireless/realtek/rtw88/coex.c +@@ -3095,6 +3095,9 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) + for (i = 0; i < COEX_BTINFO_LENGTH; i++) + coex_stat->bt_info_c2h[rsp_source][i] = buf[i]; + ++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) ++ coex_stat->bt_info_c2h[rsp_source][5] = 0; ++ + /* get the same info from bt, skip it */ + if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 && + coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 && +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch b/queue-7.0/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch new file mode 100644 index 0000000000..7fc92dc747 --- /dev/null +++ b/queue-7.0/wifi-rtw88-tx-qos-null-data-the-same-way-as-null-dat.patch @@ -0,0 +1,58 @@ +From 3b71ac5fd6d7264881b40a625992fb757fab0654 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:45:13 +0200 +Subject: wifi: rtw88: TX QOS Null data the same way as Null data + +From: Bitterblue Smith + +[ Upstream commit 737e980e12983bb7420a2c00b981a1e607079a84 ] + +When filling out the TX descriptor, Null data frames are treated like +management frames, but QOS Null data frames are treated like normal +data frames. Somehow this causes a problem for the firmware. + +When connected to a network in the 2.4 GHz band, wpa_supplicant (or +NetworkManager?) triggers a scan every five minutes. During these scans +mac80211 transmits many QOS Null frames in quick succession. Because +these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88 +asks the firmware to report the TX ACK status for each of these frames. +Sometimes the firmware can't process the TX status requests quickly +enough, they add up, it only processes some of them, and then marks +every subsequent TX status report with the wrong number. + +The symptom is that after a while the warning "failed to get tx report +from firmware" appears every five minutes. + +This problem apparently happens only with the older RTL8723D, RTL8821A, +RTL8812A, and probably RTL8703B chips. + +Treat QOS Null data frames the same way as Null data frames. This seems +to avoid the problem. + +Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU. + +Signed-off-by: Bitterblue Smith +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c +index 2ab440cb2d67b..3106edb84fb47 100644 +--- a/drivers/net/wireless/realtek/rtw88/tx.c ++++ b/drivers/net/wireless/realtek/rtw88/tx.c +@@ -421,7 +421,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, + pkt_info->mac_id = rtwvif->mac_id; + } + +- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) ++ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) + rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); + else if (ieee80211_is_data(fc)) + rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch b/queue-7.0/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch new file mode 100644 index 0000000000..ab7f61f97a --- /dev/null +++ b/queue-7.0/wifi-rtw88-validate-rx-rate-to-prevent-out-of-bound.patch @@ -0,0 +1,59 @@ +From 6fefcc0328f9ce30f4189983ab420119d941b9c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 09:10:01 +0800 +Subject: wifi: rtw88: validate RX rate to prevent out-of-bound + +From: Ping-Ke Shih + +[ Upstream commit bf14367719fa86f7c6922c64d37a2df347954c66 ] + +The reported RX rate might be unexpected, causing kernel warns: + + Rate marked as a VHT rate but data is invalid: MCS: 0, NSS: 0 + WARNING: net/mac80211/rx.c:5491 at ieee80211_rx_list+0x183/0x1020 [mac80211] + +As the RX rate can be index of an array under certain conditions, validate +it to prevent accessing array out-of-bound potentially. + +Tested on HP Notebook P3S95EA#ACB (kernel 6.19.9-1-cachyos): + + - No WARNING: net/mac80211/rx.c:5491 observed after the v2 patch. +The unexpected `NSS: 0, MCS: 0` VHT rate warnings are successfully +mitigated. + - The system remains fully stable through prolonged idle periods, +high network load, active Bluetooth A2DP usage, and multiple deep +suspend/resume cycles. + - Zero h2c timeouts or firmware lps state errors observed in dmesg. + +Reported-by: Oleksandr Havrylov +Closes: https://lore.kernel.org/linux-wireless/CALdGYqSMUPnPfW-_q1RgYr0_SjoXUejAaJJr-o+jpwCk1S7ndQ@mail.gmail.com/ +Tested-by: Oleksandr Havrylov +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260324011001.5742-1-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw88/rx.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c +index 8b0afaaffaa0e..d9e11343d4988 100644 +--- a/drivers/net/wireless/realtek/rtw88/rx.c ++++ b/drivers/net/wireless/realtek/rtw88/rx.c +@@ -295,6 +295,14 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + + pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL); + ++ if (unlikely(pkt_stat->rate >= DESC_RATE_MAX)) { ++ rtw_dbg(rtwdev, RTW_DBG_UNEXP, ++ "unexpected RX rate=0x%x\n", pkt_stat->rate); ++ ++ pkt_stat->rate = DESC_RATE1M; ++ pkt_stat->bw = RTW_CHANNEL_WIDTH_20; ++ } ++ + /* drv_info_sz is in unit of 8-bytes */ + pkt_stat->drv_info_sz *= 8; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-add-support-for-buffalo-wi-u3-2400xe2.patch b/queue-7.0/wifi-rtw89-add-support-for-buffalo-wi-u3-2400xe2.patch new file mode 100644 index 0000000000..83c17f43bb --- /dev/null +++ b/queue-7.0/wifi-rtw89-add-support-for-buffalo-wi-u3-2400xe2.patch @@ -0,0 +1,37 @@ +From 35474e47dff23af10ea3cf7bfdfbd82f1e92e329 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:41:36 +0800 +Subject: wifi: rtw89: Add support for Buffalo WI-U3-2400XE2 + +From: Zenm Chen + +[ Upstream commit aefb20749074731c4f35444761e730991f1b8c77 ] + +Add the ID 0411:03a6 to the table to support an additional RTL8832CU +adapter: Buffalo WI-U3-2400XE2. + +Link: https://github.com/morrownr/rtw89/commit/506d193b8cb7d6394509aebcf8de1531629f6100 +Signed-off-by: Zenm Chen +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260320154136.5750-1-zenmchen@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/rtw8852cu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +index 3b9825c92a0d9..a485dacbb0531 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +@@ -38,6 +38,8 @@ static const struct rtw89_driver_info rtw89_8852cu_info = { + }; + + static const struct usb_device_id rtw_8852cu_id_table[] = { ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03a6, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc832, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc85a, 0xff, 0xff, 0xff), +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-add-support-for-elecom-wdc-xe2402tu3-b.patch b/queue-7.0/wifi-rtw89-add-support-for-elecom-wdc-xe2402tu3-b.patch new file mode 100644 index 0000000000..c13236cea9 --- /dev/null +++ b/queue-7.0/wifi-rtw89-add-support-for-elecom-wdc-xe2402tu3-b.patch @@ -0,0 +1,37 @@ +From 41ac089b6f468705ad0e1eb07cd377fd31c17c31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 17:34:39 +0800 +Subject: wifi: rtw89: Add support for Elecom WDC-XE2402TU3-B + +From: Zenm Chen + +[ Upstream commit 4e4fc2149b0a983670fd99bbd549012839bda79e ] + +Add the ID 056e:4024 to the table to support an additional RTL8832CU +adapter: Elecom WDC-XE2402TU3-B. + +Link: https://github.com/morrownr/rtw89/commit/55c059e2bd49acd5cf93edbc8eda7b9e042f4efd +Signed-off-by: Zenm Chen +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260330093440.3615-1-zenmchen@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/rtw8852cu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +index 314ea7f0ba72d..d0795da154594 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +@@ -40,6 +40,8 @@ static const struct rtw89_driver_info rtw89_8852cu_info = { + static const struct usb_device_id rtw_8852cu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03a6, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, ++ { USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4024, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc832, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc85a, 0xff, 0xff, 0xff), +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-add-support-for-tp-link-archer-tx50u.patch b/queue-7.0/wifi-rtw89-add-support-for-tp-link-archer-tx50u.patch new file mode 100644 index 0000000000..5788348dd3 --- /dev/null +++ b/queue-7.0/wifi-rtw89-add-support-for-tp-link-archer-tx50u.patch @@ -0,0 +1,37 @@ +From 38d9d59476c6b62c4e906e5c31c46a4f729c978c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 17:31:22 +0800 +Subject: wifi: rtw89: Add support for TP-Link Archer TX50U + +From: Zenm Chen + +[ Upstream commit 6678828eb78f3ae0bc6db90436068d5fd0387703 ] + +Add the ID 37ad:0103 to the table to support an additional RTL8832CU +adapter: TP-Link Archer TX50U. + +Link: https://github.com/morrownr/rtl8852cu-20251113/issues/2 +Signed-off-by: Zenm Chen +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260320093122.6754-1-zenmchen@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/rtw8852cu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +index a485dacbb0531..314ea7f0ba72d 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c +@@ -56,6 +56,8 @@ static const struct usb_device_id rtw_8852cu_id_table[] = { + .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0102, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, ++ { USB_DEVICE_AND_INTERFACE_INFO(0x37ad, 0x0103, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info }, + {}, + }; + MODULE_DEVICE_TABLE(usb, rtw_8852cu_id_table); +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-mac-remove-a-die-off-setting-for-rtl8852c.patch b/queue-7.0/wifi-rtw89-mac-remove-a-die-off-setting-for-rtl8852c.patch new file mode 100644 index 0000000000..9eb2f41224 --- /dev/null +++ b/queue-7.0/wifi-rtw89-mac-remove-a-die-off-setting-for-rtl8852c.patch @@ -0,0 +1,49 @@ +From ba4c740d22ba72c63f01437d98e0ff7b1297094c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:01:36 +0800 +Subject: wifi: rtw89: mac: remove A-die off setting for RTL8852C and RTL8922A + +From: Ping-Ke Shih + +[ Upstream commit 9a38ef92aaa2d3c02ae1f6f1cacc3d3a8cf19db6 ] + +Fix timing issue of A-die off followed by XTAL off. Otherwise, device might +get lost potentially. + +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260310080146.31113-4-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c +index de5d343f80a57..896801879328d 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c +@@ -463,7 +463,7 @@ static int rtw8852c_pwr_off_func(struct rtw89_dev *rtwdev) + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); + +- rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_XTAL_OFF_A_DIE); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_XTAL_OFF_A_DIE); + rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, + B_AX_REG_ZCDC_H_MASK, 0x3); +diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c +index f41b66b362c4e..fd9cb5c281d3b 100644 +--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c ++++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c +@@ -492,7 +492,7 @@ static int rtw8922a_pwr_off_func(struct rtw89_dev *rtwdev) + return ret; + + rtw89_write32(rtwdev, R_BE_WLLPS_CTRL, 0x0000A1B2); +- rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE); ++ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + rtw89_write32(rtwdev, R_BE_UDM1, 0); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch b/queue-7.0/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch new file mode 100644 index 0000000000..e6840b9264 --- /dev/null +++ b/queue-7.0/wifi-rtw89-retry-efuse-physical-map-dump-on-transien.patch @@ -0,0 +1,78 @@ +From 098a310ee0c7454703386317aad8086c36de4f23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:21:55 +0000 +Subject: wifi: rtw89: retry efuse physical map dump on transient failure + +From: Christian Hewitt + +[ Upstream commit d92f6ad6483e6d430c8273eeb7be97ce85244bd5 ] + +On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse +physical map dump intermittently fails with -EBUSY during probe. +The failure occurs in rtw89_dump_physical_efuse_map_ddv() where +read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY +bit after 1 second. + +The root cause is a timing race during boot: the WiFi driver's +chip initialization (firmware download via PCIe) overlaps with +Bluetooth firmware download to the same combo chip via USB. This +can leave the efuse controller temporarily unavailable when the +WiFi driver attempts to read the efuse map. + +The firmware download path retries up to 5 times, but the efuse +read that follows has no similar logic. Address this by adding +retry loop logic (also up to 5 attempts) around physical efuse +map dump. + +Signed-off-by: Christian Hewitt +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260317112155.1939569-1-christianshewitt@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/efuse.c | 23 ++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c +index a2757a88d55da..89d4b1b865f8f 100644 +--- a/drivers/net/wireless/realtek/rtw89/efuse.c ++++ b/drivers/net/wireless/realtek/rtw89/efuse.c +@@ -185,8 +185,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + +-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, +- u32 dump_addr, u32 dump_size, bool dav) ++static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) + { + int ret; + +@@ -208,6 +208,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, + return 0; + } + ++static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ++ u32 dump_addr, u32 dump_size, bool dav) ++{ ++ int retry; ++ int ret; ++ ++ for (retry = 0; retry < 5; retry++) { ++ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr, ++ dump_size, dav); ++ if (!ret) ++ return 0; ++ ++ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n", ++ dav, retry); ++ } ++ ++ return ret; ++} ++ + #define invalid_efuse_header(hdr1, hdr2) \ + ((hdr1) == 0xff || (hdr2) == 0xff) + #define invalid_efuse_content(word_en, i) \ +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch b/queue-7.0/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch new file mode 100644 index 0000000000..4e21aa64d1 --- /dev/null +++ b/queue-7.0/wifi-rtw89-ser-wi-fi-7-reset-halt-c2h-after-reading-.patch @@ -0,0 +1,53 @@ +From 494cf5edba10803be890f951779bdd7016f3e5ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 14:15:51 +0800 +Subject: wifi: rtw89: ser: Wi-Fi 7 reset HALT C2H after reading it + +From: Zong-Zhe Yang + +[ Upstream commit 0cae26a78b14fe1292b0f50f28ebabe6801f3885 ] + +When a SER (system error recovery) interrupt happens, driver reads HALT C2H +register to get the error status via MAC. For Wi-Fi 7 chipset, driver needs +to reset HALT C2H register after reading it to make FW aware that. + +Signed-off-by: Zong-Zhe Yang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260213061552.29997-12-pkshih@realtek.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/mac.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c +index 8472f1a63951b..fa60f8e8bb3d4 100644 +--- a/drivers/net/wireless/realtek/rtw89/mac.c ++++ b/drivers/net/wireless/realtek/rtw89/mac.c +@@ -814,6 +814,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; ++ const struct rtw89_chip_info *chip = rtwdev->chip; + u32 err, err_scnr; + int ret; + +@@ -836,11 +837,15 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) + err = MAC_AX_ERR_RXI300; + + if (rtw89_mac_suppress_log(rtwdev, err)) +- return err; ++ goto bottom; + + rtw89_fw_st_dbg_dump(rtwdev); + mac->dump_err_status(rtwdev, err); + ++bottom: ++ if (chip->chip_gen != RTW89_CHIP_AX) ++ rtw89_write32(rtwdev, R_AX_HALT_C2H, 0); ++ + return err; + } + EXPORT_SYMBOL(rtw89_mac_get_err_status); +-- +2.53.0 + diff --git a/queue-7.0/x86-mce-restore-mca-polling-interval-halving.patch b/queue-7.0/x86-mce-restore-mca-polling-interval-halving.patch new file mode 100644 index 0000000000..c7a05fe4a2 --- /dev/null +++ b/queue-7.0/x86-mce-restore-mca-polling-interval-halving.patch @@ -0,0 +1,138 @@ +From b23a2e032ab37263b3eca396f573c6b587bb1f14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 16:12:00 +0100 +Subject: x86/mce: Restore MCA polling interval halving + +From: Borislav Petkov (AMD) + +[ Upstream commit ea324444ece9f301b5c4ff71b258cc68990c4d61 ] + +RongQing reported that the MCA polling interval doesn't halve when an +error gets logged. It was traced down to the commit in Fixes:, because: + + mce_timer_fn() + |-> mce_poll_banks() + |-> machine_check_poll() + |-> mce_log() + +which will queue the work and return. + +Now, back in mce_timer_fn(): + + /* + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ + if (mce_notify_irq()) + +<--- here we haven't ran the notifier chain yet so mce_need_notify is +not set yet so this won't hit and we won't halve the interval iv. + +Now the notifier chain runs. mce_early_notifier() sets the bit, does +mce_notify_irq(), that clears the bit and then the notifier chain +a little later logs the error. + +So this is a silly timing issue. + +But, that's all unnecessary. + +All it needs to happen here is, the "should we notify of a logged MCE" +mce_notify_irq() asks, should be simply a question to the mce gen pool: +"Are you empty?" + +And that then turns into a simple yes or no answer and it all +JustWorks(tm). + +So do that and also distribute the functionality where it belongs: + - Print that MCE events have been logged in mce_log() + - Trigger the mcelog tool specific work in the first notifier + +As a result, mce_notify_irq() can go now. + +Fixes: 011d82611172 ("RAS: Add a Corrected Errors Collector") +Reported-by: Li RongQing +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Qiuxu Zhuo +Tested-by: Qiuxu Zhuo +Link: https://lore.kernel.org/r/20260112082747.2842-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/core.c | 33 +++++---------------------------- + 1 file changed, 5 insertions(+), 28 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 8dd424ac5de8a..f3a793e3a6c8f 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -90,7 +90,6 @@ struct mca_config mca_cfg __read_mostly = { + }; + + static DEFINE_PER_CPU(struct mce_hw_err, hw_errs_seen); +-static unsigned long mce_need_notify; + + /* + * MCA banks polled by the period polling timer for corrected events. +@@ -152,8 +151,10 @@ EXPORT_PER_CPU_SYMBOL_GPL(injectm); + + void mce_log(struct mce_hw_err *err) + { +- if (mce_gen_pool_add(err)) ++ if (mce_gen_pool_add(err)) { ++ pr_info(HW_ERR "Machine check events logged\n"); + irq_work_queue(&mce_irq_work); ++ } + } + EXPORT_SYMBOL_GPL(mce_log); + +@@ -585,28 +586,6 @@ bool mce_is_correctable(struct mce *m) + } + EXPORT_SYMBOL_GPL(mce_is_correctable); + +-/* +- * Notify the user(s) about new machine check events. +- * Can be called from interrupt context, but not from machine check/NMI +- * context. +- */ +-static bool mce_notify_irq(void) +-{ +- /* Not more than two messages every minute */ +- static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); +- +- if (test_and_clear_bit(0, &mce_need_notify)) { +- mce_work_trigger(); +- +- if (__ratelimit(&ratelimit)) +- pr_info(HW_ERR "Machine check events logged\n"); +- +- return true; +- } +- +- return false; +-} +- + static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + void *data) + { +@@ -618,9 +597,7 @@ static int mce_early_notifier(struct notifier_block *nb, unsigned long val, + /* Emit the trace record: */ + trace_mce_record(err); + +- set_bit(0, &mce_need_notify); +- +- mce_notify_irq(); ++ mce_work_trigger(); + + return NOTIFY_DONE; + } +@@ -1804,7 +1781,7 @@ static void mce_timer_fn(struct timer_list *t) + * Alert userspace if needed. If we logged an MCE, reduce the polling + * interval, otherwise increase the polling interval. + */ +- if (mce_notify_irq()) ++ if (!mce_gen_pool_empty()) + iv = max(iv / 2, (unsigned long) HZ/100); + else + iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); +-- +2.53.0 + diff --git a/queue-7.0/x86-xen-fix-xen_e820_swap_entry_with_ram.patch b/queue-7.0/x86-xen-fix-xen_e820_swap_entry_with_ram.patch new file mode 100644 index 0000000000..ab38c0daaa --- /dev/null +++ b/queue-7.0/x86-xen-fix-xen_e820_swap_entry_with_ram.patch @@ -0,0 +1,39 @@ +From d88597ae3d67b511c7648435ec3a6b64fa09acd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 May 2026 12:24:17 +0200 +Subject: x86/xen: Fix xen_e820_swap_entry_with_ram() + +From: Juergen Gross + +[ Upstream commit 28e03f78e69cf6628b81f24777799778528a84c1 ] + +When swapping a not page-aligned E820 map entry with RAM, the start +address of the modified entry is calculated wrong (the offset into the +page is subtracted instead of being added to the page address). + +Fixes: be35d91c8880 ("xen: tolerate ACPI NVS memory overlapping with Xen allocated memory") +Reported-by: Jan Beulich +Reviewed-by: Jan Beulich +Signed-off-by: Juergen Gross +Message-ID: <20260505102417.208138-1-jgross@suse.com> +Signed-off-by: Sasha Levin +--- + arch/x86/xen/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index ac8021c3a997e..d4738e03a63a4 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -655,7 +655,7 @@ static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry) + /* Fill new entry (keep size and page offset). */ + entry->type = swap_entry->type; + entry->addr = entry_end - swap_size + +- swap_addr - swap_entry->addr; ++ swap_entry->addr - swap_addr; + entry->size = swap_entry->size; + + /* Convert old entry to RAM, align to pages. */ +-- +2.53.0 +