]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.13
authorSasha Levin <sashal@kernel.org>
Sun, 9 Mar 2025 19:40:19 +0000 (15:40 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 9 Mar 2025 19:40:19 +0000 (15:40 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
75 files changed:
queue-6.13/alsa-hda-realtek-remove-revert-duplicate-ally-x-conf.patch [new file with mode: 0644]
queue-6.13/alsa-usx2y-validate-nrpacks-module-parameter-on-prob.patch [new file with mode: 0644]
queue-6.13/be2net-fix-sleeping-while-atomic-bugs-in-be_ndo_brid.patch [new file with mode: 0644]
queue-6.13/bluetooth-btusb-initialize-.owner-field-of-force_pol.patch [new file with mode: 0644]
queue-6.13/caif_virtio-fix-wrong-pointer-check-in-cfv_probe.patch [new file with mode: 0644]
queue-6.13/coredump-only-sort-vmas-when-core_sort_vma-sysctl-is.patch [new file with mode: 0644]
queue-6.13/cred-fix-rcu-warnings-in-override-revert_creds.patch [new file with mode: 0644]
queue-6.13/cred-return-old-creds-from-revert_creds_light.patch [new file with mode: 0644]
queue-6.13/drm-bochs-fix-dpms-regression.patch [new file with mode: 0644]
queue-6.13/drm-imagination-fix-timestamps-in-firmware-traces.patch [new file with mode: 0644]
queue-6.13/drm-nouveau-select-fw-caching.patch [new file with mode: 0644]
queue-6.13/drm-sched-fix-preprocessor-guard.patch [new file with mode: 0644]
queue-6.13/drm-xe-remove-double-pageflip.patch [new file with mode: 0644]
queue-6.13/ethtool-linkstate-migrate-linkstate-functions-to-sup.patch [new file with mode: 0644]
queue-6.13/exfat-fix-just-enough-dentries-but-allocate-a-new-cl.patch [new file with mode: 0644]
queue-6.13/exfat-fix-soft-lockup-in-exfat_clear_bitmap.patch [new file with mode: 0644]
queue-6.13/exfat-short-circuit-zero-byte-writes-in-exfat_file_w.patch [new file with mode: 0644]
queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch [new file with mode: 0644]
queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch [new file with mode: 0644]
queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch [new file with mode: 0644]
queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch [new file with mode: 0644]
queue-6.13/fs-pipe-do-not-open-code-pipe-head-tail-logic-in-fio.patch [new file with mode: 0644]
queue-6.13/fs-pipe-fix-pipe-buffer-index-use-in-fuse.patch [new file with mode: 0644]
queue-6.13/fs-pipe-fix-pipe_occupancy-with-16-bit-indexes.patch [new file with mode: 0644]
queue-6.13/fs-pipe-read-pipe-head-tail-atomically-outside-pipe-.patch [new file with mode: 0644]
queue-6.13/gpio-rcar-fix-missing-of_node_put-call.patch [new file with mode: 0644]
queue-6.13/hid-google-fix-unused-variable-warning-under-config_.patch [new file with mode: 0644]
queue-6.13/hid-hid-steam-fix-use-after-free-when-detaching-devi.patch [new file with mode: 0644]
queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-hid_is.patch [new file with mode: 0644]
queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-ishtp_.patch [new file with mode: 0644]
queue-6.13/hwmon-ad7314-validate-leading-zero-bits-and-return-e.patch [new file with mode: 0644]
queue-6.13/hwmon-fix-a-null-vs-is_err_or_null-check-in-xgene_hw.patch [new file with mode: 0644]
queue-6.13/hwmon-ntc_thermistor-fix-the-ncpxxxh103-sensor-table.patch [new file with mode: 0644]
queue-6.13/hwmon-pmbus-initialise-page-count-in-pmbus_identify.patch [new file with mode: 0644]
queue-6.13/llc-do-not-use-skb_get-before-dev_queue_xmit.patch [new file with mode: 0644]
queue-6.13/mctp-i3c-handle-null-header-address.patch [new file with mode: 0644]
queue-6.13/net-dsa-mt7530-fix-traffic-flooding-for-mmio-devices.patch [new file with mode: 0644]
queue-6.13/net-ethtool-netlink-allow-null-nlattrs-when-getting-.patch [new file with mode: 0644]
queue-6.13/net-ethtool-plumb-phy-stats-to-phy-drivers.patch [new file with mode: 0644]
queue-6.13/net-gso-fix-ownership-in-__udp_gso_segment.patch [new file with mode: 0644]
queue-6.13/net-hns3-make-sure-ptp-clock-is-unregister-and-freed.patch [new file with mode: 0644]
queue-6.13/net-ipa-enable-checksum-for-ipa_endpoint_ap_modem_-r.patch [new file with mode: 0644]
queue-6.13/net-ipa-fix-qsb-data-for-v4.7.patch [new file with mode: 0644]
queue-6.13/net-ipa-fix-v4.7-resource-group-names.patch [new file with mode: 0644]
queue-6.13/net-ipv6-fix-dst-ref-loop-in-ila-lwtunnel.patch [new file with mode: 0644]
queue-6.13/net-ipv6-fix-missing-dst-ref-drop-in-ila-lwtunnel.patch [new file with mode: 0644]
queue-6.13/net-timestamp-support-tcp-gso-case-for-a-few-missing.patch [new file with mode: 0644]
queue-6.13/nvme-ioctl-fix-leaked-requests-on-mapping-error.patch [new file with mode: 0644]
queue-6.13/nvme-tcp-add-basic-support-for-the-c2htermreq-pdu.patch [new file with mode: 0644]
queue-6.13/nvme-tcp-fix-potential-memory-corruption-in-nvme_tcp.patch [new file with mode: 0644]
queue-6.13/nvme-tcp-fix-signedness-bug-in-nvme_tcp_init_connect.patch [new file with mode: 0644]
queue-6.13/nvmet-remove-old-function-prototype.patch [new file with mode: 0644]
queue-6.13/nvmet-tcp-fix-a-possible-sporadic-response-drops-in-.patch [new file with mode: 0644]
queue-6.13/perf-core-fix-pmus_lock-vs.-pmus_srcu-ordering.patch [new file with mode: 0644]
queue-6.13/ppp-fix-kmsan-uninit-value-warning-with-bpf.patch [new file with mode: 0644]
queue-6.13/sched-fair-fix-potential-memory-corruption-in-child_.patch [new file with mode: 0644]
queue-6.13/series
queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch [new file with mode: 0644]
queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch [new file with mode: 0644]
queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch [new file with mode: 0644]
queue-6.13/tracing-probe-events-remove-unused-max_arg_buf_len-m.patch [new file with mode: 0644]
queue-6.13/ublk-set_params-properly-check-if-parameters-can-be-.patch [new file with mode: 0644]
queue-6.13/vlan-enforce-underlying-device-type.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-fix-a-msdu-tso-preparation.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-free-pages-allocated-when-failing-to-bu.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-fw-avoid-using-an-uninitialized-variabl.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-limit-printed-string-from-fw-file.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-mvm-clean-up-roc-on-failure.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-mvm-don-t-dump-the-firmware-state-upon-.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-mvm-don-t-try-to-talk-to-a-dead-firmwar.patch [new file with mode: 0644]
queue-6.13/wifi-iwlwifi-mvm-log-error-for-failures-after-d3.patch [new file with mode: 0644]
queue-6.13/wifi-mac80211-fix-mle-non-inheritance-parsing.patch [new file with mode: 0644]
queue-6.13/wifi-mac80211-fix-vendor-specific-inheritance.patch [new file with mode: 0644]
queue-6.13/wifi-mac80211-support-parsing-epcs-ml-element.patch [new file with mode: 0644]
queue-6.13/x86-sgx-fix-size-overflows-in-sgx_encl_create.patch [new file with mode: 0644]

diff --git a/queue-6.13/alsa-hda-realtek-remove-revert-duplicate-ally-x-conf.patch b/queue-6.13/alsa-hda-realtek-remove-revert-duplicate-ally-x-conf.patch
new file mode 100644 (file)
index 0000000..cf203dc
--- /dev/null
@@ -0,0 +1,64 @@
+From 51274b4c540d884d00138de0599ebda1f127116c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 18:51:06 +0100
+Subject: ALSA: hda/realtek: Remove (revert) duplicate Ally X config
+
+From: Antheas Kapenekakis <lkml@antheas.dev>
+
+[ Upstream commit 3414cda9d41f41703832d0abd01063dd8de82b89 ]
+
+In commit 1e9c708dc3ae ("ALSA: hda/tas2781: Add new quirk for Lenovo,
+ASUS, Dell projects") Baojun adds a bunch of projects to the file,
+including for the Ally X. Turns out the initial Ally X was not sorted
+properly, so the kernel had 2 quirks for it.
+
+The previous quirk overrode the new one due to being earlier and they
+are different. When AB testing, the normal pin fixup seems to work ok
+but causes a bit of a minor popping. Given the other config is more
+complicated and may cause undefined behavior, revert it.
+
+Fixes: 1e9c708dc3ae ("ALSA: hda/tas2781: Add new quirk for Lenovo, ASUS, Dell projects")
+Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
+Link: https://patch.msgid.link/20250227175107.33432-2-lkml@antheas.dev
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 2cd606900b8b0..e86c4d894ea30 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -7761,7 +7761,6 @@ enum {
+       ALC285_FIXUP_THINKPAD_X1_GEN7,
+       ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       ALC294_FIXUP_ASUS_ALLY,
+-      ALC294_FIXUP_ASUS_ALLY_X,
+       ALC294_FIXUP_ASUS_ALLY_PINS,
+       ALC294_FIXUP_ASUS_ALLY_VERBS,
+       ALC294_FIXUP_ASUS_ALLY_SPEAKER,
+@@ -9206,12 +9205,6 @@ static const struct hda_fixup alc269_fixups[] = {
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
+       },
+-      [ALC294_FIXUP_ASUS_ALLY_X] = {
+-              .type = HDA_FIXUP_FUNC,
+-              .v.func = tas2781_fixup_i2c,
+-              .chained = true,
+-              .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
+-      },
+       [ALC294_FIXUP_ASUS_ALLY_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+@@ -10705,7 +10698,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
+       SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
+       SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
+-      SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X),
+       SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
+       SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+-- 
+2.39.5
+
diff --git a/queue-6.13/alsa-usx2y-validate-nrpacks-module-parameter-on-prob.patch b/queue-6.13/alsa-usx2y-validate-nrpacks-module-parameter-on-prob.patch
new file mode 100644 (file)
index 0000000..4dd82e1
--- /dev/null
@@ -0,0 +1,135 @@
+From 58650e6a19064173af6d4cb4a0751991e7b2170a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 13:04:13 +0300
+Subject: ALSA: usx2y: validate nrpacks module parameter on probe
+
+From: Murad Masimov <m.masimov@mt-integration.ru>
+
+[ Upstream commit 172a0f509723fe4741d4b8e9190cf434b18320d8 ]
+
+The module parameter defines number of iso packets per one URB. User is
+allowed to set any value to the parameter of type int, which can lead to
+various kinds of weird and incorrect behavior like integer overflows,
+truncations, etc. Number of packets should be a small non-negative number.
+
+Since this parameter is read-only, its value can be validated on driver
+probe.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
+Link: https://patch.msgid.link/20250303100413.835-1-m.masimov@mt-integration.ru
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/usx2y/usbusx2y.c      | 11 +++++++++++
+ sound/usb/usx2y/usbusx2y.h      | 26 ++++++++++++++++++++++++++
+ sound/usb/usx2y/usbusx2yaudio.c | 27 ---------------------------
+ 3 files changed, 37 insertions(+), 27 deletions(-)
+
+diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
+index 5f81c68fd42b6..5756ff3528a2d 100644
+--- a/sound/usb/usx2y/usbusx2y.c
++++ b/sound/usb/usx2y/usbusx2y.c
+@@ -151,6 +151,12 @@ static int snd_usx2y_card_used[SNDRV_CARDS];
+ static void snd_usx2y_card_private_free(struct snd_card *card);
+ static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s);
++#ifdef USX2Y_NRPACKS_VARIABLE
++int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
++module_param(nrpacks, int, 0444);
++MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
++#endif
++
+ /*
+  * pipe 4 is used for switching the lamps, setting samplerate, volumes ....
+  */
+@@ -432,6 +438,11 @@ static int snd_usx2y_probe(struct usb_interface *intf,
+       struct snd_card *card;
+       int err;
++#ifdef USX2Y_NRPACKS_VARIABLE
++      if (nrpacks < 0 || nrpacks > USX2Y_NRPACKS_MAX)
++              return -EINVAL;
++#endif
++
+       if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
+           (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
+            le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
+diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
+index 391fd7b4ed5ef..6a76d04bf1c7d 100644
+--- a/sound/usb/usx2y/usbusx2y.h
++++ b/sound/usb/usx2y/usbusx2y.h
+@@ -7,6 +7,32 @@
+ #define NRURBS                2
++/* Default value used for nr of packs per urb.
++ * 1 to 4 have been tested ok on uhci.
++ * To use 3 on ohci, you'd need a patch:
++ * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
++ * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
++ *
++ * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
++ * Bigger is safer operation, smaller gives lower latencies.
++ */
++#define USX2Y_NRPACKS 4
++
++#define USX2Y_NRPACKS_MAX 1024
++
++/* If your system works ok with this module's parameter
++ * nrpacks set to 1, you might as well comment
++ * this define out, and thereby produce smaller, faster code.
++ * You'd also set USX2Y_NRPACKS to 1 then.
++ */
++#define USX2Y_NRPACKS_VARIABLE 1
++
++#ifdef USX2Y_NRPACKS_VARIABLE
++extern int nrpacks;
++#define nr_of_packs() nrpacks
++#else
++#define nr_of_packs() USX2Y_NRPACKS
++#endif
+ #define URBS_ASYNC_SEQ 10
+ #define URB_DATA_LEN_ASYNC_SEQ 32
+diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
+index f540f46a0b143..acca8bead82e5 100644
+--- a/sound/usb/usx2y/usbusx2yaudio.c
++++ b/sound/usb/usx2y/usbusx2yaudio.c
+@@ -28,33 +28,6 @@
+ #include "usx2y.h"
+ #include "usbusx2y.h"
+-/* Default value used for nr of packs per urb.
+- * 1 to 4 have been tested ok on uhci.
+- * To use 3 on ohci, you'd need a patch:
+- * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
+- * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
+- *
+- * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
+- * Bigger is safer operation, smaller gives lower latencies.
+- */
+-#define USX2Y_NRPACKS 4
+-
+-/* If your system works ok with this module's parameter
+- * nrpacks set to 1, you might as well comment
+- * this define out, and thereby produce smaller, faster code.
+- * You'd also set USX2Y_NRPACKS to 1 then.
+- */
+-#define USX2Y_NRPACKS_VARIABLE 1
+-
+-#ifdef USX2Y_NRPACKS_VARIABLE
+-static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
+-#define  nr_of_packs() nrpacks
+-module_param(nrpacks, int, 0444);
+-MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
+-#else
+-#define nr_of_packs() USX2Y_NRPACKS
+-#endif
+-
+ static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
+ {
+       struct urb      *urb = subs->completed_urb;
+-- 
+2.39.5
+
diff --git a/queue-6.13/be2net-fix-sleeping-while-atomic-bugs-in-be_ndo_brid.patch b/queue-6.13/be2net-fix-sleeping-while-atomic-bugs-in-be_ndo_brid.patch
new file mode 100644 (file)
index 0000000..448f7fb
--- /dev/null
@@ -0,0 +1,951 @@
+From 5df7c90854bc35b612180dada693200c38621609 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 18:41:29 +0200
+Subject: be2net: fix sleeping while atomic bugs in be_ndo_bridge_getlink
+
+From: Nikolay Aleksandrov <razor@blackwall.org>
+
+[ Upstream commit 1a82d19ca2d6835904ee71e2d40fd331098f94a0 ]
+
+Partially revert commit b71724147e73 ("be2net: replace polling with
+sleeping in the FW completion path") w.r.t mcc mutex it introduces and the
+use of usleep_range. The be2net be_ndo_bridge_getlink() callback is
+called with rcu_read_lock, so this code has been broken for a long time.
+Both the mutex_lock and the usleep_range can cause the issue Ian Kumlien
+reported[1]. The call path is:
+be_ndo_bridge_getlink -> be_cmd_get_hsw_config -> be_mcc_notify_wait ->
+be_mcc_wait_compl -> usleep_range()
+
+[1] https://lore.kernel.org/netdev/CAA85sZveppNgEVa_FD+qhOMtG_AavK9_mFiU+jWrMtXmwqefGA@mail.gmail.com/
+
+Tested-by: Ian Kumlien <ian.kumlien@gmail.com>
+Fixes: b71724147e73 ("be2net: replace polling with sleeping in the FW completion path")
+Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20250227164129.1201164-1-razor@blackwall.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/emulex/benet/be.h      |   2 +-
+ drivers/net/ethernet/emulex/benet/be_cmds.c | 197 ++++++++++----------
+ drivers/net/ethernet/emulex/benet/be_main.c |   2 +-
+ 3 files changed, 100 insertions(+), 101 deletions(-)
+
+diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
+index e48b861e4ce15..270ff9aab3352 100644
+--- a/drivers/net/ethernet/emulex/benet/be.h
++++ b/drivers/net/ethernet/emulex/benet/be.h
+@@ -562,7 +562,7 @@ struct be_adapter {
+       struct be_dma_mem mbox_mem_alloced;
+       struct be_mcc_obj mcc_obj;
+-      struct mutex mcc_lock;  /* For serializing mcc cmds to BE card */
++      spinlock_t mcc_lock;    /* For serializing mcc cmds to BE card */
+       spinlock_t mcc_cq_lock;
+       u16 cfg_num_rx_irqs;            /* configured via set-channels */
+diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
+index 61adcebeef010..51b8377edd1d0 100644
+--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
+@@ -575,7 +575,7 @@ int be_process_mcc(struct be_adapter *adapter)
+ /* Wait till no more pending mcc requests are present */
+ static int be_mcc_wait_compl(struct be_adapter *adapter)
+ {
+-#define mcc_timeout           12000 /* 12s timeout */
++#define mcc_timeout           120000 /* 12s timeout */
+       int i, status = 0;
+       struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+@@ -589,7 +589,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
+               if (atomic_read(&mcc_obj->q.used) == 0)
+                       break;
+-              usleep_range(500, 1000);
++              udelay(100);
+       }
+       if (i == mcc_timeout) {
+               dev_err(&adapter->pdev->dev, "FW not responding\n");
+@@ -866,7 +866,7 @@ static bool use_mcc(struct be_adapter *adapter)
+ static int be_cmd_lock(struct be_adapter *adapter)
+ {
+       if (use_mcc(adapter)) {
+-              mutex_lock(&adapter->mcc_lock);
++              spin_lock_bh(&adapter->mcc_lock);
+               return 0;
+       } else {
+               return mutex_lock_interruptible(&adapter->mbox_lock);
+@@ -877,7 +877,7 @@ static int be_cmd_lock(struct be_adapter *adapter)
+ static void be_cmd_unlock(struct be_adapter *adapter)
+ {
+       if (use_mcc(adapter))
+-              return mutex_unlock(&adapter->mcc_lock);
++              return spin_unlock_bh(&adapter->mcc_lock);
+       else
+               return mutex_unlock(&adapter->mbox_lock);
+ }
+@@ -1047,7 +1047,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
+       struct be_cmd_req_mac_query *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1076,7 +1076,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1088,7 +1088,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, const u8 *mac_addr,
+       struct be_cmd_req_pmac_add *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1113,7 +1113,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, const u8 *mac_addr,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST)
+               status = -EPERM;
+@@ -1131,7 +1131,7 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom)
+       if (pmac_id == -1)
+               return 0;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1151,7 +1151,7 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom)
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1414,7 +1414,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
+       struct be_dma_mem *q_mem = &rxq->dma_mem;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1444,7 +1444,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1508,7 +1508,7 @@ int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q)
+       struct be_cmd_req_q_destroy *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1525,7 +1525,7 @@ int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q)
+       q->created = false;
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1593,7 +1593,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
+       struct be_cmd_req_hdr *hdr;
+       int status = 0;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1621,7 +1621,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
+       adapter->stats_cmd_sent = true;
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1637,7 +1637,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
+                           CMD_SUBSYSTEM_ETH))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1660,7 +1660,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
+       adapter->stats_cmd_sent = true;
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1697,7 +1697,7 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed,
+       struct be_cmd_req_link_status *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       if (link_status)
+               *link_status = LINK_DOWN;
+@@ -1736,7 +1736,7 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1747,7 +1747,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
+       struct be_cmd_req_get_cntl_addnl_attribs *req;
+       int status = 0;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1762,7 +1762,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
+       status = be_mcc_notify(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1811,7 +1811,7 @@ int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf)
+       if (!get_fat_cmd.va)
+               return -ENOMEM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       while (total_size) {
+               buf_size = min(total_size, (u32)60 * 1024);
+@@ -1849,9 +1849,9 @@ int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf)
+               log_offset += buf_size;
+       }
+ err:
++      spin_unlock_bh(&adapter->mcc_lock);
+       dma_free_coherent(&adapter->pdev->dev, get_fat_cmd.size,
+                         get_fat_cmd.va, get_fat_cmd.dma);
+-      mutex_unlock(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1862,7 +1862,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter)
+       struct be_cmd_req_get_fw_version *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1885,7 +1885,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter)
+                       sizeof(adapter->fw_on_flash));
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1899,7 +1899,7 @@ static int __be_cmd_modify_eqd(struct be_adapter *adapter,
+       struct be_cmd_req_modify_eq_delay *req;
+       int status = 0, i;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1922,7 +1922,7 @@ static int __be_cmd_modify_eqd(struct be_adapter *adapter,
+       status = be_mcc_notify(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1949,7 +1949,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
+       struct be_cmd_req_vlan_config *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -1971,7 +1971,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -1982,7 +1982,7 @@ static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+       struct be_cmd_req_rx_filter *req = mem->va;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2015,7 +2015,7 @@ static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2046,7 +2046,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
+                           CMD_SUBSYSTEM_COMMON))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2066,7 +2066,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       if (base_status(status) == MCC_STATUS_FEATURE_NOT_SUPPORTED)
+               return  -EOPNOTSUPP;
+@@ -2085,7 +2085,7 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
+                           CMD_SUBSYSTEM_COMMON))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2108,7 +2108,7 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2189,7 +2189,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
+       if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS))
+               return 0;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2214,7 +2214,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2226,7 +2226,7 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
+       struct be_cmd_req_enable_disable_beacon *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2247,7 +2247,7 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2258,7 +2258,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
+       struct be_cmd_req_get_beacon_state *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2282,7 +2282,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2306,7 +2306,7 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
+               return -ENOMEM;
+       }
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2328,7 +2328,7 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
+               memcpy(data, resp->page_data + off, len);
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
+       return status;
+ }
+@@ -2345,7 +2345,7 @@ static int lancer_cmd_write_object(struct be_adapter *adapter,
+       void *ctxt = NULL;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       adapter->flash_status = 0;
+       wrb = wrb_from_mccq(adapter);
+@@ -2387,7 +2387,7 @@ static int lancer_cmd_write_object(struct be_adapter *adapter,
+       if (status)
+               goto err_unlock;
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       if (!wait_for_completion_timeout(&adapter->et_cmd_compl,
+                                        msecs_to_jiffies(60000)))
+@@ -2406,7 +2406,7 @@ static int lancer_cmd_write_object(struct be_adapter *adapter,
+       return status;
+ err_unlock:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2460,7 +2460,7 @@ static int lancer_cmd_delete_object(struct be_adapter *adapter,
+       struct be_mcc_wrb *wrb;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2478,7 +2478,7 @@ static int lancer_cmd_delete_object(struct be_adapter *adapter,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2491,7 +2491,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+       struct lancer_cmd_resp_read_object *resp;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2525,7 +2525,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+       }
+ err_unlock:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2537,7 +2537,7 @@ static int be_cmd_write_flashrom(struct be_adapter *adapter,
+       struct be_cmd_write_flashrom *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       adapter->flash_status = 0;
+       wrb = wrb_from_mccq(adapter);
+@@ -2562,7 +2562,7 @@ static int be_cmd_write_flashrom(struct be_adapter *adapter,
+       if (status)
+               goto err_unlock;
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       if (!wait_for_completion_timeout(&adapter->et_cmd_compl,
+                                        msecs_to_jiffies(40000)))
+@@ -2573,7 +2573,7 @@ static int be_cmd_write_flashrom(struct be_adapter *adapter,
+       return status;
+ err_unlock:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -2584,7 +2584,7 @@ static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
+       struct be_mcc_wrb *wrb;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -2611,7 +2611,7 @@ static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
+               memcpy(flashed_crc, req->crc, 4);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3217,7 +3217,7 @@ int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
+       struct be_cmd_req_acpi_wol_magic_config *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3234,7 +3234,7 @@ int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3249,7 +3249,7 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
+                           CMD_SUBSYSTEM_LOWLEVEL))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3272,7 +3272,7 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
+       if (status)
+               goto err_unlock;
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       if (!wait_for_completion_timeout(&adapter->et_cmd_compl,
+                                        msecs_to_jiffies(SET_LB_MODE_TIMEOUT)))
+@@ -3281,7 +3281,7 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
+       return status;
+ err_unlock:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3298,7 +3298,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
+                           CMD_SUBSYSTEM_LOWLEVEL))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3324,7 +3324,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
+       if (status)
+               goto err;
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       wait_for_completion(&adapter->et_cmd_compl);
+       resp = embedded_payload(wrb);
+@@ -3332,7 +3332,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
+       return status;
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3348,7 +3348,7 @@ int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
+                           CMD_SUBSYSTEM_LOWLEVEL))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3382,7 +3382,7 @@ int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3393,7 +3393,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+       struct be_cmd_req_seeprom_read *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3409,7 +3409,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3424,7 +3424,7 @@ int be_cmd_get_phy_info(struct be_adapter *adapter)
+                           CMD_SUBSYSTEM_COMMON))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3469,7 +3469,7 @@ int be_cmd_get_phy_info(struct be_adapter *adapter)
+       }
+       dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3479,7 +3479,7 @@ static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+       struct be_cmd_req_set_qos *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3499,7 +3499,7 @@ static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3611,7 +3611,7 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
+       struct be_cmd_req_get_fn_privileges *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3643,7 +3643,7 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3655,7 +3655,7 @@ int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
+       struct be_cmd_req_set_fn_privileges *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3675,7 +3675,7 @@ int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3707,7 +3707,7 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
+               return -ENOMEM;
+       }
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3771,7 +3771,7 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
+       }
+ out:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       dma_free_coherent(&adapter->pdev->dev, get_mac_list_cmd.size,
+                         get_mac_list_cmd.va, get_mac_list_cmd.dma);
+       return status;
+@@ -3831,7 +3831,7 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
+       if (!cmd.va)
+               return -ENOMEM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3853,7 +3853,7 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
+ err:
+       dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3889,7 +3889,7 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
+                           CMD_SUBSYSTEM_COMMON))
+               return -EPERM;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3930,7 +3930,7 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -3944,7 +3944,7 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
+       int status;
+       u16 vid;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -3991,7 +3991,7 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -4190,7 +4190,7 @@ int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
+       struct be_cmd_req_set_ext_fat_caps *req;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -4206,7 +4206,7 @@ int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -4684,7 +4684,7 @@ int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op)
+       if (iface == 0xFFFFFFFF)
+               return -1;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -4701,7 +4701,7 @@ int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op)
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -4735,7 +4735,7 @@ int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
+       struct be_cmd_resp_get_iface_list *resp;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -4756,7 +4756,7 @@ int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
+       }
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -4850,7 +4850,7 @@ int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
+       if (BEx_chip(adapter))
+               return 0;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -4868,7 +4868,7 @@ int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
+       req->enable = 1;
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -4941,7 +4941,7 @@ __be_cmd_set_logical_link_config(struct be_adapter *adapter,
+       u32 link_config = 0;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -4969,7 +4969,7 @@ __be_cmd_set_logical_link_config(struct be_adapter *adapter,
+       status = be_mcc_notify_wait(adapter);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -5000,8 +5000,7 @@ int be_cmd_set_features(struct be_adapter *adapter)
+       struct be_mcc_wrb *wrb;
+       int status;
+-      if (mutex_lock_interruptible(&adapter->mcc_lock))
+-              return -1;
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -5039,7 +5038,7 @@ int be_cmd_set_features(struct be_adapter *adapter)
+               dev_info(&adapter->pdev->dev,
+                        "Adapter does not support HW error recovery\n");
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+@@ -5053,7 +5052,7 @@ int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
+       struct be_cmd_resp_hdr *resp;
+       int status;
+-      mutex_lock(&adapter->mcc_lock);
++      spin_lock_bh(&adapter->mcc_lock);
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+@@ -5076,7 +5075,7 @@ int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
+       memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length);
+       be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length);
+ err:
+-      mutex_unlock(&adapter->mcc_lock);
++      spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+ }
+ EXPORT_SYMBOL(be_roce_mcc_cmd);
+diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
+index 875fe379eea21..3d2e215921191 100644
+--- a/drivers/net/ethernet/emulex/benet/be_main.c
++++ b/drivers/net/ethernet/emulex/benet/be_main.c
+@@ -5667,8 +5667,8 @@ static int be_drv_init(struct be_adapter *adapter)
+       }
+       mutex_init(&adapter->mbox_lock);
+-      mutex_init(&adapter->mcc_lock);
+       mutex_init(&adapter->rx_filter_lock);
++      spin_lock_init(&adapter->mcc_lock);
+       spin_lock_init(&adapter->mcc_cq_lock);
+       init_completion(&adapter->et_cmd_compl);
+-- 
+2.39.5
+
diff --git a/queue-6.13/bluetooth-btusb-initialize-.owner-field-of-force_pol.patch b/queue-6.13/bluetooth-btusb-initialize-.owner-field-of-force_pol.patch
new file mode 100644 (file)
index 0000000..03c4ddc
--- /dev/null
@@ -0,0 +1,35 @@
+From 20bea8103ada2df992147915056665341ac6b0df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 22:32:59 +0100
+Subject: bluetooth: btusb: Initialize .owner field of force_poll_sync_fops
+
+From: Salah Triki <salah.triki@gmail.com>
+
+[ Upstream commit cbf85b9cb80bec6345ffe0368dfff98386f4714f ]
+
+Initialize .owner field of force_poll_sync_fops to THIS_MODULE in order to
+prevent btusb from being unloaded while its operations are in use.
+
+Fixes: 800fe5ec302e ("Bluetooth: btusb: Add support for queuing during polling interval")
+Signed-off-by: Salah Triki <salah.triki@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index 72e85673b7095..75dbe07e07e21 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -3652,6 +3652,7 @@ static ssize_t force_poll_sync_write(struct file *file,
+ }
+ static const struct file_operations force_poll_sync_fops = {
++      .owner          = THIS_MODULE,
+       .open           = simple_open,
+       .read           = force_poll_sync_read,
+       .write          = force_poll_sync_write,
+-- 
+2.39.5
+
diff --git a/queue-6.13/caif_virtio-fix-wrong-pointer-check-in-cfv_probe.patch b/queue-6.13/caif_virtio-fix-wrong-pointer-check-in-cfv_probe.patch
new file mode 100644 (file)
index 0000000..67c72c2
--- /dev/null
@@ -0,0 +1,43 @@
+From 5e288daf3bc446c7488aafb8f21f7e662272553c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 23:46:27 +0500
+Subject: caif_virtio: fix wrong pointer check in cfv_probe()
+
+From: Vitaliy Shevtsov <v.shevtsov@mt-integration.ru>
+
+[ Upstream commit a466fd7e9fafd975949e5945e2f70c33a94b1a70 ]
+
+del_vqs() frees virtqueues, therefore cfv->vq_tx pointer should be checked
+for NULL before calling it, not cfv->vdev. Also the current implementation
+is redundant because the pointer cfv->vdev is dereferenced before it is
+checked for NULL.
+
+Fix this by checking cfv->vq_tx for NULL instead of cfv->vdev before
+calling del_vqs().
+
+Fixes: 0d2e1a2926b1 ("caif_virtio: Introduce caif over virtio")
+Signed-off-by: Vitaliy Shevtsov <v.shevtsov@mt-integration.ru>
+Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
+Link: https://patch.msgid.link/20250227184716.4715-1-v.shevtsov@mt-integration.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/caif/caif_virtio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
+index 7fea00c7ca8a6..c60386bf2d1a4 100644
+--- a/drivers/net/caif/caif_virtio.c
++++ b/drivers/net/caif/caif_virtio.c
+@@ -745,7 +745,7 @@ static int cfv_probe(struct virtio_device *vdev)
+       if (cfv->vr_rx)
+               vdev->vringh_config->del_vrhs(cfv->vdev);
+-      if (cfv->vdev)
++      if (cfv->vq_tx)
+               vdev->config->del_vqs(cfv->vdev);
+       free_netdev(netdev);
+       return err;
+-- 
+2.39.5
+
diff --git a/queue-6.13/coredump-only-sort-vmas-when-core_sort_vma-sysctl-is.patch b/queue-6.13/coredump-only-sort-vmas-when-core_sort_vma-sysctl-is.patch
new file mode 100644 (file)
index 0000000..b170dc7
--- /dev/null
@@ -0,0 +1,89 @@
+From 8712544b26ee025805cd83d2fc950db3f1a9f10a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 11:53:16 -0800
+Subject: coredump: Only sort VMAs when core_sort_vma sysctl is set
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 39ec9eaaa165d297d008d1fa385748430bd18e4d ]
+
+The sorting of VMAs by size in commit 7d442a33bfe8 ("binfmt_elf: Dump
+smaller VMAs first in ELF cores") breaks elfutils[1]. Instead, sort
+based on the setting of the new sysctl, core_sort_vma, which defaults
+to 0, no sorting.
+
+Reported-by: Michael Stapelberg <michael@stapelberg.ch>
+Closes: https://lore.kernel.org/all/20250218085407.61126-1-michael@stapelberg.de/ [1]
+Fixes: 7d442a33bfe8 ("binfmt_elf: Dump smaller VMAs first in ELF cores")
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/admin-guide/sysctl/kernel.rst | 11 +++++++++++
+ fs/coredump.c                               | 15 +++++++++++++--
+ 2 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
+index b2b36d0c3094d..7a85b6eb884ea 100644
+--- a/Documentation/admin-guide/sysctl/kernel.rst
++++ b/Documentation/admin-guide/sysctl/kernel.rst
+@@ -212,6 +212,17 @@ pid>/``).
+ This value defaults to 0.
++core_sort_vma
++=============
++
++The default coredump writes VMAs in address order. By setting
++``core_sort_vma`` to 1, VMAs will be written from smallest size
++to largest size. This is known to break at least elfutils, but
++can be handy when dealing with very large (and truncated)
++coredumps where the more useful debugging details are included
++in the smaller VMAs.
++
++
+ core_uses_pid
+ =============
+diff --git a/fs/coredump.c b/fs/coredump.c
+index d48edb37bc35c..c6f4c745e1bd8 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -63,6 +63,7 @@ static void free_vma_snapshot(struct coredump_params *cprm);
+ static int core_uses_pid;
+ static unsigned int core_pipe_limit;
++static unsigned int core_sort_vma;
+ static char core_pattern[CORENAME_MAX_SIZE] = "core";
+ static int core_name_size = CORENAME_MAX_SIZE;
+ unsigned int core_file_note_size_limit = CORE_FILE_NOTE_SIZE_DEFAULT;
+@@ -1026,6 +1027,15 @@ static struct ctl_table coredump_sysctls[] = {
+               .extra1         = (unsigned int *)&core_file_note_size_min,
+               .extra2         = (unsigned int *)&core_file_note_size_max,
+       },
++      {
++              .procname       = "core_sort_vma",
++              .data           = &core_sort_vma,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = proc_douintvec_minmax,
++              .extra1         = SYSCTL_ZERO,
++              .extra2         = SYSCTL_ONE,
++      },
+ };
+ static int __init init_fs_coredump_sysctls(void)
+@@ -1256,8 +1266,9 @@ static bool dump_vma_snapshot(struct coredump_params *cprm)
+               cprm->vma_data_size += m->dump_size;
+       }
+-      sort(cprm->vma_meta, cprm->vma_count, sizeof(*cprm->vma_meta),
+-              cmp_vma_size, NULL);
++      if (core_sort_vma)
++              sort(cprm->vma_meta, cprm->vma_count, sizeof(*cprm->vma_meta),
++                   cmp_vma_size, NULL);
+       return true;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.13/cred-fix-rcu-warnings-in-override-revert_creds.patch b/queue-6.13/cred-fix-rcu-warnings-in-override-revert_creds.patch
new file mode 100644 (file)
index 0000000..e31a928
--- /dev/null
@@ -0,0 +1,53 @@
+From 4ffaad7bd171912068e8b0c85cd327aa6c0501c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Mar 2025 15:18:24 +0800
+Subject: cred: Fix RCU warnings in override/revert_creds
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit e04918dc594669068f5d59d567d08db531167188 ]
+
+Fix RCU warnings in override_creds and revert_creds by turning
+the RCU pointer into a normal pointer using rcu_replace_pointer.
+
+These warnings were previously private to the cred code, but due
+to the move into the header file they are now polluting unrelated
+subsystems.
+
+Fixes: 49dffdfde462 ("cred: Add a light version of override/revert_creds()")
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Link: https://lore.kernel.org/r/Z8QGQGW0IaSklKG7@gondor.apana.org.au
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cred.h | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+diff --git a/include/linux/cred.h b/include/linux/cred.h
+index 382768a9707b5..1e1ec8834e454 100644
+--- a/include/linux/cred.h
++++ b/include/linux/cred.h
+@@ -179,18 +179,12 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
+  */
+ static inline const struct cred *override_creds_light(const struct cred *override_cred)
+ {
+-      const struct cred *old = current->cred;
+-
+-      rcu_assign_pointer(current->cred, override_cred);
+-      return old;
++      return rcu_replace_pointer(current->cred, override_cred, 1);
+ }
+ static inline const struct cred *revert_creds_light(const struct cred *revert_cred)
+ {
+-      const struct cred *override_cred = current->cred;
+-
+-      rcu_assign_pointer(current->cred, revert_cred);
+-      return override_cred;
++      return rcu_replace_pointer(current->cred, revert_cred, 1);
+ }
+ /**
+-- 
+2.39.5
+
diff --git a/queue-6.13/cred-return-old-creds-from-revert_creds_light.patch b/queue-6.13/cred-return-old-creds-from-revert_creds_light.patch
new file mode 100644 (file)
index 0000000..02d43f5
--- /dev/null
@@ -0,0 +1,43 @@
+From 17eef0c3ff364e08e48bee730ca7e66a9dccc3d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2024 15:09:58 +0100
+Subject: cred: return old creds from revert_creds_light()
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 95c54bc81791c210b131f2b1013942487e74896f ]
+
+So we can easily convert revert_creds() callers over to drop the
+reference count explicitly.
+
+Link: https://lore.kernel.org/r/20241125-work-cred-v2-2-68b9d38bb5b2@kernel.org
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Stable-dep-of: e04918dc5946 ("cred: Fix RCU warnings in override/revert_creds")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cred.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/cred.h b/include/linux/cred.h
+index e4a3155fe409d..382768a9707b5 100644
+--- a/include/linux/cred.h
++++ b/include/linux/cred.h
+@@ -185,9 +185,12 @@ static inline const struct cred *override_creds_light(const struct cred *overrid
+       return old;
+ }
+-static inline void revert_creds_light(const struct cred *revert_cred)
++static inline const struct cred *revert_creds_light(const struct cred *revert_cred)
+ {
++      const struct cred *override_cred = current->cred;
++
+       rcu_assign_pointer(current->cred, revert_cred);
++      return override_cred;
+ }
+ /**
+-- 
+2.39.5
+
diff --git a/queue-6.13/drm-bochs-fix-dpms-regression.patch b/queue-6.13/drm-bochs-fix-dpms-regression.patch
new file mode 100644 (file)
index 0000000..230bf1e
--- /dev/null
@@ -0,0 +1,50 @@
+From 8450eab7171bdac790f40def130960e1cd019bf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 14:41:57 +0100
+Subject: drm/bochs: Fix DPMS regression
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 80da96d735094ea22985ced98bc57fe3a4422921 ]
+
+The recent rewrite with the use of regular atomic helpers broke the
+DPMS unblanking on X11.  Fix it by moving the call of
+bochs_hw_blank(false) from CRTC mode_set_nofb() to atomic_enable().
+
+Fixes: 2037174993c8 ("drm/bochs: Use regular atomic helpers")
+Link: https://bugzilla.suse.com/show_bug.cgi?id=1238209
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250304134203.20534-1-tiwai@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/tiny/bochs.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
+index 6f91ff1dbf7e2..4e7d49fb9e6e6 100644
+--- a/drivers/gpu/drm/tiny/bochs.c
++++ b/drivers/gpu/drm/tiny/bochs.c
+@@ -335,8 +335,6 @@ static void bochs_hw_setmode(struct bochs_device *bochs, struct drm_display_mode
+                        bochs->xres, bochs->yres, bochs->bpp,
+                        bochs->yres_virtual);
+-      bochs_hw_blank(bochs, false);
+-
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
+@@ -506,6 +504,9 @@ static int bochs_crtc_helper_atomic_check(struct drm_crtc *crtc,
+ static void bochs_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+                                           struct drm_atomic_state *state)
+ {
++      struct bochs_device *bochs = to_bochs_device(crtc->dev);
++
++      bochs_hw_blank(bochs, false);
+ }
+ static void bochs_crtc_helper_atomic_disable(struct drm_crtc *crtc,
+-- 
+2.39.5
+
diff --git a/queue-6.13/drm-imagination-fix-timestamps-in-firmware-traces.patch b/queue-6.13/drm-imagination-fix-timestamps-in-firmware-traces.patch
new file mode 100644 (file)
index 0000000..04f1f0f
--- /dev/null
@@ -0,0 +1,59 @@
+From a47213ff79f6dc76216f4d69cd192cf8bdd8eb2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 10:49:35 +0000
+Subject: drm/imagination: Fix timestamps in firmware traces
+
+From: Alessio Belle <alessio.belle@imgtec.com>
+
+[ Upstream commit 1d2eabb6616433ccaa13927811bdfa205e91ba60 ]
+
+When firmware traces are enabled, the firmware dumps 48-bit timestamps
+for each trace as two 32-bit values, highest 32 bits (of which only 16
+useful) first.
+
+The driver was reassembling them the other way round i.e. interpreting
+the first value in memory as the lowest 32 bits, and the second value
+as the highest 32 bits (then truncated to 16 bits).
+
+Due to this, firmware trace dumps showed very large timestamps even for
+traces recorded shortly after GPU boot. The timestamps in these dumps
+would also sometimes jump backwards because of the truncation.
+
+Example trace dumped after loading the powervr module and enabling
+firmware traces, where each line is commented with the timestamp value
+in hexadecimal to better show both issues:
+
+[93540092739584] : Host Sync Partition marker: 1    // 0x551300000000
+[28419798597632] : GPU units deinit                 // 0x19d900000000
+[28548647616512] : GPU deinit                       // 0x19f700000000
+
+Update logic to reassemble the timestamps halves in the correct order.
+
+Fixes: cb56cd610866 ("drm/imagination: Add firmware trace to debugfs")
+Signed-off-by: Alessio Belle <alessio.belle@imgtec.com>
+Reviewed-by: Matt Coster <matt.coster@imgtec.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250221-fix-fw-trace-timestamps-v1-1-dba4aeb030ca@imgtec.com
+Signed-off-by: Matt Coster <matt.coster@imgtec.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/imagination/pvr_fw_trace.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c
+index 73707daa4e52d..5dbb636d7d4ff 100644
+--- a/drivers/gpu/drm/imagination/pvr_fw_trace.c
++++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c
+@@ -333,8 +333,8 @@ static int fw_trace_seq_show(struct seq_file *s, void *v)
+       if (sf_id == ROGUE_FW_SF_LAST)
+               return -EINVAL;
+-      timestamp = read_fw_trace(trace_seq_data, 1) |
+-              ((u64)read_fw_trace(trace_seq_data, 2) << 32);
++      timestamp = ((u64)read_fw_trace(trace_seq_data, 1) << 32) |
++              read_fw_trace(trace_seq_data, 2);
+       timestamp = (timestamp & ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK) >>
+               ROGUE_FWT_TIMESTAMP_TIME_SHIFT;
+-- 
+2.39.5
+
diff --git a/queue-6.13/drm-nouveau-select-fw-caching.patch b/queue-6.13/drm-nouveau-select-fw-caching.patch
new file mode 100644 (file)
index 0000000..1b87cc1
--- /dev/null
@@ -0,0 +1,37 @@
+From c54f61254dfcbb1b436482e42f16e5e2a8b160fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 11:25:31 +1000
+Subject: drm/nouveau: select FW caching
+
+From: Dave Airlie <airlied@redhat.com>
+
+[ Upstream commit 6b481ab0e6855fb30e2923c51f62f1662d1cda7e ]
+
+nouveau tries to load some firmware during suspend that it loaded
+earlier, but with fw caching disabled it hangs suspend, so just rely on
+FW cache enabling instead of working around it in the driver.
+
+Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM")
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250207012531.621369-1-airlied@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/nouveau/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
+index ce840300578d8..1050a4617fc15 100644
+--- a/drivers/gpu/drm/nouveau/Kconfig
++++ b/drivers/gpu/drm/nouveau/Kconfig
+@@ -4,6 +4,7 @@ config DRM_NOUVEAU
+       depends on DRM && PCI && MMU
+       select IOMMU_API
+       select FW_LOADER
++      select FW_CACHE if PM_SLEEP
+       select DRM_CLIENT_SELECTION
+       select DRM_DISPLAY_DP_HELPER
+       select DRM_DISPLAY_HDMI_HELPER
+-- 
+2.39.5
+
diff --git a/queue-6.13/drm-sched-fix-preprocessor-guard.patch b/queue-6.13/drm-sched-fix-preprocessor-guard.patch
new file mode 100644 (file)
index 0000000..ec0c424
--- /dev/null
@@ -0,0 +1,48 @@
+From bd73827fec0e65cb3e6da9b0c84c2c9ea77ba719 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 13:41:50 +0100
+Subject: drm/sched: Fix preprocessor guard
+
+From: Philipp Stanner <phasta@kernel.org>
+
+[ Upstream commit 23e0832d6d7be2d3c713f9390c060b6f1c48bf36 ]
+
+When writing the header guard for gpu_scheduler_trace.h, a typo,
+apparently, occurred.
+
+Fix the typo and document the scope of the guard.
+
+Fixes: 353da3c520b4 ("drm/amdgpu: add tracepoint for scheduler (v2)")
+Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Signed-off-by: Philipp Stanner <phasta@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250218124149.118002-2-phasta@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/scheduler/gpu_scheduler_trace.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h b/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h
+index c75302ca3427c..f56e77e7f6d02 100644
+--- a/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h
++++ b/drivers/gpu/drm/scheduler/gpu_scheduler_trace.h
+@@ -21,7 +21,7 @@
+  *
+  */
+-#if !defined(_GPU_SCHED_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
++#if !defined(_GPU_SCHED_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+ #define _GPU_SCHED_TRACE_H_
+ #include <linux/stringify.h>
+@@ -106,7 +106,7 @@ TRACE_EVENT(drm_sched_job_wait_dep,
+                     __entry->seqno)
+ );
+-#endif
++#endif /* _GPU_SCHED_TRACE_H_ */
+ /* This part must be outside protection */
+ #undef TRACE_INCLUDE_PATH
+-- 
+2.39.5
+
diff --git a/queue-6.13/drm-xe-remove-double-pageflip.patch b/queue-6.13/drm-xe-remove-double-pageflip.patch
new file mode 100644 (file)
index 0000000..c2768de
--- /dev/null
@@ -0,0 +1,58 @@
+From aa47c3a1a4a227d86e2e4e9b16c5b0d3b8606d4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Dec 2024 09:31:02 +0100
+Subject: drm/xe: Remove double pageflip
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Maarten Lankhorst <dev@lankhorst.se>
+
+[ Upstream commit 30bfc151f0c1ec80c27a80a7651b2c15c648ad16 ]
+
+This is already handled below in the code by fixup_initial_plane_config.
+
+Fixes: a8153627520a ("drm/i915: Try to relocate the BIOS fb to the start of ggtt")
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Reviewed-by: Vinod Govindapillai <vinod.govindapillai@intel.com>
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241210083111.230484-3-dev@lankhorst.se
+Signed-off-by: Maarten Lankhorst <dev@lankhorst.se>
+(cherry picked from commit 2218704997979fbf11765281ef752f07c5cf25bb)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_plane_initial.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_plane_initial.c b/drivers/gpu/drm/xe/display/xe_plane_initial.c
+index 8c113463a3d55..668f544a7ac80 100644
+--- a/drivers/gpu/drm/xe/display/xe_plane_initial.c
++++ b/drivers/gpu/drm/xe/display/xe_plane_initial.c
+@@ -194,8 +194,6 @@ intel_find_initial_plane_obj(struct intel_crtc *crtc,
+               to_intel_plane(crtc->base.primary);
+       struct intel_plane_state *plane_state =
+               to_intel_plane_state(plane->base.state);
+-      struct intel_crtc_state *crtc_state =
+-              to_intel_crtc_state(crtc->base.state);
+       struct drm_framebuffer *fb;
+       struct i915_vma *vma;
+@@ -241,14 +239,6 @@ intel_find_initial_plane_obj(struct intel_crtc *crtc,
+       atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
+       plane_config->vma = vma;
+-
+-      /*
+-       * Flip to the newly created mapping ASAP, so we can re-use the
+-       * first part of GGTT for WOPCM, prevent flickering, and prevent
+-       * the lookup of sysmem scratch pages.
+-       */
+-      plane->check_plane(crtc_state, plane_state);
+-      plane->async_flip(NULL, plane, crtc_state, plane_state, true);
+       return;
+ nofb:
+-- 
+2.39.5
+
diff --git a/queue-6.13/ethtool-linkstate-migrate-linkstate-functions-to-sup.patch b/queue-6.13/ethtool-linkstate-migrate-linkstate-functions-to-sup.patch
new file mode 100644 (file)
index 0000000..a5909f8
--- /dev/null
@@ -0,0 +1,100 @@
+From 0aa788e31f8f0ac2a82c7aa7fe01906afed461de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 07:05:11 +0100
+Subject: ethtool: linkstate: migrate linkstate functions to support multi-PHY
+ setups
+
+From: Oleksij Rempel <o.rempel@pengutronix.de>
+
+[ Upstream commit fe55b1d401c697c2ef126fe3ebbcaa6885fced5a ]
+
+Adapt linkstate_get_sqi() and linkstate_get_sqi_max() to take a
+phy_device argument directly, enabling support for setups with
+multiple PHYs. The previous assumption of a single PHY attached to
+a net_device no longer holds.
+
+Use ethnl_req_get_phydev() to identify the appropriate PHY device
+for the operation. Update linkstate_prepare_data() and related
+logic to accommodate this change, ensuring compatibility with
+multi-PHY configurations.
+
+Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 637399bf7e77 ("net: ethtool: netlink: Allow NULL nlattrs when getting a phy_device")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ethtool/linkstate.c | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c
+index 34d76e87847d0..459cfea7652d4 100644
+--- a/net/ethtool/linkstate.c
++++ b/net/ethtool/linkstate.c
+@@ -26,9 +26,8 @@ const struct nla_policy ethnl_linkstate_get_policy[] = {
+               NLA_POLICY_NESTED(ethnl_header_policy_stats),
+ };
+-static int linkstate_get_sqi(struct net_device *dev)
++static int linkstate_get_sqi(struct phy_device *phydev)
+ {
+-      struct phy_device *phydev = dev->phydev;
+       int ret;
+       if (!phydev)
+@@ -46,9 +45,8 @@ static int linkstate_get_sqi(struct net_device *dev)
+       return ret;
+ }
+-static int linkstate_get_sqi_max(struct net_device *dev)
++static int linkstate_get_sqi_max(struct phy_device *phydev)
+ {
+-      struct phy_device *phydev = dev->phydev;
+       int ret;
+       if (!phydev)
+@@ -100,19 +98,28 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
+ {
+       struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
+       struct net_device *dev = reply_base->dev;
++      struct nlattr **tb = info->attrs;
++      struct phy_device *phydev;
+       int ret;
++      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_LINKSTATE_HEADER],
++                                    info->extack);
++      if (IS_ERR(phydev)) {
++              ret = PTR_ERR(phydev);
++              goto out;
++      }
++
+       ret = ethnl_ops_begin(dev);
+       if (ret < 0)
+               return ret;
+       data->link = __ethtool_get_link(dev);
+-      ret = linkstate_get_sqi(dev);
++      ret = linkstate_get_sqi(phydev);
+       if (linkstate_sqi_critical_error(ret))
+               goto out;
+       data->sqi = ret;
+-      ret = linkstate_get_sqi_max(dev);
++      ret = linkstate_get_sqi_max(phydev);
+       if (linkstate_sqi_critical_error(ret))
+               goto out;
+       data->sqi_max = ret;
+@@ -127,9 +134,9 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
+                          sizeof(data->link_stats) / 8);
+       if (req_base->flags & ETHTOOL_FLAG_STATS) {
+-              if (dev->phydev)
++              if (phydev)
+                       data->link_stats.link_down_events =
+-                              READ_ONCE(dev->phydev->link_down_events);
++                              READ_ONCE(phydev->link_down_events);
+               if (dev->ethtool_ops->get_link_ext_stats)
+                       dev->ethtool_ops->get_link_ext_stats(dev,
+-- 
+2.39.5
+
diff --git a/queue-6.13/exfat-fix-just-enough-dentries-but-allocate-a-new-cl.patch b/queue-6.13/exfat-fix-just-enough-dentries-but-allocate-a-new-cl.patch
new file mode 100644 (file)
index 0000000..5e97282
--- /dev/null
@@ -0,0 +1,38 @@
+From 4cca8401e41774d3e64a945e1fa16bcc19d915d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 10:50:55 +0800
+Subject: exfat: fix just enough dentries but allocate a new cluster to dir
+
+From: Yuezhang Mo <Yuezhang.Mo@sony.com>
+
+[ Upstream commit 6697f819a10b238ccf01998c3f203d65d8374696 ]
+
+This commit fixes the condition for allocating cluster to parent
+directory to avoid allocating new cluster to parent directory when
+there are just enough empty directory entries at the end of the
+parent directory.
+
+Fixes: af02c72d0b62 ("exfat: convert exfat_find_empty_entry() to use dentry cache")
+Signed-off-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/namei.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
+index 099f806450721..9996ca61c85b7 100644
+--- a/fs/exfat/namei.c
++++ b/fs/exfat/namei.c
+@@ -237,7 +237,7 @@ static int exfat_search_empty_slot(struct super_block *sb,
+               dentry = 0;
+       }
+-      while (dentry + num_entries < total_entries &&
++      while (dentry + num_entries <= total_entries &&
+              clu.dir != EXFAT_EOF_CLUSTER) {
+               i = dentry & (dentries_per_clu - 1);
+-- 
+2.39.5
+
diff --git a/queue-6.13/exfat-fix-soft-lockup-in-exfat_clear_bitmap.patch b/queue-6.13/exfat-fix-soft-lockup-in-exfat_clear_bitmap.patch
new file mode 100644 (file)
index 0000000..5885b25
--- /dev/null
@@ -0,0 +1,129 @@
+From 9ce1e14704a01ce4edca97e41768f9b058ff562f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jan 2025 12:55:55 +0900
+Subject: exfat: fix soft lockup in exfat_clear_bitmap
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 9da33619e0ca53627641bc97d1b93ec741299111 ]
+
+bitmap clear loop will take long time in __exfat_free_cluster()
+if data size of file/dir enty is invalid.
+If cluster bit in bitmap is already clear, stop clearing bitmap go to
+out of loop.
+
+Fixes: 31023864e67a ("exfat: add fat entry operations")
+Reported-by: Kun Hu <huk23@m.fudan.edu.cn>, Jiaji Qin <jjtan24@m.fudan.edu.cn>
+Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/balloc.c   | 10 ++++++++--
+ fs/exfat/exfat_fs.h |  2 +-
+ fs/exfat/fatent.c   | 11 +++++++----
+ 3 files changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
+index ce9be95c9172f..9ff825f1502d5 100644
+--- a/fs/exfat/balloc.c
++++ b/fs/exfat/balloc.c
+@@ -141,7 +141,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync)
+       return 0;
+ }
+-void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
++int exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
+ {
+       int i, b;
+       unsigned int ent_idx;
+@@ -150,13 +150,17 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
+       struct exfat_mount_options *opts = &sbi->options;
+       if (!is_valid_cluster(sbi, clu))
+-              return;
++              return -EIO;
+       ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
+       i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
+       b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
++      if (!test_bit_le(b, sbi->vol_amap[i]->b_data))
++              return -EIO;
++
+       clear_bit_le(b, sbi->vol_amap[i]->b_data);
++
+       exfat_update_bh(sbi->vol_amap[i], sync);
+       if (opts->discard) {
+@@ -171,6 +175,8 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
+                       opts->discard = 0;
+               }
+       }
++
++      return 0;
+ }
+ /*
+diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
+index 78be6964a8a08..d30ce18a88b7a 100644
+--- a/fs/exfat/exfat_fs.h
++++ b/fs/exfat/exfat_fs.h
+@@ -456,7 +456,7 @@ int exfat_count_num_clusters(struct super_block *sb,
+ int exfat_load_bitmap(struct super_block *sb);
+ void exfat_free_bitmap(struct exfat_sb_info *sbi);
+ int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync);
+-void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
++int exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
+ unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
+ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
+ int exfat_trim_fs(struct inode *inode, struct fstrim_range *range);
+diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
+index 9e5492ac409b0..6f3651c6ca91e 100644
+--- a/fs/exfat/fatent.c
++++ b/fs/exfat/fatent.c
+@@ -175,6 +175,7 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain
+               BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu));
+       if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
++              int err;
+               unsigned int last_cluster = p_chain->dir + p_chain->size - 1;
+               do {
+                       bool sync = false;
+@@ -189,7 +190,9 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain
+                               cur_cmap_i = next_cmap_i;
+                       }
+-                      exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
++                      err = exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
++                      if (err)
++                              break;
+                       clu++;
+                       num_clusters++;
+               } while (num_clusters < p_chain->size);
+@@ -210,12 +213,13 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain
+                               cur_cmap_i = next_cmap_i;
+                       }
+-                      exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
++                      if (exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode))))
++                              break;
+                       clu = n_clu;
+                       num_clusters++;
+                       if (err)
+-                              goto dec_used_clus;
++                              break;
+                       if (num_clusters >= sbi->num_clusters - EXFAT_FIRST_CLUSTER) {
+                               /*
+@@ -229,7 +233,6 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain
+               } while (clu != EXFAT_EOF_CLUSTER);
+       }
+-dec_used_clus:
+       sbi->used_clusters -= num_clusters;
+       return 0;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.13/exfat-short-circuit-zero-byte-writes-in-exfat_file_w.patch b/queue-6.13/exfat-short-circuit-zero-byte-writes-in-exfat_file_w.patch
new file mode 100644 (file)
index 0000000..310cca1
--- /dev/null
@@ -0,0 +1,44 @@
+From 21846bfe892c62859c1a9f79456ecb23301dc31d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Feb 2025 14:14:21 -0600
+Subject: exfat: short-circuit zero-byte writes in exfat_file_write_iter
+
+From: Eric Sandeen <sandeen@redhat.com>
+
+[ Upstream commit fda94a9919fd632033979ad7765a99ae3cab9289 ]
+
+When generic_write_checks() returns zero, it means that
+iov_iter_count() is zero, and there is no work to do.
+
+Simply return success like all other filesystems do, rather than
+proceeding down the write path, which today yields an -EFAULT in
+generic_perform_write() via the
+(fault_in_iov_iter_readable(i, bytes) == bytes) check when bytes
+== 0.
+
+Fixes: 11a347fb6cef ("exfat: change to get file size from DataLength")
+Reported-by: Noah <kernel-org-10@maxgrass.eu>
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/file.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/exfat/file.c b/fs/exfat/file.c
+index 05b51e7217838..807349d8ea050 100644
+--- a/fs/exfat/file.c
++++ b/fs/exfat/file.c
+@@ -587,7 +587,7 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+       valid_size = ei->valid_size;
+       ret = generic_write_checks(iocb, iter);
+-      if (ret < 0)
++      if (ret <= 0)
+               goto unlock;
+       if (iocb->ki_flags & IOCB_DIRECT) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch b/queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch
new file mode 100644 (file)
index 0000000..6682a8c
--- /dev/null
@@ -0,0 +1,766 @@
+From 8d08d4ef90d31596e14da03d051eaa3dc100344a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:11:55 +0900
+Subject: fgraph: Replace fgraph_ret_regs with ftrace_regs
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit a3ed4157b7d89800a0008de0c9e46a438a5c3745 ]
+
+Use ftrace_regs instead of fgraph_ret_regs for tracing return value
+on function_graph tracer because of simplifying the callback interface.
+
+The CONFIG_HAVE_FUNCTION_GRAPH_RETVAL is also replaced by
+CONFIG_HAVE_FUNCTION_GRAPH_FREGS.
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Heiko Carstens <hca@linux.ibm.com>
+Acked-by: Will Deacon <will@kernel.org>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Florent Revest <revest@chromium.org>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Huacai Chen <chenhuacai@kernel.org>
+Cc: WANG Xuerui <kernel@xen0n.name>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: x86@kernel.org
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Link: https://lore.kernel.org/173518991508.391279.16635322774382197642.stgit@devnote2
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/Kconfig                  |  1 +
+ arch/arm64/include/asm/ftrace.h     | 23 ++++++---------------
+ arch/arm64/kernel/asm-offsets.c     | 12 -----------
+ arch/arm64/kernel/entry-ftrace.S    | 32 ++++++++++++++++-------------
+ arch/loongarch/Kconfig              |  2 +-
+ arch/loongarch/include/asm/ftrace.h | 26 ++++-------------------
+ arch/loongarch/kernel/asm-offsets.c | 12 -----------
+ arch/loongarch/kernel/mcount.S      | 17 ++++++++-------
+ arch/loongarch/kernel/mcount_dyn.S  | 14 ++++++-------
+ arch/riscv/Kconfig                  |  2 +-
+ arch/riscv/include/asm/ftrace.h     | 26 +++++------------------
+ arch/riscv/kernel/mcount.S          | 24 ++++++++++++----------
+ arch/s390/Kconfig                   |  2 +-
+ arch/s390/include/asm/ftrace.h      | 24 +++++++---------------
+ arch/s390/kernel/asm-offsets.c      |  6 ------
+ arch/s390/kernel/mcount.S           | 12 +++++------
+ arch/x86/Kconfig                    |  2 +-
+ arch/x86/include/asm/ftrace.h       | 20 ------------------
+ arch/x86/kernel/ftrace_32.S         | 13 ++++++------
+ arch/x86/kernel/ftrace_64.S         | 17 +++++++--------
+ include/linux/ftrace.h              | 12 ++++++++---
+ include/linux/ftrace_regs.h         |  2 ++
+ kernel/trace/Kconfig                |  4 ++--
+ kernel/trace/fgraph.c               | 21 ++++++++-----------
+ 24 files changed, 119 insertions(+), 207 deletions(-)
+
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 100570a048c5e..5f086777dad9b 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -219,6 +219,7 @@ config ARM64
+       select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_ERROR_INJECTION
++      select HAVE_FUNCTION_GRAPH_FREGS
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_GRAPH_RETVAL
+       select HAVE_GCC_PLUGINS
+diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
+index 5ccff4de7f091..b5fa57b61378e 100644
+--- a/arch/arm64/include/asm/ftrace.h
++++ b/arch/arm64/include/asm/ftrace.h
+@@ -129,6 +129,12 @@ ftrace_override_function_with_return(struct ftrace_regs *fregs)
+       arch_ftrace_regs(fregs)->pc = arch_ftrace_regs(fregs)->lr;
+ }
++static __always_inline unsigned long
++ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->fp;
++}
++
+ int ftrace_regs_query_register_offset(const char *name);
+ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+@@ -186,23 +192,6 @@ static inline bool arch_syscall_match_sym_name(const char *sym,
+ #ifndef __ASSEMBLY__
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-struct fgraph_ret_regs {
+-      /* x0 - x7 */
+-      unsigned long regs[8];
+-
+-      unsigned long fp;
+-      unsigned long __unused;
+-};
+-
+-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->regs[0];
+-}
+-
+-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->fp;
+-}
+ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
+                          unsigned long frame_pointer);
+diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
+index 29bf85dacffe1..eb1a840e4110f 100644
+--- a/arch/arm64/kernel/asm-offsets.c
++++ b/arch/arm64/kernel/asm-offsets.c
+@@ -179,18 +179,6 @@ int main(void)
+   DEFINE(FTRACE_OPS_FUNC,             offsetof(struct ftrace_ops, func));
+ #endif
+   BLANK();
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-  DEFINE(FGRET_REGS_X0,                       offsetof(struct fgraph_ret_regs, regs[0]));
+-  DEFINE(FGRET_REGS_X1,                       offsetof(struct fgraph_ret_regs, regs[1]));
+-  DEFINE(FGRET_REGS_X2,                       offsetof(struct fgraph_ret_regs, regs[2]));
+-  DEFINE(FGRET_REGS_X3,                       offsetof(struct fgraph_ret_regs, regs[3]));
+-  DEFINE(FGRET_REGS_X4,                       offsetof(struct fgraph_ret_regs, regs[4]));
+-  DEFINE(FGRET_REGS_X5,                       offsetof(struct fgraph_ret_regs, regs[5]));
+-  DEFINE(FGRET_REGS_X6,                       offsetof(struct fgraph_ret_regs, regs[6]));
+-  DEFINE(FGRET_REGS_X7,                       offsetof(struct fgraph_ret_regs, regs[7]));
+-  DEFINE(FGRET_REGS_FP,                       offsetof(struct fgraph_ret_regs, fp));
+-  DEFINE(FGRET_REGS_SIZE,             sizeof(struct fgraph_ret_regs));
+-#endif
+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+   DEFINE(FTRACE_OPS_DIRECT_CALL,      offsetof(struct ftrace_ops, direct_call));
+ #endif
+diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
+index f0c16640ef215..169ccf600066b 100644
+--- a/arch/arm64/kernel/entry-ftrace.S
++++ b/arch/arm64/kernel/entry-ftrace.S
+@@ -329,24 +329,28 @@ SYM_FUNC_END(ftrace_stub_graph)
+  * @fp is checked against the value passed by ftrace_graph_caller().
+  */
+ SYM_CODE_START(return_to_handler)
+-      /* save return value regs */
+-      sub sp, sp, #FGRET_REGS_SIZE
+-      stp x0, x1, [sp, #FGRET_REGS_X0]
+-      stp x2, x3, [sp, #FGRET_REGS_X2]
+-      stp x4, x5, [sp, #FGRET_REGS_X4]
+-      stp x6, x7, [sp, #FGRET_REGS_X6]
+-      str x29,    [sp, #FGRET_REGS_FP]        // parent's fp
++      /* Make room for ftrace_regs */
++      sub     sp, sp, #FREGS_SIZE
++
++      /* Save return value regs */
++      stp     x0, x1, [sp, #FREGS_X0]
++      stp     x2, x3, [sp, #FREGS_X2]
++      stp     x4, x5, [sp, #FREGS_X4]
++      stp     x6, x7, [sp, #FREGS_X6]
++
++      /* Save the callsite's FP */
++      str     x29, [sp, #FREGS_FP]
+       mov     x0, sp
+-      bl      ftrace_return_to_handler        // addr = ftrace_return_to_hander(regs);
++      bl      ftrace_return_to_handler        // addr = ftrace_return_to_hander(fregs);
+       mov     x30, x0                         // restore the original return address
+-      /* restore return value regs */
+-      ldp x0, x1, [sp, #FGRET_REGS_X0]
+-      ldp x2, x3, [sp, #FGRET_REGS_X2]
+-      ldp x4, x5, [sp, #FGRET_REGS_X4]
+-      ldp x6, x7, [sp, #FGRET_REGS_X6]
+-      add sp, sp, #FGRET_REGS_SIZE
++      /* Restore return value regs */
++      ldp     x0, x1, [sp, #FREGS_X0]
++      ldp     x2, x3, [sp, #FREGS_X2]
++      ldp     x4, x5, [sp, #FREGS_X4]
++      ldp     x6, x7, [sp, #FREGS_X6]
++      add     sp, sp, #FREGS_SIZE
+       ret
+ SYM_CODE_END(return_to_handler)
+diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
+index dae3a9104ca65..49f5bfc00e5a1 100644
+--- a/arch/loongarch/Kconfig
++++ b/arch/loongarch/Kconfig
+@@ -137,7 +137,7 @@ config LOONGARCH
+       select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_FUNCTION_ARG_ACCESS_API
+       select HAVE_FUNCTION_ERROR_INJECTION
+-      select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER
++      select HAVE_FUNCTION_GRAPH_FREGS
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER
+       select HAVE_GCC_PLUGINS
+diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
+index 8f13eaeaa3251..ceb3e3d9c0d3d 100644
+--- a/arch/loongarch/include/asm/ftrace.h
++++ b/arch/loongarch/include/asm/ftrace.h
+@@ -57,6 +57,10 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip)
+       instruction_pointer_set(&arch_ftrace_regs(fregs)->regs, ip);
+ }
++#undef ftrace_regs_get_frame_pointer
++#define ftrace_regs_get_frame_pointer(fregs) \
++      (arch_ftrace_regs(fregs)->regs.regs[22])
++
+ #define ftrace_graph_func ftrace_graph_func
+ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+                      struct ftrace_ops *op, struct ftrace_regs *fregs);
+@@ -78,26 +82,4 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
+ #endif /* CONFIG_FUNCTION_TRACER */
+-#ifndef __ASSEMBLY__
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-struct fgraph_ret_regs {
+-      /* a0 - a1 */
+-      unsigned long regs[2];
+-
+-      unsigned long fp;
+-      unsigned long __unused;
+-};
+-
+-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->regs[0];
+-}
+-
+-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->fp;
+-}
+-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */
+-#endif
+-
+ #endif /* _ASM_LOONGARCH_FTRACE_H */
+diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c
+index 049c5c3e370cb..8be1c38ad8eb2 100644
+--- a/arch/loongarch/kernel/asm-offsets.c
++++ b/arch/loongarch/kernel/asm-offsets.c
+@@ -280,18 +280,6 @@ static void __used output_pbe_defines(void)
+ }
+ #endif
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-static void __used output_fgraph_ret_regs_defines(void)
+-{
+-      COMMENT("LoongArch fgraph_ret_regs offsets.");
+-      OFFSET(FGRET_REGS_A0, fgraph_ret_regs, regs[0]);
+-      OFFSET(FGRET_REGS_A1, fgraph_ret_regs, regs[1]);
+-      OFFSET(FGRET_REGS_FP, fgraph_ret_regs, fp);
+-      DEFINE(FGRET_REGS_SIZE, sizeof(struct fgraph_ret_regs));
+-      BLANK();
+-}
+-#endif
+-
+ static void __used output_kvm_defines(void)
+ {
+       COMMENT("KVM/LoongArch Specific offsets.");
+diff --git a/arch/loongarch/kernel/mcount.S b/arch/loongarch/kernel/mcount.S
+index 3015896016a0b..b6850503e061b 100644
+--- a/arch/loongarch/kernel/mcount.S
++++ b/arch/loongarch/kernel/mcount.S
+@@ -79,10 +79,11 @@ SYM_FUNC_START(ftrace_graph_caller)
+ SYM_FUNC_END(ftrace_graph_caller)
+ SYM_FUNC_START(return_to_handler)
+-      PTR_ADDI        sp, sp, -FGRET_REGS_SIZE
+-      PTR_S           a0, sp, FGRET_REGS_A0
+-      PTR_S           a1, sp, FGRET_REGS_A1
+-      PTR_S           zero, sp, FGRET_REGS_FP
++      /* Save return value regs */
++      PTR_ADDI        sp, sp, -PT_SIZE
++      PTR_S           a0, sp, PT_R4
++      PTR_S           a1, sp, PT_R5
++      PTR_S           zero, sp, PT_R22
+       move            a0, sp
+       bl              ftrace_return_to_handler
+@@ -90,9 +91,11 @@ SYM_FUNC_START(return_to_handler)
+       /* Restore the real parent address: a0 -> ra */
+       move            ra, a0
+-      PTR_L           a0, sp, FGRET_REGS_A0
+-      PTR_L           a1, sp, FGRET_REGS_A1
+-      PTR_ADDI        sp, sp, FGRET_REGS_SIZE
++      /* Restore return value regs */
++      PTR_L           a0, sp, PT_R4
++      PTR_L           a1, sp, PT_R5
++      PTR_ADDI        sp, sp, PT_SIZE
++
+       jr              ra
+ SYM_FUNC_END(return_to_handler)
+ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S
+index 0c65cf09110cd..d6b474ad1d5e5 100644
+--- a/arch/loongarch/kernel/mcount_dyn.S
++++ b/arch/loongarch/kernel/mcount_dyn.S
+@@ -140,19 +140,19 @@ SYM_CODE_END(ftrace_graph_caller)
+ SYM_CODE_START(return_to_handler)
+       UNWIND_HINT_UNDEFINED
+       /* Save return value regs */
+-      PTR_ADDI        sp, sp, -FGRET_REGS_SIZE
+-      PTR_S           a0, sp, FGRET_REGS_A0
+-      PTR_S           a1, sp, FGRET_REGS_A1
+-      PTR_S           zero, sp, FGRET_REGS_FP
++      PTR_ADDI        sp, sp, -PT_SIZE
++      PTR_S           a0, sp, PT_R4
++      PTR_S           a1, sp, PT_R5
++      PTR_S           zero, sp, PT_R22
+       move            a0, sp
+       bl              ftrace_return_to_handler
+       move            ra, a0
+       /* Restore return value regs */
+-      PTR_L           a0, sp, FGRET_REGS_A0
+-      PTR_L           a1, sp, FGRET_REGS_A1
+-      PTR_ADDI        sp, sp, FGRET_REGS_SIZE
++      PTR_L           a0, sp, PT_R4
++      PTR_L           a1, sp, PT_R5
++      PTR_ADDI        sp, sp, PT_SIZE
+       jr              ra
+ SYM_CODE_END(return_to_handler)
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index d4a7ca0388c07..1e807c61258fb 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -148,7 +148,7 @@ config RISCV
+       select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE
+       select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
+       select HAVE_FUNCTION_GRAPH_TRACER
+-      select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER
++      select HAVE_FUNCTION_GRAPH_FREGS
+       select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION
+       select HAVE_EBPF_JIT if MMU
+       select HAVE_GUP_FAST if MMU
+diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h
+index 3d66437a10297..9372f8d7036f8 100644
+--- a/arch/riscv/include/asm/ftrace.h
++++ b/arch/riscv/include/asm/ftrace.h
+@@ -168,6 +168,11 @@ static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct
+       return arch_ftrace_regs(fregs)->sp;
+ }
++static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->s0;
++}
++
+ static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs,
+                                                             unsigned int n)
+ {
+@@ -208,25 +213,4 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsi
+ #endif /* CONFIG_DYNAMIC_FTRACE */
+-#ifndef __ASSEMBLY__
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-struct fgraph_ret_regs {
+-      unsigned long a1;
+-      unsigned long a0;
+-      unsigned long s0;
+-      unsigned long ra;
+-};
+-
+-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->a0;
+-}
+-
+-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->s0;
+-}
+-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */
+-#endif
+-
+ #endif /* _ASM_RISCV_FTRACE_H */
+diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S
+index 3a42f6287909d..068168046e0ef 100644
+--- a/arch/riscv/kernel/mcount.S
++++ b/arch/riscv/kernel/mcount.S
+@@ -12,6 +12,8 @@
+ #include <asm/asm-offsets.h>
+ #include <asm/ftrace.h>
++#define ABI_SIZE_ON_STACK     80
++
+       .text
+       .macro SAVE_ABI_STATE
+@@ -26,12 +28,12 @@
+        * register if a0 was not saved.
+        */
+       .macro SAVE_RET_ABI_STATE
+-      addi    sp, sp, -4*SZREG
+-      REG_S   s0, 2*SZREG(sp)
+-      REG_S   ra, 3*SZREG(sp)
+-      REG_S   a0, 1*SZREG(sp)
+-      REG_S   a1, 0*SZREG(sp)
+-      addi    s0, sp, 4*SZREG
++      addi    sp, sp, -ABI_SIZE_ON_STACK
++      REG_S   ra, 1*SZREG(sp)
++      REG_S   s0, 8*SZREG(sp)
++      REG_S   a0, 10*SZREG(sp)
++      REG_S   a1, 11*SZREG(sp)
++      addi    s0, sp, ABI_SIZE_ON_STACK
+       .endm
+       .macro RESTORE_ABI_STATE
+@@ -41,11 +43,11 @@
+       .endm
+       .macro RESTORE_RET_ABI_STATE
+-      REG_L   ra, 3*SZREG(sp)
+-      REG_L   s0, 2*SZREG(sp)
+-      REG_L   a0, 1*SZREG(sp)
+-      REG_L   a1, 0*SZREG(sp)
+-      addi    sp, sp, 4*SZREG
++      REG_L   ra, 1*SZREG(sp)
++      REG_L   s0, 8*SZREG(sp)
++      REG_L   a0, 10*SZREG(sp)
++      REG_L   a1, 11*SZREG(sp)
++      addi    sp, sp, ABI_SIZE_ON_STACK
+       .endm
+ SYM_TYPED_FUNC_START(ftrace_stub)
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index 83b1d7bbd8880..a8cecae74fe81 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -193,7 +193,7 @@ config S390
+       select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_FUNCTION_ARG_ACCESS_API
+       select HAVE_FUNCTION_ERROR_INJECTION
+-      select HAVE_FUNCTION_GRAPH_RETVAL
++      select HAVE_FUNCTION_GRAPH_FREGS
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER
+       select HAVE_GCC_PLUGINS
+diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
+index fc97d75dc752c..5c94c1fc1bc1c 100644
+--- a/arch/s390/include/asm/ftrace.h
++++ b/arch/s390/include/asm/ftrace.h
+@@ -62,23 +62,6 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *
+       return NULL;
+ }
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-struct fgraph_ret_regs {
+-      unsigned long gpr2;
+-      unsigned long fp;
+-};
+-
+-static __always_inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->gpr2;
+-}
+-
+-static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->fp;
+-}
+-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+-
+ static __always_inline void
+ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+                                   unsigned long ip)
+@@ -86,6 +69,13 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+       arch_ftrace_regs(fregs)->regs.psw.addr = ip;
+ }
++#undef ftrace_regs_get_frame_pointer
++static __always_inline unsigned long
++ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs)
++{
++      return ftrace_regs_get_stack_pointer(fregs);
++}
++
+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+ /*
+  * When an ftrace registered caller is tracing a function that is
+diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
+index 862a9140528e9..36709112ae7a2 100644
+--- a/arch/s390/kernel/asm-offsets.c
++++ b/arch/s390/kernel/asm-offsets.c
+@@ -175,12 +175,6 @@ int main(void)
+       DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size));
+       DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line));
+       DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size));
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-      /* function graph return value tracing */
+-      OFFSET(__FGRAPH_RET_GPR2, fgraph_ret_regs, gpr2);
+-      OFFSET(__FGRAPH_RET_FP, fgraph_ret_regs, fp);
+-      DEFINE(__FGRAPH_RET_SIZE, sizeof(struct fgraph_ret_regs));
+-#endif
+       OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs);
+       DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs));
+diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
+index 7e267ef63a7fe..2b628aa3d8095 100644
+--- a/arch/s390/kernel/mcount.S
++++ b/arch/s390/kernel/mcount.S
+@@ -134,14 +134,14 @@ SYM_CODE_END(ftrace_common)
+ SYM_FUNC_START(return_to_handler)
+       stmg    %r2,%r5,32(%r15)
+       lgr     %r1,%r15
+-      aghi    %r15,-(STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE)
++      # allocate ftrace_regs and stack frame for ftrace_return_to_handler
++      aghi    %r15,-STACK_FRAME_SIZE_FREGS
+       stg     %r1,__SF_BACKCHAIN(%r15)
+-      la      %r3,STACK_FRAME_OVERHEAD(%r15)
+-      stg     %r1,__FGRAPH_RET_FP(%r3)
+-      stg     %r2,__FGRAPH_RET_GPR2(%r3)
+-      lgr     %r2,%r3
++      stg     %r2,(STACK_FREGS_PTREGS_GPRS+2*8)(%r15)
++      stg     %r1,(STACK_FREGS_PTREGS_GPRS+15*8)(%r15)
++      la      %r2,STACK_FRAME_OVERHEAD(%r15)
+       brasl   %r14,ftrace_return_to_handler
+-      aghi    %r15,STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE
++      aghi    %r15,STACK_FRAME_SIZE_FREGS
+       lgr     %r14,%r2
+       lmg     %r2,%r5,32(%r15)
+       BR_EX   %r14
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index 757333fe82c76..aa317f6064b89 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -234,7 +234,7 @@ config X86
+       select HAVE_GUP_FAST
+       select HAVE_FENTRY                      if X86_64 || DYNAMIC_FTRACE
+       select HAVE_FTRACE_MCOUNT_RECORD
+-      select HAVE_FUNCTION_GRAPH_RETVAL       if HAVE_FUNCTION_GRAPH_TRACER
++      select HAVE_FUNCTION_GRAPH_FREGS        if HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_GRAPH_TRACER       if X86_32 || (X86_64 && DYNAMIC_FTRACE)
+       select HAVE_FUNCTION_TRACER
+       select HAVE_GCC_PLUGINS
+diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
+index 6e8cf0fa48fc6..d61407c680c28 100644
+--- a/arch/x86/include/asm/ftrace.h
++++ b/arch/x86/include/asm/ftrace.h
+@@ -134,24 +134,4 @@ static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
+ #endif /* !COMPILE_OFFSETS */
+ #endif /* !__ASSEMBLY__ */
+-#ifndef __ASSEMBLY__
+-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+-struct fgraph_ret_regs {
+-      unsigned long ax;
+-      unsigned long dx;
+-      unsigned long bp;
+-};
+-
+-static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->ax;
+-}
+-
+-static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs)
+-{
+-      return ret_regs->bp;
+-}
+-#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */
+-#endif
+-
+ #endif /* _ASM_X86_FTRACE_H */
+diff --git a/arch/x86/kernel/ftrace_32.S b/arch/x86/kernel/ftrace_32.S
+index 58d9ed50fe617..f4e0c33612342 100644
+--- a/arch/x86/kernel/ftrace_32.S
++++ b/arch/x86/kernel/ftrace_32.S
+@@ -187,14 +187,15 @@ SYM_CODE_END(ftrace_graph_caller)
+ .globl return_to_handler
+ return_to_handler:
+-      pushl   $0
+-      pushl   %edx
+-      pushl   %eax
++      subl    $(PTREGS_SIZE), %esp
++      movl    $0, PT_EBP(%esp)
++      movl    %edx, PT_EDX(%esp)
++      movl    %eax, PT_EAX(%esp)
+       movl    %esp, %eax
+       call    ftrace_return_to_handler
+       movl    %eax, %ecx
+-      popl    %eax
+-      popl    %edx
+-      addl    $4, %esp                # skip ebp
++      movl    PT_EAX(%esp), %eax
++      movl    PT_EDX(%esp), %edx
++      addl    $(PTREGS_SIZE), %esp
+       JMP_NOSPEC ecx
+ #endif
+diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S
+index 214f30e9f0c01..d516472285967 100644
+--- a/arch/x86/kernel/ftrace_64.S
++++ b/arch/x86/kernel/ftrace_64.S
+@@ -348,21 +348,22 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__)
+ SYM_CODE_START(return_to_handler)
+       UNWIND_HINT_UNDEFINED
+       ANNOTATE_NOENDBR
+-      subq  $24, %rsp
+-      /* Save the return values */
+-      movq %rax, (%rsp)
+-      movq %rdx, 8(%rsp)
+-      movq %rbp, 16(%rsp)
++      /* Save ftrace_regs for function exit context  */
++      subq $(FRAME_SIZE), %rsp
++
++      movq %rax, RAX(%rsp)
++      movq %rdx, RDX(%rsp)
++      movq %rbp, RBP(%rsp)
+       movq %rsp, %rdi
+       call ftrace_return_to_handler
+       movq %rax, %rdi
+-      movq 8(%rsp), %rdx
+-      movq (%rsp), %rax
++      movq RDX(%rsp), %rdx
++      movq RAX(%rsp), %rax
+-      addq $24, %rsp
++      addq $(FRAME_SIZE), %rsp
+       /*
+        * Jump back to the old return address. This cannot be JMP_NOSPEC rdi
+        * since IBT would demand that contain ENDBR, which simply isn't so for
+diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
+index aa9ddd1e4bb6a..b7407004c799e 100644
+--- a/include/linux/ftrace.h
++++ b/include/linux/ftrace.h
+@@ -43,9 +43,8 @@ struct dyn_ftrace;
+ char *arch_ftrace_match_adjust(char *str, const char *search);
+-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL
+-struct fgraph_ret_regs;
+-unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs);
++#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS
++unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs);
+ #else
+ unsigned long ftrace_return_to_handler(unsigned long frame_pointer);
+ #endif
+@@ -134,6 +133,13 @@ extern int ftrace_enabled;
+  * Also, architecture dependent fields can be used for internal process.
+  * (e.g. orig_ax on x86_64)
+  *
++ * Basically, ftrace_regs stores the registers related to the context.
++ * On function entry, registers for function parameters and hooking the
++ * function call are stored, and on function exit, registers for function
++ * return value and frame pointers are stored.
++ *
++ * And also, it dpends on the context that which registers are restored
++ * from the ftrace_regs.
+  * On the function entry, those registers will be restored except for
+  * the stack pointer, so that user can change the function parameters
+  * and instruction pointer (e.g. live patching.)
+diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
+index be1ed0c891d07..bbc1873ca6b8e 100644
+--- a/include/linux/ftrace_regs.h
++++ b/include/linux/ftrace_regs.h
+@@ -30,6 +30,8 @@ struct ftrace_regs;
+       override_function_with_return(&arch_ftrace_regs(fregs)->regs)
+ #define ftrace_regs_query_register_offset(name) \
+       regs_query_register_offset(name)
++#define ftrace_regs_get_frame_pointer(fregs) \
++      frame_pointer(&arch_ftrace_regs(fregs)->regs)
+ #endif /* HAVE_ARCH_FTRACE_REGS */
+diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
+index 74c2b1d43bb98..c5ab2a561272d 100644
+--- a/kernel/trace/Kconfig
++++ b/kernel/trace/Kconfig
+@@ -31,7 +31,7 @@ config HAVE_FUNCTION_GRAPH_TRACER
+       help
+         See Documentation/trace/ftrace-design.rst
+-config HAVE_FUNCTION_GRAPH_RETVAL
++config HAVE_FUNCTION_GRAPH_FREGS
+       bool
+ config HAVE_DYNAMIC_FTRACE
+@@ -232,7 +232,7 @@ config FUNCTION_GRAPH_TRACER
+ config FUNCTION_GRAPH_RETVAL
+       bool "Kernel Function Graph Return Value"
+-      depends on HAVE_FUNCTION_GRAPH_RETVAL
++      depends on HAVE_FUNCTION_GRAPH_FREGS
+       depends on FUNCTION_GRAPH_TRACER
+       default n
+       help
+diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
+index 30e3ddc8a8a84..6e55759b45776 100644
+--- a/kernel/trace/fgraph.c
++++ b/kernel/trace/fgraph.c
+@@ -792,15 +792,12 @@ static struct notifier_block ftrace_suspend_notifier = {
+       .notifier_call = ftrace_suspend_notifier_call,
+ };
+-/* fgraph_ret_regs is not defined without CONFIG_FUNCTION_GRAPH_RETVAL */
+-struct fgraph_ret_regs;
+-
+ /*
+  * Send the trace to the ring-buffer.
+  * @return the original return address.
+  */
+-static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs,
+-                                              unsigned long frame_pointer)
++static inline unsigned long
++__ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointer)
+ {
+       struct ftrace_ret_stack *ret_stack;
+       struct ftrace_graph_ret trace;
+@@ -820,7 +817,7 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs
+       trace.rettime = trace_clock_local();
+ #ifdef CONFIG_FUNCTION_GRAPH_RETVAL
+-      trace.retval = fgraph_ret_regs_return_value(ret_regs);
++      trace.retval = ftrace_regs_get_return_value(fregs);
+ #endif
+       bitmap = get_bitmap_bits(current, offset);
+@@ -855,14 +852,14 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs
+ }
+ /*
+- * After all architecures have selected HAVE_FUNCTION_GRAPH_RETVAL, we can
+- * leave only ftrace_return_to_handler(ret_regs).
++ * After all architecures have selected HAVE_FUNCTION_GRAPH_FREGS, we can
++ * leave only ftrace_return_to_handler(fregs).
+  */
+-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL
+-unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs)
++#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS
++unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs)
+ {
+-      return __ftrace_return_to_handler(ret_regs,
+-                              fgraph_ret_regs_frame_pointer(ret_regs));
++      return __ftrace_return_to_handler(fregs,
++                              ftrace_regs_get_frame_pointer(fregs));
+ }
+ #else
+ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
+-- 
+2.39.5
+
diff --git a/queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch b/queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch
new file mode 100644 (file)
index 0000000..04302fe
--- /dev/null
@@ -0,0 +1,1168 @@
+From 98b2c6a182a85ab61910f92b12b78f066e34fd38 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:13:59 +0900
+Subject: fprobe: Rewrite fprobe on function-graph tracer
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 4346ba1604093305a287e08eb465a9c15ba05b80 ]
+
+Rewrite fprobe implementation on function-graph tracer.
+Major API changes are:
+ -  'nr_maxactive' field is deprecated.
+ -  This depends on CONFIG_DYNAMIC_FTRACE_WITH_ARGS or
+    !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS, and
+    CONFIG_HAVE_FUNCTION_GRAPH_FREGS. So currently works only
+    on x86_64.
+ -  Currently the entry size is limited in 15 * sizeof(long).
+ -  If there is too many fprobe exit handler set on the same
+    function, it will fail to probe.
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Florent Revest <revest@chromium.org>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Huacai Chen <chenhuacai@kernel.org>
+Cc: WANG Xuerui <kernel@xen0n.name>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Naveen N Rao <naveen@kernel.org>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: x86@kernel.org
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Link: https://lore.kernel.org/173519003970.391279.14406792285453830996.stgit@devnote2
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/ftrace.h     |   6 +
+ arch/loongarch/include/asm/ftrace.h |   6 +
+ arch/powerpc/include/asm/ftrace.h   |   6 +
+ arch/riscv/include/asm/ftrace.h     |   5 +
+ arch/s390/include/asm/ftrace.h      |   6 +
+ arch/x86/include/asm/ftrace.h       |   6 +
+ include/linux/fprobe.h              |  58 ++-
+ kernel/trace/Kconfig                |   8 +-
+ kernel/trace/fprobe.c               | 637 ++++++++++++++++++++--------
+ lib/test_fprobe.c                   |  45 --
+ 10 files changed, 538 insertions(+), 245 deletions(-)
+
+diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
+index 10e56522122aa..876e88ad4119f 100644
+--- a/arch/arm64/include/asm/ftrace.h
++++ b/arch/arm64/include/asm/ftrace.h
+@@ -135,6 +135,12 @@ ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
+       return arch_ftrace_regs(fregs)->fp;
+ }
++static __always_inline unsigned long
++ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->lr;
++}
++
+ static __always_inline struct pt_regs *
+ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
+ {
+diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h
+index ceb3e3d9c0d3d..6e0a99763a9a7 100644
+--- a/arch/loongarch/include/asm/ftrace.h
++++ b/arch/loongarch/include/asm/ftrace.h
+@@ -61,6 +61,12 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip)
+ #define ftrace_regs_get_frame_pointer(fregs) \
+       (arch_ftrace_regs(fregs)->regs.regs[22])
++static __always_inline unsigned long
++ftrace_regs_get_return_address(struct ftrace_regs *fregs)
++{
++      return *(unsigned long *)(arch_ftrace_regs(fregs)->regs.regs[1]);
++}
++
+ #define ftrace_graph_func ftrace_graph_func
+ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+                      struct ftrace_ops *op, struct ftrace_regs *fregs);
+diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
+index fe181bafdca4f..82da7c7a1d125 100644
+--- a/arch/powerpc/include/asm/ftrace.h
++++ b/arch/powerpc/include/asm/ftrace.h
+@@ -57,6 +57,12 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+       regs_set_return_ip(&arch_ftrace_regs(fregs)->regs, ip);
+ }
++static __always_inline unsigned long
++ftrace_regs_get_return_address(struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->regs.link;
++}
++
+ struct ftrace_ops;
+ #define ftrace_graph_func ftrace_graph_func
+diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h
+index 7064a530794b6..c4721ce44ca47 100644
+--- a/arch/riscv/include/asm/ftrace.h
++++ b/arch/riscv/include/asm/ftrace.h
+@@ -186,6 +186,11 @@ static __always_inline unsigned long ftrace_regs_get_return_value(const struct f
+       return arch_ftrace_regs(fregs)->a0;
+ }
++static __always_inline unsigned long ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->ra;
++}
++
+ static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs,
+                                                        unsigned long ret)
+ {
+diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
+index 5b7cb49c41ee0..8c94a330c70c9 100644
+--- a/arch/s390/include/asm/ftrace.h
++++ b/arch/s390/include/asm/ftrace.h
+@@ -76,6 +76,12 @@ ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs)
+       return ftrace_regs_get_stack_pointer(fregs);
+ }
++static __always_inline unsigned long
++ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
++{
++      return arch_ftrace_regs(fregs)->regs.gprs[14];
++}
++
+ #define arch_ftrace_fill_perf_regs(fregs, _regs)       do {           \
+               (_regs)->psw.mask = 0;                                  \
+               (_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr;             \
+diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
+index 7e06f8c7937aa..cc92c99ef2760 100644
+--- a/arch/x86/include/asm/ftrace.h
++++ b/arch/x86/include/asm/ftrace.h
+@@ -58,6 +58,12 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs)
+       do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0)
++static __always_inline unsigned long
++ftrace_regs_get_return_address(struct ftrace_regs *fregs)
++{
++      return *(unsigned long *)ftrace_regs_get_stack_pointer(fregs);
++}
++
+ struct ftrace_ops;
+ #define ftrace_graph_func ftrace_graph_func
+ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h
+index ef609bcca0f92..91337bcb452ff 100644
+--- a/include/linux/fprobe.h
++++ b/include/linux/fprobe.h
+@@ -5,10 +5,11 @@
+ #include <linux/compiler.h>
+ #include <linux/ftrace.h>
+-#include <linux/rethook.h>
++#include <linux/rcupdate.h>
++#include <linux/refcount.h>
++#include <linux/slab.h>
+ struct fprobe;
+-
+ typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip,
+                              unsigned long ret_ip, struct ftrace_regs *regs,
+                              void *entry_data);
+@@ -17,35 +18,57 @@ typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip,
+                              unsigned long ret_ip, struct ftrace_regs *regs,
+                              void *entry_data);
++/**
++ * struct fprobe_hlist_node - address based hash list node for fprobe.
++ *
++ * @hlist: The hlist node for address search hash table.
++ * @addr: One of the probing address of @fp.
++ * @fp: The fprobe which owns this.
++ */
++struct fprobe_hlist_node {
++      struct hlist_node       hlist;
++      unsigned long           addr;
++      struct fprobe           *fp;
++};
++
++/**
++ * struct fprobe_hlist - hash list nodes for fprobe.
++ *
++ * @hlist: The hlist node for existence checking hash table.
++ * @rcu: rcu_head for RCU deferred release.
++ * @fp: The fprobe which owns this fprobe_hlist.
++ * @size: The size of @array.
++ * @array: The fprobe_hlist_node for each address to probe.
++ */
++struct fprobe_hlist {
++      struct hlist_node               hlist;
++      struct rcu_head                 rcu;
++      struct fprobe                   *fp;
++      int                             size;
++      struct fprobe_hlist_node        array[] __counted_by(size);
++};
++
+ /**
+  * struct fprobe - ftrace based probe.
+- * @ops: The ftrace_ops.
++ *
+  * @nmissed: The counter for missing events.
+  * @flags: The status flag.
+- * @rethook: The rethook data structure. (internal data)
+  * @entry_data_size: The private data storage size.
+- * @nr_maxactive: The max number of active functions.
++ * @nr_maxactive: The max number of active functions. (*deprecated)
+  * @entry_handler: The callback function for function entry.
+  * @exit_handler: The callback function for function exit.
++ * @hlist_array: The fprobe_hlist for fprobe search from IP hash table.
+  */
+ struct fprobe {
+-#ifdef CONFIG_FUNCTION_TRACER
+-      /*
+-       * If CONFIG_FUNCTION_TRACER is not set, CONFIG_FPROBE is disabled too.
+-       * But user of fprobe may keep embedding the struct fprobe on their own
+-       * code. To avoid build error, this will keep the fprobe data structure
+-       * defined here, but remove ftrace_ops data structure.
+-       */
+-      struct ftrace_ops       ops;
+-#endif
+       unsigned long           nmissed;
+       unsigned int            flags;
+-      struct rethook          *rethook;
+       size_t                  entry_data_size;
+       int                     nr_maxactive;
+       fprobe_entry_cb entry_handler;
+       fprobe_exit_cb  exit_handler;
++
++      struct fprobe_hlist     *hlist_array;
+ };
+ /* This fprobe is soft-disabled. */
+@@ -121,4 +144,9 @@ static inline void enable_fprobe(struct fprobe *fp)
+               fp->flags &= ~FPROBE_FL_DISABLED;
+ }
++/* The entry data size is 4 bits (=16) * sizeof(long) in maximum */
++#define FPROBE_DATA_SIZE_BITS         4
++#define MAX_FPROBE_DATA_SIZE_WORD     ((1L << FPROBE_DATA_SIZE_BITS) - 1)
++#define MAX_FPROBE_DATA_SIZE          (MAX_FPROBE_DATA_SIZE_WORD * sizeof(long))
++
+ #endif
+diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
+index 7f8165f2049a5..69954212c77d1 100644
+--- a/kernel/trace/Kconfig
++++ b/kernel/trace/Kconfig
+@@ -302,11 +302,9 @@ config DYNAMIC_FTRACE_WITH_ARGS
+ config FPROBE
+       bool "Kernel Function Probe (fprobe)"
+-      depends on FUNCTION_TRACER
+-      depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
+-      depends on HAVE_FTRACE_REGS_HAVING_PT_REGS || !HAVE_DYNAMIC_FTRACE_WITH_ARGS
+-      depends on HAVE_RETHOOK
+-      select RETHOOK
++      depends on HAVE_FUNCTION_GRAPH_FREGS && HAVE_FTRACE_GRAPH_FUNC
++      depends on DYNAMIC_FTRACE_WITH_ARGS
++      select FUNCTION_GRAPH_TRACER
+       default n
+       help
+         This option enables kernel function probe (fprobe) based on ftrace.
+diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
+index 90a3c8e2bbdf1..ed9c1d79426a2 100644
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -8,98 +8,195 @@
+ #include <linux/fprobe.h>
+ #include <linux/kallsyms.h>
+ #include <linux/kprobes.h>
+-#include <linux/rethook.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
+ #include <linux/slab.h>
+ #include <linux/sort.h>
+ #include "trace.h"
+-struct fprobe_rethook_node {
+-      struct rethook_node node;
+-      unsigned long entry_ip;
+-      unsigned long entry_parent_ip;
+-      char data[];
+-};
++#define FPROBE_IP_HASH_BITS 8
++#define FPROBE_IP_TABLE_SIZE (1 << FPROBE_IP_HASH_BITS)
+-static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
+-                      struct ftrace_ops *ops, struct ftrace_regs *fregs)
+-{
+-      struct fprobe_rethook_node *fpr;
+-      struct rethook_node *rh = NULL;
+-      struct fprobe *fp;
+-      void *entry_data = NULL;
+-      int ret = 0;
++#define FPROBE_HASH_BITS 6
++#define FPROBE_TABLE_SIZE (1 << FPROBE_HASH_BITS)
+-      fp = container_of(ops, struct fprobe, ops);
++#define SIZE_IN_LONG(x) ((x + sizeof(long) - 1) >> (sizeof(long) == 8 ? 3 : 2))
+-      if (fp->exit_handler) {
+-              rh = rethook_try_get(fp->rethook);
+-              if (!rh) {
+-                      fp->nmissed++;
+-                      return;
+-              }
+-              fpr = container_of(rh, struct fprobe_rethook_node, node);
+-              fpr->entry_ip = ip;
+-              fpr->entry_parent_ip = parent_ip;
+-              if (fp->entry_data_size)
+-                      entry_data = fpr->data;
++/*
++ * fprobe_table: hold 'fprobe_hlist::hlist' for checking the fprobe still
++ *   exists. The key is the address of fprobe instance.
++ * fprobe_ip_table: hold 'fprobe_hlist::array[*]' for searching the fprobe
++ *   instance related to the funciton address. The key is the ftrace IP
++ *   address.
++ *
++ * When unregistering the fprobe, fprobe_hlist::fp and fprobe_hlist::array[*].fp
++ * are set NULL and delete those from both hash tables (by hlist_del_rcu).
++ * After an RCU grace period, the fprobe_hlist itself will be released.
++ *
++ * fprobe_table and fprobe_ip_table can be accessed from either
++ *  - Normal hlist traversal and RCU add/del under 'fprobe_mutex' is held.
++ *  - RCU hlist traversal under disabling preempt
++ */
++static struct hlist_head fprobe_table[FPROBE_TABLE_SIZE];
++static struct hlist_head fprobe_ip_table[FPROBE_IP_TABLE_SIZE];
++static DEFINE_MUTEX(fprobe_mutex);
++
++/*
++ * Find first fprobe in the hlist. It will be iterated twice in the entry
++ * probe, once for correcting the total required size, the second time is
++ * calling back the user handlers.
++ * Thus the hlist in the fprobe_table must be sorted and new probe needs to
++ * be added *before* the first fprobe.
++ */
++static struct fprobe_hlist_node *find_first_fprobe_node(unsigned long ip)
++{
++      struct fprobe_hlist_node *node;
++      struct hlist_head *head;
++
++      head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)];
++      hlist_for_each_entry_rcu(node, head, hlist,
++                               lockdep_is_held(&fprobe_mutex)) {
++              if (node->addr == ip)
++                      return node;
+       }
++      return NULL;
++}
++NOKPROBE_SYMBOL(find_first_fprobe_node);
+-      if (fp->entry_handler)
+-              ret = fp->entry_handler(fp, ip, parent_ip, fregs, entry_data);
++/* Node insertion and deletion requires the fprobe_mutex */
++static void insert_fprobe_node(struct fprobe_hlist_node *node)
++{
++      unsigned long ip = node->addr;
++      struct fprobe_hlist_node *next;
++      struct hlist_head *head;
+-      /* If entry_handler returns !0, nmissed is not counted. */
+-      if (rh) {
+-              if (ret)
+-                      rethook_recycle(rh);
+-              else
+-                      rethook_hook(rh, ftrace_get_regs(fregs), true);
++      lockdep_assert_held(&fprobe_mutex);
++
++      next = find_first_fprobe_node(ip);
++      if (next) {
++              hlist_add_before_rcu(&node->hlist, &next->hlist);
++              return;
+       }
++      head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)];
++      hlist_add_head_rcu(&node->hlist, head);
+ }
+-static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
+-              struct ftrace_ops *ops, struct ftrace_regs *fregs)
++/* Return true if there are synonims */
++static bool delete_fprobe_node(struct fprobe_hlist_node *node)
+ {
+-      struct fprobe *fp;
+-      int bit;
++      lockdep_assert_held(&fprobe_mutex);
+-      fp = container_of(ops, struct fprobe, ops);
+-      if (fprobe_disabled(fp))
+-              return;
++      WRITE_ONCE(node->fp, NULL);
++      hlist_del_rcu(&node->hlist);
++      return !!find_first_fprobe_node(node->addr);
++}
+-      /* recursion detection has to go before any traceable function and
+-       * all functions before this point should be marked as notrace
+-       */
+-      bit = ftrace_test_recursion_trylock(ip, parent_ip);
+-      if (bit < 0) {
+-              fp->nmissed++;
+-              return;
++/* Check existence of the fprobe */
++static bool is_fprobe_still_exist(struct fprobe *fp)
++{
++      struct hlist_head *head;
++      struct fprobe_hlist *fph;
++
++      head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)];
++      hlist_for_each_entry_rcu(fph, head, hlist,
++                               lockdep_is_held(&fprobe_mutex)) {
++              if (fph->fp == fp)
++                      return true;
+       }
+-      __fprobe_handler(ip, parent_ip, ops, fregs);
+-      ftrace_test_recursion_unlock(bit);
++      return false;
++}
++NOKPROBE_SYMBOL(is_fprobe_still_exist);
++
++static int add_fprobe_hash(struct fprobe *fp)
++{
++      struct fprobe_hlist *fph = fp->hlist_array;
++      struct hlist_head *head;
++
++      lockdep_assert_held(&fprobe_mutex);
++
++      if (WARN_ON_ONCE(!fph))
++              return -EINVAL;
++
++      if (is_fprobe_still_exist(fp))
++              return -EEXIST;
++      head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)];
++      hlist_add_head_rcu(&fp->hlist_array->hlist, head);
++      return 0;
+ }
+-NOKPROBE_SYMBOL(fprobe_handler);
+-static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
+-                                struct ftrace_ops *ops, struct ftrace_regs *fregs)
++static int del_fprobe_hash(struct fprobe *fp)
+ {
++      struct fprobe_hlist *fph = fp->hlist_array;
++
++      lockdep_assert_held(&fprobe_mutex);
++
++      if (WARN_ON_ONCE(!fph))
++              return -EINVAL;
++
++      if (!is_fprobe_still_exist(fp))
++              return -ENOENT;
++
++      fph->fp = NULL;
++      hlist_del_rcu(&fph->hlist);
++      return 0;
++}
++
++/* Generic fprobe_header */
++struct __fprobe_header {
+       struct fprobe *fp;
+-      int bit;
++      unsigned long size_words;
++} __packed;
+-      fp = container_of(ops, struct fprobe, ops);
+-      if (fprobe_disabled(fp))
+-              return;
++#define FPROBE_HEADER_SIZE_IN_LONG    SIZE_IN_LONG(sizeof(struct __fprobe_header))
+-      /* recursion detection has to go before any traceable function and
+-       * all functions called before this point should be marked as notrace
+-       */
+-      bit = ftrace_test_recursion_trylock(ip, parent_ip);
+-      if (bit < 0) {
+-              fp->nmissed++;
+-              return;
+-      }
++static inline bool write_fprobe_header(unsigned long *stack,
++                                      struct fprobe *fp, unsigned int size_words)
++{
++      struct __fprobe_header *fph = (struct __fprobe_header *)stack;
++      if (WARN_ON_ONCE(size_words > MAX_FPROBE_DATA_SIZE_WORD))
++              return false;
++
++      fph->fp = fp;
++      fph->size_words = size_words;
++      return true;
++}
++
++static inline void read_fprobe_header(unsigned long *stack,
++                                      struct fprobe **fp, unsigned int *size_words)
++{
++      struct __fprobe_header *fph = (struct __fprobe_header *)stack;
++
++      *fp = fph->fp;
++      *size_words = fph->size_words;
++}
++
++/*
++ * fprobe shadow stack management:
++ * Since fprobe shares a single fgraph_ops, it needs to share the stack entry
++ * among the probes on the same function exit. Note that a new probe can be
++ * registered before a target function is returning, we can not use the hash
++ * table to find the corresponding probes. Thus the probe address is stored on
++ * the shadow stack with its entry data size.
++ *
++ */
++static inline int __fprobe_handler(unsigned long ip, unsigned long parent_ip,
++                                 struct fprobe *fp, struct ftrace_regs *fregs,
++                                 void *data)
++{
++      if (!fp->entry_handler)
++              return 0;
++
++      return fp->entry_handler(fp, ip, parent_ip, fregs, data);
++}
++
++static inline int __fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
++                                        struct fprobe *fp, struct ftrace_regs *fregs,
++                                        void *data)
++{
++      int ret;
+       /*
+        * This user handler is shared with other kprobes and is not expected to be
+        * called recursively. So if any other kprobe handler is running, this will
+@@ -108,45 +205,183 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
+        */
+       if (unlikely(kprobe_running())) {
+               fp->nmissed++;
+-              goto recursion_unlock;
++              return 0;
+       }
+       kprobe_busy_begin();
+-      __fprobe_handler(ip, parent_ip, ops, fregs);
++      ret = __fprobe_handler(ip, parent_ip, fp, fregs, data);
+       kprobe_busy_end();
+-
+-recursion_unlock:
+-      ftrace_test_recursion_unlock(bit);
++      return ret;
+ }
+-static void fprobe_exit_handler(struct rethook_node *rh, void *data,
+-                              unsigned long ret_ip, struct pt_regs *regs)
++static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops,
++                      struct ftrace_regs *fregs)
+ {
+-      struct fprobe *fp = (struct fprobe *)data;
+-      struct fprobe_rethook_node *fpr;
+-      struct ftrace_regs *fregs = (struct ftrace_regs *)regs;
+-      int bit;
++      struct fprobe_hlist_node *node, *first;
++      unsigned long *fgraph_data = NULL;
++      unsigned long func = trace->func;
++      unsigned long ret_ip;
++      int reserved_words;
++      struct fprobe *fp;
++      int used, ret;
+-      if (!fp || fprobe_disabled(fp))
+-              return;
++      if (WARN_ON_ONCE(!fregs))
++              return 0;
+-      fpr = container_of(rh, struct fprobe_rethook_node, node);
++      first = node = find_first_fprobe_node(func);
++      if (unlikely(!first))
++              return 0;
++
++      reserved_words = 0;
++      hlist_for_each_entry_from_rcu(node, hlist) {
++              if (node->addr != func)
++                      break;
++              fp = READ_ONCE(node->fp);
++              if (!fp || !fp->exit_handler)
++                      continue;
++              /*
++               * Since fprobe can be enabled until the next loop, we ignore the
++               * fprobe's disabled flag in this loop.
++               */
++              reserved_words +=
++                      FPROBE_HEADER_SIZE_IN_LONG + SIZE_IN_LONG(fp->entry_data_size);
++      }
++      node = first;
++      if (reserved_words) {
++              fgraph_data = fgraph_reserve_data(gops->idx, reserved_words * sizeof(long));
++              if (unlikely(!fgraph_data)) {
++                      hlist_for_each_entry_from_rcu(node, hlist) {
++                              if (node->addr != func)
++                                      break;
++                              fp = READ_ONCE(node->fp);
++                              if (fp && !fprobe_disabled(fp))
++                                      fp->nmissed++;
++                      }
++                      return 0;
++              }
++      }
+       /*
+-       * we need to assure no calls to traceable functions in-between the
+-       * end of fprobe_handler and the beginning of fprobe_exit_handler.
++       * TODO: recursion detection has been done in the fgraph. Thus we need
++       * to add a callback to increment missed counter.
+        */
+-      bit = ftrace_test_recursion_trylock(fpr->entry_ip, fpr->entry_parent_ip);
+-      if (bit < 0) {
+-              fp->nmissed++;
++      ret_ip = ftrace_regs_get_return_address(fregs);
++      used = 0;
++      hlist_for_each_entry_from_rcu(node, hlist) {
++              int data_size;
++              void *data;
++
++              if (node->addr != func)
++                      break;
++              fp = READ_ONCE(node->fp);
++              if (!fp || fprobe_disabled(fp))
++                      continue;
++
++              data_size = fp->entry_data_size;
++              if (data_size && fp->exit_handler)
++                      data = fgraph_data + used + FPROBE_HEADER_SIZE_IN_LONG;
++              else
++                      data = NULL;
++
++              if (fprobe_shared_with_kprobes(fp))
++                      ret = __fprobe_kprobe_handler(func, ret_ip, fp, fregs, data);
++              else
++                      ret = __fprobe_handler(func, ret_ip, fp, fregs, data);
++
++              /* If entry_handler returns !0, nmissed is not counted but skips exit_handler. */
++              if (!ret && fp->exit_handler) {
++                      int size_words = SIZE_IN_LONG(data_size);
++
++                      if (write_fprobe_header(&fgraph_data[used], fp, size_words))
++                              used += FPROBE_HEADER_SIZE_IN_LONG + size_words;
++              }
++      }
++      if (used < reserved_words)
++              memset(fgraph_data + used, 0, reserved_words - used);
++
++      /* If any exit_handler is set, data must be used. */
++      return used != 0;
++}
++NOKPROBE_SYMBOL(fprobe_entry);
++
++static void fprobe_return(struct ftrace_graph_ret *trace,
++                        struct fgraph_ops *gops,
++                        struct ftrace_regs *fregs)
++{
++      unsigned long *fgraph_data = NULL;
++      unsigned long ret_ip;
++      struct fprobe *fp;
++      int size, curr;
++      int size_words;
++
++      fgraph_data = (unsigned long *)fgraph_retrieve_data(gops->idx, &size);
++      if (WARN_ON_ONCE(!fgraph_data))
+               return;
++      size_words = SIZE_IN_LONG(size);
++      ret_ip = ftrace_regs_get_instruction_pointer(fregs);
++
++      preempt_disable();
++
++      curr = 0;
++      while (size_words > curr) {
++              read_fprobe_header(&fgraph_data[curr], &fp, &size);
++              if (!fp)
++                      break;
++              curr += FPROBE_HEADER_SIZE_IN_LONG;
++              if (is_fprobe_still_exist(fp) && !fprobe_disabled(fp)) {
++                      if (WARN_ON_ONCE(curr + size > size_words))
++                              break;
++                      fp->exit_handler(fp, trace->func, ret_ip, fregs,
++                                       size ? fgraph_data + curr : NULL);
++              }
++              curr += size;
+       }
++      preempt_enable();
++}
++NOKPROBE_SYMBOL(fprobe_return);
++
++static struct fgraph_ops fprobe_graph_ops = {
++      .entryfunc      = fprobe_entry,
++      .retfunc        = fprobe_return,
++};
++static int fprobe_graph_active;
++
++/* Add @addrs to the ftrace filter and register fgraph if needed. */
++static int fprobe_graph_add_ips(unsigned long *addrs, int num)
++{
++      int ret;
+-      fp->exit_handler(fp, fpr->entry_ip, ret_ip, fregs,
+-                       fp->entry_data_size ? (void *)fpr->data : NULL);
+-      ftrace_test_recursion_unlock(bit);
++      lockdep_assert_held(&fprobe_mutex);
++
++      ret = ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 0, 0);
++      if (ret)
++              return ret;
++
++      if (!fprobe_graph_active) {
++              ret = register_ftrace_graph(&fprobe_graph_ops);
++              if (WARN_ON_ONCE(ret)) {
++                      ftrace_free_filter(&fprobe_graph_ops.ops);
++                      return ret;
++              }
++      }
++      fprobe_graph_active++;
++      return 0;
++}
++
++/* Remove @addrs from the ftrace filter and unregister fgraph if possible. */
++static void fprobe_graph_remove_ips(unsigned long *addrs, int num)
++{
++      lockdep_assert_held(&fprobe_mutex);
++
++      fprobe_graph_active--;
++      if (!fprobe_graph_active) {
++              /* Q: should we unregister it ? */
++              unregister_ftrace_graph(&fprobe_graph_ops);
++              return;
++      }
++
++      ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 1, 0);
+ }
+-NOKPROBE_SYMBOL(fprobe_exit_handler);
+ static int symbols_cmp(const void *a, const void *b)
+ {
+@@ -176,54 +411,97 @@ static unsigned long *get_ftrace_locations(const char **syms, int num)
+       return ERR_PTR(-ENOENT);
+ }
+-static void fprobe_init(struct fprobe *fp)
+-{
+-      fp->nmissed = 0;
+-      if (fprobe_shared_with_kprobes(fp))
+-              fp->ops.func = fprobe_kprobe_handler;
+-      else
+-              fp->ops.func = fprobe_handler;
+-
+-      fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS;
+-}
++struct filter_match_data {
++      const char *filter;
++      const char *notfilter;
++      size_t index;
++      size_t size;
++      unsigned long *addrs;
++};
+-static int fprobe_init_rethook(struct fprobe *fp, int num)
++static int filter_match_callback(void *data, const char *name, unsigned long addr)
+ {
+-      int size;
++      struct filter_match_data *match = data;
+-      if (!fp->exit_handler) {
+-              fp->rethook = NULL;
++      if (!glob_match(match->filter, name) ||
++          (match->notfilter && glob_match(match->notfilter, name)))
+               return 0;
+-      }
+-      /* Initialize rethook if needed */
+-      if (fp->nr_maxactive)
+-              num = fp->nr_maxactive;
+-      else
+-              num *= num_possible_cpus() * 2;
+-      if (num <= 0)
+-              return -EINVAL;
++      if (!ftrace_location(addr))
++              return 0;
+-      size = sizeof(struct fprobe_rethook_node) + fp->entry_data_size;
++      if (match->addrs)
++              match->addrs[match->index] = addr;
+-      /* Initialize rethook */
+-      fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler, size, num);
+-      if (IS_ERR(fp->rethook))
+-              return PTR_ERR(fp->rethook);
++      match->index++;
++      return match->index == match->size;
++}
+-      return 0;
++/*
++ * Make IP list from the filter/no-filter glob patterns.
++ * Return the number of matched symbols, or -ENOENT.
++ */
++static int ip_list_from_filter(const char *filter, const char *notfilter,
++                             unsigned long *addrs, size_t size)
++{
++      struct filter_match_data match = { .filter = filter, .notfilter = notfilter,
++              .index = 0, .size = size, .addrs = addrs};
++      int ret;
++
++      ret = kallsyms_on_each_symbol(filter_match_callback, &match);
++      if (ret < 0)
++              return ret;
++      ret = module_kallsyms_on_each_symbol(NULL, filter_match_callback, &match);
++      if (ret < 0)
++              return ret;
++
++      return match.index ?: -ENOENT;
+ }
+ static void fprobe_fail_cleanup(struct fprobe *fp)
+ {
+-      if (!IS_ERR_OR_NULL(fp->rethook)) {
+-              /* Don't need to cleanup rethook->handler because this is not used. */
+-              rethook_free(fp->rethook);
+-              fp->rethook = NULL;
++      kfree(fp->hlist_array);
++      fp->hlist_array = NULL;
++}
++
++/* Initialize the fprobe data structure. */
++static int fprobe_init(struct fprobe *fp, unsigned long *addrs, int num)
++{
++      struct fprobe_hlist *hlist_array;
++      unsigned long addr;
++      int size, i;
++
++      if (!fp || !addrs || num <= 0)
++              return -EINVAL;
++
++      size = ALIGN(fp->entry_data_size, sizeof(long));
++      if (size > MAX_FPROBE_DATA_SIZE)
++              return -E2BIG;
++      fp->entry_data_size = size;
++
++      hlist_array = kzalloc(struct_size(hlist_array, array, num), GFP_KERNEL);
++      if (!hlist_array)
++              return -ENOMEM;
++
++      fp->nmissed = 0;
++
++      hlist_array->size = num;
++      fp->hlist_array = hlist_array;
++      hlist_array->fp = fp;
++      for (i = 0; i < num; i++) {
++              hlist_array->array[i].fp = fp;
++              addr = ftrace_location(addrs[i]);
++              if (!addr) {
++                      fprobe_fail_cleanup(fp);
++                      return -ENOENT;
++              }
++              hlist_array->array[i].addr = addr;
+       }
+-      ftrace_free_filter(&fp->ops);
++      return 0;
+ }
++#define FPROBE_IPS_MAX        INT_MAX
++
+ /**
+  * register_fprobe() - Register fprobe to ftrace by pattern.
+  * @fp: A fprobe data structure to be registered.
+@@ -237,46 +515,24 @@ static void fprobe_fail_cleanup(struct fprobe *fp)
+  */
+ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter)
+ {
+-      struct ftrace_hash *hash;
+-      unsigned char *str;
+-      int ret, len;
++      unsigned long *addrs;
++      int ret;
+       if (!fp || !filter)
+               return -EINVAL;
+-      fprobe_init(fp);
+-
+-      len = strlen(filter);
+-      str = kstrdup(filter, GFP_KERNEL);
+-      ret = ftrace_set_filter(&fp->ops, str, len, 0);
+-      kfree(str);
+-      if (ret)
++      ret = ip_list_from_filter(filter, notfilter, NULL, FPROBE_IPS_MAX);
++      if (ret < 0)
+               return ret;
+-      if (notfilter) {
+-              len = strlen(notfilter);
+-              str = kstrdup(notfilter, GFP_KERNEL);
+-              ret = ftrace_set_notrace(&fp->ops, str, len, 0);
+-              kfree(str);
+-              if (ret)
+-                      goto out;
+-      }
+-
+-      /* TODO:
+-       * correctly calculate the total number of filtered symbols
+-       * from both filter and notfilter.
+-       */
+-      hash = rcu_access_pointer(fp->ops.local_hash.filter_hash);
+-      if (WARN_ON_ONCE(!hash))
+-              goto out;
+-
+-      ret = fprobe_init_rethook(fp, (int)hash->count);
+-      if (!ret)
+-              ret = register_ftrace_function(&fp->ops);
++      addrs = kcalloc(ret, sizeof(unsigned long), GFP_KERNEL);
++      if (!addrs)
++              return -ENOMEM;
++      ret = ip_list_from_filter(filter, notfilter, addrs, ret);
++      if (ret > 0)
++              ret = register_fprobe_ips(fp, addrs, ret);
+-out:
+-      if (ret)
+-              fprobe_fail_cleanup(fp);
++      kfree(addrs);
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(register_fprobe);
+@@ -284,7 +540,7 @@ EXPORT_SYMBOL_GPL(register_fprobe);
+ /**
+  * register_fprobe_ips() - Register fprobe to ftrace by address.
+  * @fp: A fprobe data structure to be registered.
+- * @addrs: An array of target ftrace location addresses.
++ * @addrs: An array of target function address.
+  * @num: The number of entries of @addrs.
+  *
+  * Register @fp to ftrace for enabling the probe on the address given by @addrs.
+@@ -296,23 +552,27 @@ EXPORT_SYMBOL_GPL(register_fprobe);
+  */
+ int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num)
+ {
+-      int ret;
+-
+-      if (!fp || !addrs || num <= 0)
+-              return -EINVAL;
++      struct fprobe_hlist *hlist_array;
++      int ret, i;
+-      fprobe_init(fp);
+-
+-      ret = ftrace_set_filter_ips(&fp->ops, addrs, num, 0, 0);
++      ret = fprobe_init(fp, addrs, num);
+       if (ret)
+               return ret;
+-      ret = fprobe_init_rethook(fp, num);
+-      if (!ret)
+-              ret = register_ftrace_function(&fp->ops);
++      mutex_lock(&fprobe_mutex);
++
++      hlist_array = fp->hlist_array;
++      ret = fprobe_graph_add_ips(addrs, num);
++      if (!ret) {
++              add_fprobe_hash(fp);
++              for (i = 0; i < hlist_array->size; i++)
++                      insert_fprobe_node(&hlist_array->array[i]);
++      }
++      mutex_unlock(&fprobe_mutex);
+       if (ret)
+               fprobe_fail_cleanup(fp);
++
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(register_fprobe_ips);
+@@ -350,14 +610,13 @@ EXPORT_SYMBOL_GPL(register_fprobe_syms);
+ bool fprobe_is_registered(struct fprobe *fp)
+ {
+-      if (!fp || (fp->ops.saved_func != fprobe_handler &&
+-                  fp->ops.saved_func != fprobe_kprobe_handler))
++      if (!fp || !fp->hlist_array)
+               return false;
+       return true;
+ }
+ /**
+- * unregister_fprobe() - Unregister fprobe from ftrace
++ * unregister_fprobe() - Unregister fprobe.
+  * @fp: A fprobe data structure to be unregistered.
+  *
+  * Unregister fprobe (and remove ftrace hooks from the function entries).
+@@ -366,23 +625,41 @@ bool fprobe_is_registered(struct fprobe *fp)
+  */
+ int unregister_fprobe(struct fprobe *fp)
+ {
+-      int ret;
++      struct fprobe_hlist *hlist_array;
++      unsigned long *addrs = NULL;
++      int ret = 0, i, count;
+-      if (!fprobe_is_registered(fp))
+-              return -EINVAL;
++      mutex_lock(&fprobe_mutex);
++      if (!fp || !is_fprobe_still_exist(fp)) {
++              ret = -EINVAL;
++              goto out;
++      }
+-      if (!IS_ERR_OR_NULL(fp->rethook))
+-              rethook_stop(fp->rethook);
++      hlist_array = fp->hlist_array;
++      addrs = kcalloc(hlist_array->size, sizeof(unsigned long), GFP_KERNEL);
++      if (!addrs) {
++              ret = -ENOMEM;  /* TODO: Fallback to one-by-one loop */
++              goto out;
++      }
+-      ret = unregister_ftrace_function(&fp->ops);
+-      if (ret < 0)
+-              return ret;
++      /* Remove non-synonim ips from table and hash */
++      count = 0;
++      for (i = 0; i < hlist_array->size; i++) {
++              if (!delete_fprobe_node(&hlist_array->array[i]))
++                      addrs[count++] = hlist_array->array[i].addr;
++      }
++      del_fprobe_hash(fp);
+-      if (!IS_ERR_OR_NULL(fp->rethook))
+-              rethook_free(fp->rethook);
++      if (count)
++              fprobe_graph_remove_ips(addrs, count);
+-      ftrace_free_filter(&fp->ops);
++      kfree_rcu(hlist_array, rcu);
++      fp->hlist_array = NULL;
++out:
++      mutex_unlock(&fprobe_mutex);
++
++      kfree(addrs);
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(unregister_fprobe);
+diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c
+index 271ce0caeec03..cf92111b5c79d 100644
+--- a/lib/test_fprobe.c
++++ b/lib/test_fprobe.c
+@@ -17,10 +17,8 @@ static u32 rand1, entry_val, exit_val;
+ /* Use indirect calls to avoid inlining the target functions */
+ static u32 (*target)(u32 value);
+ static u32 (*target2)(u32 value);
+-static u32 (*target_nest)(u32 value, u32 (*nest)(u32));
+ static unsigned long target_ip;
+ static unsigned long target2_ip;
+-static unsigned long target_nest_ip;
+ static int entry_return_value;
+ static noinline u32 fprobe_selftest_target(u32 value)
+@@ -33,11 +31,6 @@ static noinline u32 fprobe_selftest_target2(u32 value)
+       return (value / div_factor) + 1;
+ }
+-static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32))
+-{
+-      return nest(value + 2);
+-}
+-
+ static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
+                                   unsigned long ret_ip,
+                                   struct ftrace_regs *fregs, void *data)
+@@ -79,22 +72,6 @@ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
+               KUNIT_EXPECT_NULL(current_test, data);
+ }
+-static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
+-                                    unsigned long ret_ip,
+-                                    struct ftrace_regs *fregs, void *data)
+-{
+-      KUNIT_EXPECT_FALSE(current_test, preemptible());
+-      return 0;
+-}
+-
+-static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip,
+-                                    unsigned long ret_ip,
+-                                    struct ftrace_regs *fregs, void *data)
+-{
+-      KUNIT_EXPECT_FALSE(current_test, preemptible());
+-      KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip);
+-}
+-
+ /* Test entry only (no rethook) */
+ static void test_fprobe_entry(struct kunit *test)
+ {
+@@ -191,25 +168,6 @@ static void test_fprobe_data(struct kunit *test)
+       KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
+ }
+-/* Test nr_maxactive */
+-static void test_fprobe_nest(struct kunit *test)
+-{
+-      static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_nest_target"};
+-      struct fprobe fp = {
+-              .entry_handler = nest_entry_handler,
+-              .exit_handler = nest_exit_handler,
+-              .nr_maxactive = 1,
+-      };
+-
+-      current_test = test;
+-      KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
+-
+-      target_nest(rand1, target);
+-      KUNIT_EXPECT_EQ(test, 1, fp.nmissed);
+-
+-      KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
+-}
+-
+ static void test_fprobe_skip(struct kunit *test)
+ {
+       struct fprobe fp = {
+@@ -247,10 +205,8 @@ static int fprobe_test_init(struct kunit *test)
+       rand1 = get_random_u32_above(div_factor);
+       target = fprobe_selftest_target;
+       target2 = fprobe_selftest_target2;
+-      target_nest = fprobe_selftest_nest_target;
+       target_ip = get_ftrace_location(target);
+       target2_ip = get_ftrace_location(target2);
+-      target_nest_ip = get_ftrace_location(target_nest);
+       return 0;
+ }
+@@ -260,7 +216,6 @@ static struct kunit_case fprobe_testcases[] = {
+       KUNIT_CASE(test_fprobe),
+       KUNIT_CASE(test_fprobe_syms),
+       KUNIT_CASE(test_fprobe_data),
+-      KUNIT_CASE(test_fprobe_nest),
+       KUNIT_CASE(test_fprobe_skip),
+       {}
+ };
+-- 
+2.39.5
+
diff --git a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch b/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch
new file mode 100644 (file)
index 0000000..0c7d70e
--- /dev/null
@@ -0,0 +1,207 @@
+From 96eedf4d4d07660c69478c2a7c41d8ceee750de6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:12:20 +0900
+Subject: fprobe: Use ftrace_regs in fprobe entry handler
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 46bc082388560a95e3649b698a4675e5ea3262e6 ]
+
+This allows fprobes to be available with CONFIG_DYNAMIC_FTRACE_WITH_ARGS
+instead of CONFIG_DYNAMIC_FTRACE_WITH_REGS, then we can enable fprobe
+on arm64.
+
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Link: https://lore.kernel.org/173518994037.391279.2786805566359674586.stgit@devnote2
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Florent Revest <revest@chromium.org>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/fprobe.h          |  2 +-
+ kernel/trace/Kconfig            |  3 ++-
+ kernel/trace/bpf_trace.c        | 10 +++++++---
+ kernel/trace/fprobe.c           |  3 ++-
+ kernel/trace/trace_fprobe.c     | 11 ++++++++---
+ lib/test_fprobe.c               |  4 ++--
+ samples/fprobe/fprobe_example.c |  2 +-
+ 7 files changed, 23 insertions(+), 12 deletions(-)
+
+diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h
+index f398695881175..ca64ee5e45d2c 100644
+--- a/include/linux/fprobe.h
++++ b/include/linux/fprobe.h
+@@ -10,7 +10,7 @@
+ struct fprobe;
+ typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip,
+-                             unsigned long ret_ip, struct pt_regs *regs,
++                             unsigned long ret_ip, struct ftrace_regs *regs,
+                              void *entry_data);
+ typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip,
+diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
+index c5ab2a561272d..f10ca86fbfad2 100644
+--- a/kernel/trace/Kconfig
++++ b/kernel/trace/Kconfig
+@@ -297,7 +297,7 @@ config DYNAMIC_FTRACE_WITH_ARGS
+ config FPROBE
+       bool "Kernel Function Probe (fprobe)"
+       depends on FUNCTION_TRACER
+-      depends on DYNAMIC_FTRACE_WITH_REGS
++      depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
+       depends on HAVE_RETHOOK
+       select RETHOOK
+       default n
+@@ -682,6 +682,7 @@ config FPROBE_EVENTS
+       select TRACING
+       select PROBE_EVENTS
+       select DYNAMIC_EVENTS
++      depends on DYNAMIC_FTRACE_WITH_REGS
+       default y
+       help
+         This allows user to add tracing events on the function entry and
+diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
+index 2c2205e91fee9..6b58e84995e46 100644
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2562,7 +2562,7 @@ struct bpf_session_run_ctx {
+       void *data;
+ };
+-#ifdef CONFIG_FPROBE
++#if defined(CONFIG_FPROBE) && defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS)
+ struct bpf_kprobe_multi_link {
+       struct bpf_link link;
+       struct fprobe fp;
+@@ -2814,12 +2814,16 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
+ static int
+ kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip,
+-                        unsigned long ret_ip, struct pt_regs *regs,
++                        unsigned long ret_ip, struct ftrace_regs *fregs,
+                         void *data)
+ {
++      struct pt_regs *regs = ftrace_get_regs(fregs);
+       struct bpf_kprobe_multi_link *link;
+       int err;
++      if (!regs)
++              return 0;
++
+       link = container_of(fp, struct bpf_kprobe_multi_link, fp);
+       err = kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs, false, data);
+       return is_kprobe_session(link->link.prog) ? err : 0;
+@@ -3094,7 +3098,7 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
+       kvfree(cookies);
+       return err;
+ }
+-#else /* !CONFIG_FPROBE */
++#else /* !CONFIG_FPROBE || !CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
+ {
+       return -EOPNOTSUPP;
+diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
+index 9ff0182458408..3d37892838739 100644
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -46,7 +46,7 @@ static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
+       }
+       if (fp->entry_handler)
+-              ret = fp->entry_handler(fp, ip, parent_ip, ftrace_get_regs(fregs), entry_data);
++              ret = fp->entry_handler(fp, ip, parent_ip, fregs, entry_data);
+       /* If entry_handler returns !0, nmissed is not counted. */
+       if (rh) {
+@@ -182,6 +182,7 @@ static void fprobe_init(struct fprobe *fp)
+               fp->ops.func = fprobe_kprobe_handler;
+       else
+               fp->ops.func = fprobe_handler;
++
+       fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS;
+ }
+diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
+index 99048c3303822..c1eef70212b25 100644
+--- a/kernel/trace/trace_fprobe.c
++++ b/kernel/trace/trace_fprobe.c
+@@ -217,12 +217,13 @@ NOKPROBE_SYMBOL(fentry_trace_func);
+ /* function exit handler */
+ static int trace_fprobe_entry_handler(struct fprobe *fp, unsigned long entry_ip,
+-                              unsigned long ret_ip, struct pt_regs *regs,
++                              unsigned long ret_ip, struct ftrace_regs *fregs,
+                               void *entry_data)
+ {
+       struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
++      struct pt_regs *regs = ftrace_get_regs(fregs);
+-      if (tf->tp.entry_arg)
++      if (regs && tf->tp.entry_arg)
+               store_trace_entry_data(entry_data, &tf->tp, regs);
+       return 0;
+@@ -339,12 +340,16 @@ NOKPROBE_SYMBOL(fexit_perf_func);
+ #endif        /* CONFIG_PERF_EVENTS */
+ static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip,
+-                           unsigned long ret_ip, struct pt_regs *regs,
++                           unsigned long ret_ip, struct ftrace_regs *fregs,
+                            void *entry_data)
+ {
+       struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
++      struct pt_regs *regs = ftrace_get_regs(fregs);
+       int ret = 0;
++      if (!regs)
++              return 0;
++
+       if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE))
+               fentry_trace_func(tf, entry_ip, regs);
+ #ifdef CONFIG_PERF_EVENTS
+diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c
+index 24de0e5ff8599..ff607babba189 100644
+--- a/lib/test_fprobe.c
++++ b/lib/test_fprobe.c
+@@ -40,7 +40,7 @@ static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32))
+ static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
+                                   unsigned long ret_ip,
+-                                  struct pt_regs *regs, void *data)
++                                  struct ftrace_regs *fregs, void *data)
+ {
+       KUNIT_EXPECT_FALSE(current_test, preemptible());
+       /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
+@@ -81,7 +81,7 @@ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
+ static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
+                                     unsigned long ret_ip,
+-                                    struct pt_regs *regs, void *data)
++                                    struct ftrace_regs *fregs, void *data)
+ {
+       KUNIT_EXPECT_FALSE(current_test, preemptible());
+       return 0;
+diff --git a/samples/fprobe/fprobe_example.c b/samples/fprobe/fprobe_example.c
+index 0a50b05add969..c234afae52d6f 100644
+--- a/samples/fprobe/fprobe_example.c
++++ b/samples/fprobe/fprobe_example.c
+@@ -50,7 +50,7 @@ static void show_backtrace(void)
+ static int sample_entry_handler(struct fprobe *fp, unsigned long ip,
+                               unsigned long ret_ip,
+-                              struct pt_regs *regs, void *data)
++                              struct ftrace_regs *fregs, void *data)
+ {
+       if (use_trace)
+               /*
+-- 
+2.39.5
+
diff --git a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch b/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch
new file mode 100644 (file)
index 0000000..5e3632e
--- /dev/null
@@ -0,0 +1,261 @@
+From 9ec816522c378200971176807181e023885863af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:12:31 +0900
+Subject: fprobe: Use ftrace_regs in fprobe exit handler
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 762abbc0d09f7ae123c82d315eb1a961c1a2cf7b ]
+
+Change the fprobe exit handler to use ftrace_regs structure instead of
+pt_regs. This also introduce HAVE_FTRACE_REGS_HAVING_PT_REGS which
+means the ftrace_regs is including the pt_regs so that ftrace_regs
+can provide pt_regs without memory allocation.
+Fprobe introduces a new dependency with that.
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
+Cc: Huacai Chen <chenhuacai@kernel.org>
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Florent Revest <revest@chromium.org>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: WANG Xuerui <kernel@xen0n.name>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: x86@kernel.org
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Song Liu <song@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: KP Singh <kpsingh@kernel.org>
+Cc: Matt Bobrowski <mattbobrowski@google.com>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Daniel Borkmann <daniel@iogearbox.net>
+Cc: Andrii Nakryiko <andrii@kernel.org>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: Eduard Zingerman <eddyz87@gmail.com>
+Cc: Yonghong Song <yonghong.song@linux.dev>
+Cc: John Fastabend <john.fastabend@gmail.com>
+Cc: Stanislav Fomichev <sdf@fomichev.me>
+Cc: Hao Luo <haoluo@google.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Link: https://lore.kernel.org/173518995092.391279.6765116450352977627.stgit@devnote2
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/Kconfig          | 1 +
+ arch/s390/Kconfig               | 1 +
+ arch/x86/Kconfig                | 1 +
+ include/linux/fprobe.h          | 2 +-
+ include/linux/ftrace.h          | 6 ++++++
+ kernel/trace/Kconfig            | 7 +++++++
+ kernel/trace/bpf_trace.c        | 6 +++++-
+ kernel/trace/fprobe.c           | 3 ++-
+ kernel/trace/trace_fprobe.c     | 6 +++++-
+ lib/test_fprobe.c               | 6 +++---
+ samples/fprobe/fprobe_example.c | 2 +-
+ 11 files changed, 33 insertions(+), 8 deletions(-)
+
+diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
+index 49f5bfc00e5a1..6396615ec035e 100644
+--- a/arch/loongarch/Kconfig
++++ b/arch/loongarch/Kconfig
+@@ -128,6 +128,7 @@ config LOONGARCH
+       select HAVE_DMA_CONTIGUOUS
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_DYNAMIC_FTRACE_WITH_ARGS
++      select HAVE_FTRACE_REGS_HAVING_PT_REGS
+       select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS
+       select HAVE_EBPF_JIT
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index a8cecae74fe81..c7a7f91a6ce19 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -184,6 +184,7 @@ config S390
+       select HAVE_DMA_CONTIGUOUS
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_DYNAMIC_FTRACE_WITH_ARGS
++      select HAVE_FTRACE_REGS_HAVING_PT_REGS
+       select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS
+       select HAVE_EBPF_JIT if HAVE_MARCH_Z196_FEATURES
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index aa317f6064b89..9b20a96651671 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -224,6 +224,7 @@ config X86
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS
+       select HAVE_DYNAMIC_FTRACE_WITH_ARGS    if X86_64
++      select HAVE_FTRACE_REGS_HAVING_PT_REGS  if X86_64
+       select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+       select HAVE_SAMPLE_FTRACE_DIRECT        if X86_64
+       select HAVE_SAMPLE_FTRACE_DIRECT_MULTI  if X86_64
+diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h
+index ca64ee5e45d2c..ef609bcca0f92 100644
+--- a/include/linux/fprobe.h
++++ b/include/linux/fprobe.h
+@@ -14,7 +14,7 @@ typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip,
+                              void *entry_data);
+ typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip,
+-                             unsigned long ret_ip, struct pt_regs *regs,
++                             unsigned long ret_ip, struct ftrace_regs *regs,
+                              void *entry_data);
+ /**
+diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
+index b7407004c799e..46ac44366c90a 100644
+--- a/include/linux/ftrace.h
++++ b/include/linux/ftrace.h
+@@ -176,6 +176,12 @@ static inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
+ #define ftrace_regs_set_instruction_pointer(fregs, ip) do { } while (0)
+ #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
++#ifdef CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS
++
++static_assert(sizeof(struct pt_regs) == ftrace_regs_size());
++
++#endif /* CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */
++
+ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs)
+ {
+       if (!fregs)
+diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
+index f10ca86fbfad2..7f8165f2049a5 100644
+--- a/kernel/trace/Kconfig
++++ b/kernel/trace/Kconfig
+@@ -57,6 +57,12 @@ config HAVE_DYNAMIC_FTRACE_WITH_ARGS
+        This allows for use of ftrace_regs_get_argument() and
+        ftrace_regs_get_stack_pointer().
++config HAVE_FTRACE_REGS_HAVING_PT_REGS
++      bool
++      help
++       If this is set, ftrace_regs has pt_regs, thus it can convert to
++       pt_regs without allocating memory.
++
+ config HAVE_DYNAMIC_FTRACE_NO_PATCHABLE
+       bool
+       help
+@@ -298,6 +304,7 @@ config FPROBE
+       bool "Kernel Function Probe (fprobe)"
+       depends on FUNCTION_TRACER
+       depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
++      depends on HAVE_FTRACE_REGS_HAVING_PT_REGS || !HAVE_DYNAMIC_FTRACE_WITH_ARGS
+       depends on HAVE_RETHOOK
+       select RETHOOK
+       default n
+diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
+index 6b58e84995e46..968520b04b6d3 100644
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2831,10 +2831,14 @@ kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip,
+ static void
+ kprobe_multi_link_exit_handler(struct fprobe *fp, unsigned long fentry_ip,
+-                             unsigned long ret_ip, struct pt_regs *regs,
++                             unsigned long ret_ip, struct ftrace_regs *fregs,
+                              void *data)
+ {
+       struct bpf_kprobe_multi_link *link;
++      struct pt_regs *regs = ftrace_get_regs(fregs);
++
++      if (!regs)
++              return;
+       link = container_of(fp, struct bpf_kprobe_multi_link, fp);
+       kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs, true, data);
+diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
+index 3d37892838739..90a3c8e2bbdf1 100644
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -124,6 +124,7 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data,
+ {
+       struct fprobe *fp = (struct fprobe *)data;
+       struct fprobe_rethook_node *fpr;
++      struct ftrace_regs *fregs = (struct ftrace_regs *)regs;
+       int bit;
+       if (!fp || fprobe_disabled(fp))
+@@ -141,7 +142,7 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data,
+               return;
+       }
+-      fp->exit_handler(fp, fpr->entry_ip, ret_ip, regs,
++      fp->exit_handler(fp, fpr->entry_ip, ret_ip, fregs,
+                        fp->entry_data_size ? (void *)fpr->data : NULL);
+       ftrace_test_recursion_unlock(bit);
+ }
+diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
+index c1eef70212b25..d906baba2d40c 100644
+--- a/kernel/trace/trace_fprobe.c
++++ b/kernel/trace/trace_fprobe.c
+@@ -361,10 +361,14 @@ static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip,
+ NOKPROBE_SYMBOL(fentry_dispatcher);
+ static void fexit_dispatcher(struct fprobe *fp, unsigned long entry_ip,
+-                           unsigned long ret_ip, struct pt_regs *regs,
++                           unsigned long ret_ip, struct ftrace_regs *fregs,
+                            void *entry_data)
+ {
+       struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
++      struct pt_regs *regs = ftrace_get_regs(fregs);
++
++      if (!regs)
++              return;
+       if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE))
+               fexit_trace_func(tf, entry_ip, ret_ip, regs, entry_data);
+diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c
+index ff607babba189..271ce0caeec03 100644
+--- a/lib/test_fprobe.c
++++ b/lib/test_fprobe.c
+@@ -59,9 +59,9 @@ static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
+ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
+                                   unsigned long ret_ip,
+-                                  struct pt_regs *regs, void *data)
++                                  struct ftrace_regs *fregs, void *data)
+ {
+-      unsigned long ret = regs_return_value(regs);
++      unsigned long ret = ftrace_regs_get_return_value(fregs);
+       KUNIT_EXPECT_FALSE(current_test, preemptible());
+       if (ip != target_ip) {
+@@ -89,7 +89,7 @@ static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
+ static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip,
+                                     unsigned long ret_ip,
+-                                    struct pt_regs *regs, void *data)
++                                    struct ftrace_regs *fregs, void *data)
+ {
+       KUNIT_EXPECT_FALSE(current_test, preemptible());
+       KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip);
+diff --git a/samples/fprobe/fprobe_example.c b/samples/fprobe/fprobe_example.c
+index c234afae52d6f..bfe98ce826f3a 100644
+--- a/samples/fprobe/fprobe_example.c
++++ b/samples/fprobe/fprobe_example.c
+@@ -67,7 +67,7 @@ static int sample_entry_handler(struct fprobe *fp, unsigned long ip,
+ }
+ static void sample_exit_handler(struct fprobe *fp, unsigned long ip,
+-                              unsigned long ret_ip, struct pt_regs *regs,
++                              unsigned long ret_ip, struct ftrace_regs *regs,
+                               void *data)
+ {
+       unsigned long rip = ret_ip;
+-- 
+2.39.5
+
diff --git a/queue-6.13/fs-pipe-do-not-open-code-pipe-head-tail-logic-in-fio.patch b/queue-6.13/fs-pipe-do-not-open-code-pipe-head-tail-logic-in-fio.patch
new file mode 100644 (file)
index 0000000..4440670
--- /dev/null
@@ -0,0 +1,63 @@
+From cff7aa72cf4bb6ff5928f8534d705827ec42b140 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 07:33:58 -1000
+Subject: fs/pipe: do not open-code pipe head/tail logic in FIONREAD
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+[ Upstream commit d810d4c27bf34c719243bab9feb0d843edc09fd7 ]
+
+Rasmus points out that we do indeed have other cases of breakage from
+the type changes that were introduced on 32-bit targets in order to read
+the pipe head and tail values atomically (commit 3d252160b818: "fs/pipe:
+Read pipe->{head,tail} atomically outside pipe->mutex").
+
+Fix it up by using the proper helper functions that now deal with the
+pipe buffer index types properly.  This makes the code simpler and more
+obvious.
+
+The compiler does the CSE and loop hoisting of the pipe ring size
+masking that we used to do manually, so open-coding this was never a
+good idea.
+
+Reported-by: Rasmus Villemoes <ravi@prevas.dk>
+Link: https://lore.kernel.org/all/87cyeu5zgk.fsf@prevas.dk/
+Fixes: 3d252160b818 ("fs/pipe: Read pipe->{head,tail} atomically outside pipe->mutex")Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Mateusz Guzik <mjguzik@gmail.com>
+Cc: K Prateek Nayak <kprateek.nayak@amd.com>
+Cc: Swapnil Sapkal <swapnil.sapkal@amd.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pipe.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 0b2b6ccb8ec52..6e72670a8a0dc 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -613,7 +613,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
+ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+       struct pipe_inode_info *pipe = filp->private_data;
+-      unsigned int count, head, tail, mask;
++      unsigned int count, head, tail;
+       switch (cmd) {
+       case FIONREAD:
+@@ -621,10 +621,9 @@ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+               count = 0;
+               head = pipe->head;
+               tail = pipe->tail;
+-              mask = pipe->ring_size - 1;
+-              while (tail != head) {
+-                      count += pipe->bufs[tail & mask].len;
++              while (!pipe_empty(head, tail)) {
++                      count += pipe_buf(pipe, tail)->len;
+                       tail++;
+               }
+               mutex_unlock(&pipe->mutex);
+-- 
+2.39.5
+
diff --git a/queue-6.13/fs-pipe-fix-pipe-buffer-index-use-in-fuse.patch b/queue-6.13/fs-pipe-fix-pipe-buffer-index-use-in-fuse.patch
new file mode 100644 (file)
index 0000000..d67dbe3
--- /dev/null
@@ -0,0 +1,78 @@
+From 097ef18912b9dcbefd6ee19bb430f8f2f3832fde Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 07:53:25 -1000
+Subject: fs/pipe: fix pipe buffer index use in FUSE
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+[ Upstream commit ebb0f38bb47f74b29e267babdbcd2c47d5292aa8 ]
+
+This was another case that Rasmus pointed out where the direct access to
+the pipe head and tail pointers broke on 32-bit configurations due to
+the type changes.
+
+As with the pipe FIONREAD case, fix it by using the appropriate helper
+functions that deal with the right pipe index sizing.
+
+Reported-by: Rasmus Villemoes <ravi@prevas.dk>
+Link: https://lore.kernel.org/all/878qpi5wz4.fsf@prevas.dk/
+Fixes: 3d252160b818 ("fs/pipe: Read pipe->{head,tail} atomically outside pipe->mutex")Cc: Oleg >
+Cc: Mateusz Guzik <mjguzik@gmail.com>
+Cc: K Prateek Nayak <kprateek.nayak@amd.com>
+Cc: Swapnil Sapkal <swapnil.sapkal@amd.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/fuse/dev.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
+index 9ce6d1c6cac15..b8fb5da2565ed 100644
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -2097,7 +2097,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
+                                    struct file *out, loff_t *ppos,
+                                    size_t len, unsigned int flags)
+ {
+-      unsigned int head, tail, mask, count;
++      unsigned int head, tail, count;
+       unsigned nbuf;
+       unsigned idx;
+       struct pipe_buffer *bufs;
+@@ -2114,8 +2114,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
+       head = pipe->head;
+       tail = pipe->tail;
+-      mask = pipe->ring_size - 1;
+-      count = head - tail;
++      count = pipe_occupancy(head, tail);
+       bufs = kvmalloc_array(count, sizeof(struct pipe_buffer), GFP_KERNEL);
+       if (!bufs) {
+@@ -2125,8 +2124,8 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
+       nbuf = 0;
+       rem = 0;
+-      for (idx = tail; idx != head && rem < len; idx++)
+-              rem += pipe->bufs[idx & mask].len;
++      for (idx = tail; !pipe_empty(head, idx) && rem < len; idx++)
++              rem += pipe_buf(pipe, idx)->len;
+       ret = -EINVAL;
+       if (rem < len)
+@@ -2137,10 +2136,10 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
+               struct pipe_buffer *ibuf;
+               struct pipe_buffer *obuf;
+-              if (WARN_ON(nbuf >= count || tail == head))
++              if (WARN_ON(nbuf >= count || pipe_empty(head, tail)))
+                       goto out_free;
+-              ibuf = &pipe->bufs[tail & mask];
++              ibuf = pipe_buf(pipe, tail);
+               obuf = &bufs[nbuf];
+               if (rem >= ibuf->len) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/fs-pipe-fix-pipe_occupancy-with-16-bit-indexes.patch b/queue-6.13/fs-pipe-fix-pipe_occupancy-with-16-bit-indexes.patch
new file mode 100644 (file)
index 0000000..a9ffd78
--- /dev/null
@@ -0,0 +1,48 @@
+From f0472863c6ef82537b45b7056dd15b42f505097e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 07:08:09 -1000
+Subject: fs/pipe: Fix pipe_occupancy() with 16-bit indexes
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+[ Upstream commit c27c66afc449b80f3b4b84d123358c0248f2cf63 ]
+
+The pipe_occupancy() logic implicitly relied on the natural unsigned
+modulo arithmetic in C, but that doesn't work for the new 'pipe_index_t'
+case, since any arithmetic will be done in 'int' (and here we had also
+made it 'unsigned int' due to the function call boundary).
+
+So make the modulo arithmetic explicit by casting the result to the
+proper type.
+
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Mateusz Guzik <mjguzik@gmail.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Swapnil Sapkal <swapnil.sapkal@amd.com>
+Cc: Alexey Gladkov <legion@kernel.org>
+Cc: K Prateek Nayak <kprateek.nayak@amd.com>
+Link: https://lore.kernel.org/all/CAHk-=wjyHsGLx=rxg6PKYBNkPYAejgo7=CbyL3=HGLZLsAaJFQ@mail.gmail.com/
+Fixes: 3d252160b818 ("fs/pipe: Read pipe->{head,tail} atomically outside pipe->mutex")
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/pipe_fs_i.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
+index 3cc4f8eab853f..1f013ed7577ef 100644
+--- a/include/linux/pipe_fs_i.h
++++ b/include/linux/pipe_fs_i.h
+@@ -192,7 +192,7 @@ static inline bool pipe_empty(unsigned int head, unsigned int tail)
+  */
+ static inline unsigned int pipe_occupancy(unsigned int head, unsigned int tail)
+ {
+-      return head - tail;
++      return (pipe_index_t)(head - tail);
+ }
+ /**
+-- 
+2.39.5
+
diff --git a/queue-6.13/fs-pipe-read-pipe-head-tail-atomically-outside-pipe-.patch b/queue-6.13/fs-pipe-read-pipe-head-tail-atomically-outside-pipe-.patch
new file mode 100644 (file)
index 0000000..d5b5e9b
--- /dev/null
@@ -0,0 +1,220 @@
+From 2fa9bc4a929953d776783b960bbbd9b78efed1c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 13:51:38 +0000
+Subject: fs/pipe: Read pipe->{head,tail} atomically outside pipe->mutex
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+[ Upstream commit 3d252160b818045f3a152b13756f6f37ca34639d ]
+
+pipe_readable(), pipe_writable(), and pipe_poll() can read "pipe->head"
+and "pipe->tail" outside of "pipe->mutex" critical section. When the
+head and the tail are read individually in that order, there is a window
+for interruption between the two reads in which both the head and the
+tail can be updated by concurrent readers and writers.
+
+One of the problematic scenarios observed with hackbench running
+multiple groups on a large server on a particular pipe inode is as
+follows:
+
+    pipe->head = 36
+    pipe->tail = 36
+
+    hackbench-118762  [057] .....  1029.550548: pipe_write: *wakes up: pipe not full*
+    hackbench-118762  [057] .....  1029.550548: pipe_write: head: 36 -> 37 [tail: 36]
+    hackbench-118762  [057] .....  1029.550548: pipe_write: *wake up next reader 118740*
+    hackbench-118762  [057] .....  1029.550548: pipe_write: *wake up next writer 118768*
+
+    hackbench-118768  [206] .....  1029.55055X: pipe_write: *writer wakes up*
+    hackbench-118768  [206] .....  1029.55055X: pipe_write: head = READ_ONCE(pipe->head) [37]
+    ... CPU 206 interrupted (exact wakeup was not traced but 118768 did read head at 37 in traces)
+
+    hackbench-118740  [057] .....  1029.550558: pipe_read:  *reader wakes up: pipe is not empty*
+    hackbench-118740  [057] .....  1029.550558: pipe_read:  tail: 36 -> 37 [head = 37]
+    hackbench-118740  [057] .....  1029.550559: pipe_read:  *pipe is empty; wakeup writer 118768*
+    hackbench-118740  [057] .....  1029.550559: pipe_read:  *sleeps*
+
+    hackbench-118766  [185] .....  1029.550592: pipe_write: *New writer comes in*
+    hackbench-118766  [185] .....  1029.550592: pipe_write: head: 37 -> 38 [tail: 37]
+    hackbench-118766  [185] .....  1029.550592: pipe_write: *wakes up reader 118766*
+
+    hackbench-118740  [185] .....  1029.550598: pipe_read:  *reader wakes up; pipe not empty*
+    hackbench-118740  [185] .....  1029.550599: pipe_read:  tail: 37 -> 38 [head: 38]
+    hackbench-118740  [185] .....  1029.550599: pipe_read:  *pipe is empty*
+    hackbench-118740  [185] .....  1029.550599: pipe_read:  *reader sleeps; wakeup writer 118768*
+
+    ... CPU 206 switches back to writer
+    hackbench-118768  [206] .....  1029.550601: pipe_write: tail = READ_ONCE(pipe->tail) [38]
+    hackbench-118768  [206] .....  1029.550601: pipe_write: pipe_full()? (u32)(37 - 38) >= 16? Yes
+    hackbench-118768  [206] .....  1029.550601: pipe_write: *writer goes back to sleep*
+
+    [ Tasks 118740 and 118768 can then indefinitely wait on each other. ]
+
+The unsigned arithmetic in pipe_occupancy() wraps around when
+"pipe->tail > pipe->head" leading to pipe_full() returning true despite
+the pipe being empty.
+
+The case of genuine wraparound of "pipe->head" is handled since pipe
+buffer has data allowing readers to make progress until the pipe->tail
+wraps too after which the reader will wakeup a sleeping writer, however,
+mistaking the pipe to be full when it is in fact empty can lead to
+readers and writers waiting on each other indefinitely.
+
+This issue became more problematic and surfaced as a hang in hackbench
+after the optimization in commit aaec5a95d596 ("pipe_read: don't wake up
+the writer if the pipe is still full") significantly reduced the number
+of spurious wakeups of writers that had previously helped mask the
+issue.
+
+To avoid missing any updates between the reads of "pipe->head" and
+"pipe->write", unionize the two with a single unsigned long
+"pipe->head_tail" member that can be loaded atomically.
+
+Using "pipe->head_tail" to read the head and the tail ensures the
+lockless checks do not miss any updates to the head or the tail and
+since those two are only updated under "pipe->mutex", it ensures that
+the head is always ahead of, or equal to the tail resulting in correct
+calculations.
+
+  [ prateek: commit log, testing on x86 platforms. ]
+
+Reported-and-debugged-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
+Closes: https://lore.kernel.org/lkml/e813814e-7094-4673-bc69-731af065a0eb@amd.com/
+Reported-by: Alexey Gladkov <legion@kernel.org>
+Closes: https://lore.kernel.org/all/Z8Wn0nTvevLRG_4m@example.org/
+Fixes: 8cefc107ca54 ("pipe: Use head and tail pointers for the ring, not cursor and length")
+Tested-by: Swapnil Sapkal <swapnil.sapkal@amd.com>
+Reviewed-by: Oleg Nesterov <oleg@redhat.com>
+Tested-by: Alexey Gladkov <legion@kernel.org>
+Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pipe.c                 | 19 ++++++++-----------
+ include/linux/pipe_fs_i.h | 39 +++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 45 insertions(+), 13 deletions(-)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 12b22c2723b7e..0b2b6ccb8ec52 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -210,11 +210,10 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
+ /* Done while waiting without holding the pipe lock - thus the READ_ONCE() */
+ static inline bool pipe_readable(const struct pipe_inode_info *pipe)
+ {
+-      unsigned int head = READ_ONCE(pipe->head);
+-      unsigned int tail = READ_ONCE(pipe->tail);
++      union pipe_index idx = { .head_tail = READ_ONCE(pipe->head_tail) };
+       unsigned int writers = READ_ONCE(pipe->writers);
+-      return !pipe_empty(head, tail) || !writers;
++      return !pipe_empty(idx.head, idx.tail) || !writers;
+ }
+ static inline unsigned int pipe_update_tail(struct pipe_inode_info *pipe,
+@@ -416,11 +415,10 @@ static inline int is_packetized(struct file *file)
+ /* Done while waiting without holding the pipe lock - thus the READ_ONCE() */
+ static inline bool pipe_writable(const struct pipe_inode_info *pipe)
+ {
+-      unsigned int head = READ_ONCE(pipe->head);
+-      unsigned int tail = READ_ONCE(pipe->tail);
++      union pipe_index idx = { .head_tail = READ_ONCE(pipe->head_tail) };
+       unsigned int max_usage = READ_ONCE(pipe->max_usage);
+-      return !pipe_full(head, tail, max_usage) ||
++      return !pipe_full(idx.head, idx.tail, max_usage) ||
+               !READ_ONCE(pipe->readers);
+ }
+@@ -658,7 +656,7 @@ pipe_poll(struct file *filp, poll_table *wait)
+ {
+       __poll_t mask;
+       struct pipe_inode_info *pipe = filp->private_data;
+-      unsigned int head, tail;
++      union pipe_index idx;
+       /* Epoll has some historical nasty semantics, this enables them */
+       WRITE_ONCE(pipe->poll_usage, true);
+@@ -679,19 +677,18 @@ pipe_poll(struct file *filp, poll_table *wait)
+        * if something changes and you got it wrong, the poll
+        * table entry will wake you up and fix it.
+        */
+-      head = READ_ONCE(pipe->head);
+-      tail = READ_ONCE(pipe->tail);
++      idx.head_tail = READ_ONCE(pipe->head_tail);
+       mask = 0;
+       if (filp->f_mode & FMODE_READ) {
+-              if (!pipe_empty(head, tail))
++              if (!pipe_empty(idx.head, idx.tail))
+                       mask |= EPOLLIN | EPOLLRDNORM;
+               if (!pipe->writers && filp->f_pipe != pipe->w_counter)
+                       mask |= EPOLLHUP;
+       }
+       if (filp->f_mode & FMODE_WRITE) {
+-              if (!pipe_full(head, tail, pipe->max_usage))
++              if (!pipe_full(idx.head, idx.tail, pipe->max_usage))
+                       mask |= EPOLLOUT | EPOLLWRNORM;
+               /*
+                * Most Unices do not set EPOLLERR for FIFOs but on Linux they
+diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
+index 8ff23bf5a8197..3cc4f8eab853f 100644
+--- a/include/linux/pipe_fs_i.h
++++ b/include/linux/pipe_fs_i.h
+@@ -31,6 +31,33 @@ struct pipe_buffer {
+       unsigned long private;
+ };
++/*
++ * Really only alpha needs 32-bit fields, but
++ * might as well do it for 64-bit architectures
++ * since that's what we've historically done,
++ * and it makes 'head_tail' always be a simple
++ * 'unsigned long'.
++ */
++#ifdef CONFIG_64BIT
++typedef unsigned int pipe_index_t;
++#else
++typedef unsigned short pipe_index_t;
++#endif
++
++/*
++ * We have to declare this outside 'struct pipe_inode_info',
++ * but then we can't use 'union pipe_index' for an anonymous
++ * union, so we end up having to duplicate this declaration
++ * below. Annoying.
++ */
++union pipe_index {
++      unsigned long head_tail;
++      struct {
++              pipe_index_t head;
++              pipe_index_t tail;
++      };
++};
++
+ /**
+  *    struct pipe_inode_info - a linux kernel pipe
+  *    @mutex: mutex protecting the whole thing
+@@ -58,8 +85,16 @@ struct pipe_buffer {
+ struct pipe_inode_info {
+       struct mutex mutex;
+       wait_queue_head_t rd_wait, wr_wait;
+-      unsigned int head;
+-      unsigned int tail;
++
++      /* This has to match the 'union pipe_index' above */
++      union {
++              unsigned long head_tail;
++              struct {
++                      pipe_index_t head;
++                      pipe_index_t tail;
++              };
++      };
++
+       unsigned int max_usage;
+       unsigned int ring_size;
+       unsigned int nr_accounted;
+-- 
+2.39.5
+
diff --git a/queue-6.13/gpio-rcar-fix-missing-of_node_put-call.patch b/queue-6.13/gpio-rcar-fix-missing-of_node_put-call.patch
new file mode 100644 (file)
index 0000000..8aa1b30
--- /dev/null
@@ -0,0 +1,47 @@
+From d5a4d8738022b2e41b210e95dee105b5140a9af3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 16:37:50 +0000
+Subject: gpio: rcar: Fix missing of_node_put() call
+
+From: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
+
+[ Upstream commit 391b41f983bf7ff853de44704d8e14e7cc648a9b ]
+
+of_parse_phandle_with_fixed_args() requires its caller to
+call into of_node_put() on the node pointer from the output
+structure, but such a call is currently missing.
+
+Call into of_node_put() to rectify that.
+
+Fixes: 159f8a0209af ("gpio-rcar: Add DT support")
+Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
+Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/r/20250305163753.34913-2-fabrizio.castro.jz@renesas.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-rcar.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
+index 8e0544e924886..a7a1cdf7ac66d 100644
+--- a/drivers/gpio/gpio-rcar.c
++++ b/drivers/gpio/gpio-rcar.c
+@@ -468,7 +468,12 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
+       p->info = *info;
+       ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
+-      *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
++      if (ret) {
++              *npins = RCAR_MAX_GPIO_PER_BANK;
++      } else {
++              *npins = args.args[2];
++              of_node_put(args.np);
++      }
+       if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
+               dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
+-- 
+2.39.5
+
diff --git a/queue-6.13/hid-google-fix-unused-variable-warning-under-config_.patch b/queue-6.13/hid-google-fix-unused-variable-warning-under-config_.patch
new file mode 100644 (file)
index 0000000..d3c96ce
--- /dev/null
@@ -0,0 +1,50 @@
+From c94020093fa2fa11fe4e556ead67f7d46ad9a3ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 00:50:13 +0800
+Subject: HID: google: fix unused variable warning under !CONFIG_ACPI
+
+From: Yu-Chun Lin <eleanor15x@gmail.com>
+
+[ Upstream commit 4bd0725c09f377ffaf22b834241f6c050742e4fc ]
+
+As reported by the kernel test robot, the following warning occurs:
+
+>> drivers/hid/hid-google-hammer.c:261:36: warning: 'cbas_ec_acpi_ids' defined but not used [-Wunused-const-variable=]
+     261 | static const struct acpi_device_id cbas_ec_acpi_ids[] = {
+         |                                    ^~~~~~~~~~~~~~~~
+
+The 'cbas_ec_acpi_ids' array is only used when CONFIG_ACPI is enabled.
+Wrapping its definition and 'MODULE_DEVICE_TABLE' in '#ifdef CONFIG_ACPI'
+prevents a compiler warning when ACPI is disabled.
+
+Fixes: eb1aac4c8744f75 ("HID: google: add support tablet mode switch for Whiskers")
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202501201141.jctFH5eB-lkp@intel.com/
+Signed-off-by: Yu-Chun Lin <eleanor15x@gmail.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-google-hammer.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
+index 0f292b5d3e26d..eb6fd2dc75d0a 100644
+--- a/drivers/hid/hid-google-hammer.c
++++ b/drivers/hid/hid-google-hammer.c
+@@ -268,11 +268,13 @@ static void cbas_ec_remove(struct platform_device *pdev)
+       mutex_unlock(&cbas_ec_reglock);
+ }
++#ifdef CONFIG_ACPI
+ static const struct acpi_device_id cbas_ec_acpi_ids[] = {
+       { "GOOG000B", 0 },
+       { }
+ };
+ MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
++#endif
+ #ifdef CONFIG_OF
+ static const struct of_device_id cbas_ec_of_match[] = {
+-- 
+2.39.5
+
diff --git a/queue-6.13/hid-hid-steam-fix-use-after-free-when-detaching-devi.patch b/queue-6.13/hid-hid-steam-fix-use-after-free-when-detaching-devi.patch
new file mode 100644 (file)
index 0000000..f0d67fa
--- /dev/null
@@ -0,0 +1,45 @@
+From 3a4b825dce120c159d018af99a503f6303ce13b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 15:41:33 -0800
+Subject: HID: hid-steam: Fix use-after-free when detaching device
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ Upstream commit e53fc232a65f7488ab75d03a5b95f06aaada7262 ]
+
+When a hid-steam device is removed it must clean up the client_hdev used for
+intercepting hidraw access. This can lead to scheduling deferred work to
+reattach the input device. Though the cleanup cancels the deferred work, this
+was done before the client_hdev itself is cleaned up, so it gets rescheduled.
+This patch fixes the ordering to make sure the deferred work is properly
+canceled.
+
+Reported-by: syzbot+0154da2d403396b2bd59@syzkaller.appspotmail.com
+Fixes: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Vicki Pfau <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-steam.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
+index 5f8518f6f5ac7..03e57d8acdadf 100644
+--- a/drivers/hid/hid-steam.c
++++ b/drivers/hid/hid-steam.c
+@@ -1327,11 +1327,11 @@ static void steam_remove(struct hid_device *hdev)
+               return;
+       }
++      hid_destroy_device(steam->client_hdev);
+       cancel_delayed_work_sync(&steam->mode_switch);
+       cancel_work_sync(&steam->work_connect);
+       cancel_work_sync(&steam->rumble_work);
+       cancel_work_sync(&steam->unregister_work);
+-      hid_destroy_device(steam->client_hdev);
+       steam->client_hdev = NULL;
+       steam->client_opened = 0;
+       if (steam->quirks & STEAM_QUIRK_WIRELESS) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-hid_is.patch b/queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-hid_is.patch
new file mode 100644 (file)
index 0000000..59767cf
--- /dev/null
@@ -0,0 +1,66 @@
+From 0c0668479bc1870ce39e777163eb90f52a8ca8c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 14:37:29 +0800
+Subject: HID: intel-ish-hid: Fix use-after-free issue in hid_ishtp_cl_remove()
+
+From: Zhang Lixu <lixu.zhang@intel.com>
+
+[ Upstream commit 823987841424289339fdb4ba90e6d2c3792836db ]
+
+During the `rmmod` operation for the `intel_ishtp_hid` driver, a
+use-after-free issue can occur in the hid_ishtp_cl_remove() function.
+The function hid_ishtp_cl_deinit() is called before ishtp_hid_remove(),
+which can lead to accessing freed memory or resources during the
+removal process.
+
+Call Trace:
+ ? ishtp_cl_send+0x168/0x220 [intel_ishtp]
+ ? hid_output_report+0xe3/0x150 [hid]
+ hid_ishtp_set_feature+0xb5/0x120 [intel_ishtp_hid]
+ ishtp_hid_request+0x7b/0xb0 [intel_ishtp_hid]
+ hid_hw_request+0x1f/0x40 [hid]
+ sensor_hub_set_feature+0x11f/0x190 [hid_sensor_hub]
+ _hid_sensor_power_state+0x147/0x1e0 [hid_sensor_trigger]
+ hid_sensor_runtime_resume+0x22/0x30 [hid_sensor_trigger]
+ sensor_hub_remove+0xa8/0xe0 [hid_sensor_hub]
+ hid_device_remove+0x49/0xb0 [hid]
+ hid_destroy_device+0x6f/0x90 [hid]
+ ishtp_hid_remove+0x42/0x70 [intel_ishtp_hid]
+ hid_ishtp_cl_remove+0x6b/0xb0 [intel_ishtp_hid]
+ ishtp_cl_device_remove+0x4a/0x60 [intel_ishtp]
+ ...
+
+Additionally, ishtp_hid_remove() is a HID level power off, which should
+occur before the ISHTP level disconnect.
+
+This patch resolves the issue by reordering the calls in
+hid_ishtp_cl_remove(). The function ishtp_hid_remove() is now
+called before hid_ishtp_cl_deinit().
+
+Fixes: f645a90e8ff7 ("HID: intel-ish-hid: ishtp-hid-client: use helper functions for connection")
+Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
+Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/intel-ish-hid/ishtp-hid-client.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+index cb04cd1d980bd..6550ad5bfbb53 100644
+--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
++++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+@@ -832,9 +832,9 @@ static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
+                       hid_ishtp_cl);
+       dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
+-      hid_ishtp_cl_deinit(hid_ishtp_cl);
+       ishtp_put_device(cl_device);
+       ishtp_hid_remove(client_data);
++      hid_ishtp_cl_deinit(hid_ishtp_cl);
+       hid_ishtp_cl = NULL;
+-- 
+2.39.5
+
diff --git a/queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-ishtp_.patch b/queue-6.13/hid-intel-ish-hid-fix-use-after-free-issue-in-ishtp_.patch
new file mode 100644 (file)
index 0000000..99b08bc
--- /dev/null
@@ -0,0 +1,55 @@
+From 22966fef72cec94309dad509a4fac9d17500a8a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 14:37:30 +0800
+Subject: HID: intel-ish-hid: Fix use-after-free issue in ishtp_hid_remove()
+
+From: Zhang Lixu <lixu.zhang@intel.com>
+
+[ Upstream commit 07583a0010696a17fb0942e0b499a62785c5fc9f ]
+
+The system can experience a random crash a few minutes after the driver is
+removed. This issue occurs due to improper handling of memory freeing in
+the ishtp_hid_remove() function.
+
+The function currently frees the `driver_data` directly within the loop
+that destroys the HID devices, which can lead to accessing freed memory.
+Specifically, `hid_destroy_device()` uses `driver_data` when it calls
+`hid_ishtp_set_feature()` to power off the sensor, so freeing
+`driver_data` beforehand can result in accessing invalid memory.
+
+This patch resolves the issue by storing the `driver_data` in a temporary
+variable before calling `hid_destroy_device()`, and then freeing the
+`driver_data` after the device is destroyed.
+
+Fixes: 0b28cb4bcb17 ("HID: intel-ish-hid: ISH HID client driver")
+Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
+Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/intel-ish-hid/ishtp-hid.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c
+index 00c6f0ebf3563..be2c62fc8251d 100644
+--- a/drivers/hid/intel-ish-hid/ishtp-hid.c
++++ b/drivers/hid/intel-ish-hid/ishtp-hid.c
+@@ -261,12 +261,14 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
+  */
+ void ishtp_hid_remove(struct ishtp_cl_data *client_data)
+ {
++      void *data;
+       int i;
+       for (i = 0; i < client_data->num_hid_devices; ++i) {
+               if (client_data->hid_sensor_hubs[i]) {
+-                      kfree(client_data->hid_sensor_hubs[i]->driver_data);
++                      data = client_data->hid_sensor_hubs[i]->driver_data;
+                       hid_destroy_device(client_data->hid_sensor_hubs[i]);
++                      kfree(data);
+                       client_data->hid_sensor_hubs[i] = NULL;
+               }
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.13/hwmon-ad7314-validate-leading-zero-bits-and-return-e.patch b/queue-6.13/hwmon-ad7314-validate-leading-zero-bits-and-return-e.patch
new file mode 100644 (file)
index 0000000..86633d1
--- /dev/null
@@ -0,0 +1,65 @@
+From 1cff4f8e21c80b98933f8eda1f8576cb43100569 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 09:19:04 +0000
+Subject: hwmon: (ad7314) Validate leading zero bits and return error
+
+From: Erik Schumacher <erik.schumacher@iris-sensing.com>
+
+[ Upstream commit e278d5e8aef4c0a1d9a9fa8b8910d713a89aa800 ]
+
+Leading zero bits are sent on the bus before the temperature value is
+transmitted. If any of these bits are high, the connection might be
+unstable or there could be no AD7314 / ADT730x (or compatible) at all.
+Return -EIO in that case.
+
+Signed-off-by: Erik Schumacher <erik.schumacher@iris-sensing.com>
+Fixes: 4f3a659581cab ("hwmon: AD7314 driver (ported from IIO)")
+Link: https://lore.kernel.org/r/24a50c2981a318580aca8f50d23be7987b69ea00.camel@iris-sensing.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ad7314.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
+index 7802bbf5f9587..59424103f6348 100644
+--- a/drivers/hwmon/ad7314.c
++++ b/drivers/hwmon/ad7314.c
+@@ -22,11 +22,13 @@
+  */
+ #define AD7314_TEMP_MASK              0x7FE0
+ #define AD7314_TEMP_SHIFT             5
++#define AD7314_LEADING_ZEROS_MASK     BIT(15)
+ /*
+  * ADT7301 and ADT7302 temperature masks
+  */
+ #define ADT7301_TEMP_MASK             0x3FFF
++#define ADT7301_LEADING_ZEROS_MASK    (BIT(15) | BIT(14))
+ enum ad7314_variant {
+       adt7301,
+@@ -65,12 +67,20 @@ static ssize_t ad7314_temperature_show(struct device *dev,
+               return ret;
+       switch (spi_get_device_id(chip->spi_dev)->driver_data) {
+       case ad7314:
++              if (ret & AD7314_LEADING_ZEROS_MASK) {
++                      /* Invalid read-out, leading zero part is missing */
++                      return -EIO;
++              }
+               data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
+               data = sign_extend32(data, 9);
+               return sprintf(buf, "%d\n", 250 * data);
+       case adt7301:
+       case adt7302:
++              if (ret & ADT7301_LEADING_ZEROS_MASK) {
++                      /* Invalid read-out, leading zero part is missing */
++                      return -EIO;
++              }
+               /*
+                * Documented as a 13 bit twos complement register
+                * with a sign bit - which is a 14 bit 2's complement
+-- 
+2.39.5
+
diff --git a/queue-6.13/hwmon-fix-a-null-vs-is_err_or_null-check-in-xgene_hw.patch b/queue-6.13/hwmon-fix-a-null-vs-is_err_or_null-check-in-xgene_hw.patch
new file mode 100644 (file)
index 0000000..d522c82
--- /dev/null
@@ -0,0 +1,37 @@
+From a3533819bc031a0bebd0d00fcf21e35dad4c7b8b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 07:57:33 -0500
+Subject: hwmon: fix a NULL vs IS_ERR_OR_NULL() check in xgene_hwmon_probe()
+
+From: Xinghuo Chen <xinghuo.chen@foxmail.com>
+
+[ Upstream commit 10fce7ebe888fa8c97eee7e317a47e7603e5e78d ]
+
+The devm_memremap() function returns error pointers on error,
+it doesn't return NULL.
+
+Fixes: c7cefce03e69 ("hwmon: (xgene) access mailbox as RAM")
+Signed-off-by: Xinghuo Chen <xinghuo.chen@foxmail.com>
+Link: https://lore.kernel.org/r/tencent_9AD8E7683EC29CAC97496B44F3F865BA070A@qq.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/xgene-hwmon.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c
+index 1e3bd129a922d..7087197383c96 100644
+--- a/drivers/hwmon/xgene-hwmon.c
++++ b/drivers/hwmon/xgene-hwmon.c
+@@ -706,7 +706,7 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
+                       goto out;
+               }
+-              if (!ctx->pcc_comm_addr) {
++              if (IS_ERR_OR_NULL(ctx->pcc_comm_addr)) {
+                       dev_err(&pdev->dev,
+                               "Failed to ioremap PCC comm region\n");
+                       rc = -ENOMEM;
+-- 
+2.39.5
+
diff --git a/queue-6.13/hwmon-ntc_thermistor-fix-the-ncpxxxh103-sensor-table.patch b/queue-6.13/hwmon-ntc_thermistor-fix-the-ncpxxxh103-sensor-table.patch
new file mode 100644 (file)
index 0000000..9c070a1
--- /dev/null
@@ -0,0 +1,108 @@
+From 4940cdde6a7cf5da398706e0483f8be626543546 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 13:57:53 +0100
+Subject: hwmon: (ntc_thermistor) Fix the ncpXXxh103 sensor table
+
+From: Maud Spierings <maudspierings@gocontroll.com>
+
+[ Upstream commit 1c7932d5ae0f5c22fa52ac811b4c427bbca5aff5 ]
+
+I could not find a single table that has the values currently present in
+the table, change it to the actual values that can be found in [1]/[2]
+and [3] (page 15 column 2)
+
+[1]: https://www.murata.com/products/productdetail?partno=NCP15XH103F03RC
+[2]: https://www.murata.com/products/productdata/8796836626462/NTHCG83.txt?1437969843000
+[3]: https://nl.mouser.com/datasheet/2/281/r44e-522712.pdf
+
+Fixes: 54ce3a0d8011 ("hwmon: (ntc_thermistor) Add support for ncpXXxh103")
+Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
+Link: https://lore.kernel.org/r/20250227-ntc_thermistor_fixes-v1-3-70fa73200b52@gocontroll.com
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ntc_thermistor.c | 66 +++++++++++++++++-----------------
+ 1 file changed, 33 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
+index b5352900463fb..0d29c8f97ba7c 100644
+--- a/drivers/hwmon/ntc_thermistor.c
++++ b/drivers/hwmon/ntc_thermistor.c
+@@ -181,40 +181,40 @@ static const struct ntc_compensation ncpXXwf104[] = {
+ };
+ static const struct ntc_compensation ncpXXxh103[] = {
+-      { .temp_c       = -40, .ohm     = 247565 },
+-      { .temp_c       = -35, .ohm     = 181742 },
+-      { .temp_c       = -30, .ohm     = 135128 },
+-      { .temp_c       = -25, .ohm     = 101678 },
+-      { .temp_c       = -20, .ohm     = 77373 },
+-      { .temp_c       = -15, .ohm     = 59504 },
+-      { .temp_c       = -10, .ohm     = 46222 },
+-      { .temp_c       = -5, .ohm      = 36244 },
+-      { .temp_c       = 0, .ohm       = 28674 },
+-      { .temp_c       = 5, .ohm       = 22878 },
+-      { .temp_c       = 10, .ohm      = 18399 },
+-      { .temp_c       = 15, .ohm      = 14910 },
+-      { .temp_c       = 20, .ohm      = 12169 },
++      { .temp_c       = -40, .ohm     = 195652 },
++      { .temp_c       = -35, .ohm     = 148171 },
++      { .temp_c       = -30, .ohm     = 113347 },
++      { .temp_c       = -25, .ohm     = 87559 },
++      { .temp_c       = -20, .ohm     = 68237 },
++      { .temp_c       = -15, .ohm     = 53650 },
++      { .temp_c       = -10, .ohm     = 42506 },
++      { .temp_c       = -5, .ohm      = 33892 },
++      { .temp_c       = 0, .ohm       = 27219 },
++      { .temp_c       = 5, .ohm       = 22021 },
++      { .temp_c       = 10, .ohm      = 17926 },
++      { .temp_c       = 15, .ohm      = 14674 },
++      { .temp_c       = 20, .ohm      = 12081 },
+       { .temp_c       = 25, .ohm      = 10000 },
+-      { .temp_c       = 30, .ohm      = 8271 },
+-      { .temp_c       = 35, .ohm      = 6883 },
+-      { .temp_c       = 40, .ohm      = 5762 },
+-      { .temp_c       = 45, .ohm      = 4851 },
+-      { .temp_c       = 50, .ohm      = 4105 },
+-      { .temp_c       = 55, .ohm      = 3492 },
+-      { .temp_c       = 60, .ohm      = 2985 },
+-      { .temp_c       = 65, .ohm      = 2563 },
+-      { .temp_c       = 70, .ohm      = 2211 },
+-      { .temp_c       = 75, .ohm      = 1915 },
+-      { .temp_c       = 80, .ohm      = 1666 },
+-      { .temp_c       = 85, .ohm      = 1454 },
+-      { .temp_c       = 90, .ohm      = 1275 },
+-      { .temp_c       = 95, .ohm      = 1121 },
+-      { .temp_c       = 100, .ohm     = 990 },
+-      { .temp_c       = 105, .ohm     = 876 },
+-      { .temp_c       = 110, .ohm     = 779 },
+-      { .temp_c       = 115, .ohm     = 694 },
+-      { .temp_c       = 120, .ohm     = 620 },
+-      { .temp_c       = 125, .ohm     = 556 },
++      { .temp_c       = 30, .ohm      = 8315 },
++      { .temp_c       = 35, .ohm      = 6948 },
++      { .temp_c       = 40, .ohm      = 5834 },
++      { .temp_c       = 45, .ohm      = 4917 },
++      { .temp_c       = 50, .ohm      = 4161 },
++      { .temp_c       = 55, .ohm      = 3535 },
++      { .temp_c       = 60, .ohm      = 3014 },
++      { .temp_c       = 65, .ohm      = 2586 },
++      { .temp_c       = 70, .ohm      = 2228 },
++      { .temp_c       = 75, .ohm      = 1925 },
++      { .temp_c       = 80, .ohm      = 1669 },
++      { .temp_c       = 85, .ohm      = 1452 },
++      { .temp_c       = 90, .ohm      = 1268 },
++      { .temp_c       = 95, .ohm      = 1110 },
++      { .temp_c       = 100, .ohm     = 974 },
++      { .temp_c       = 105, .ohm     = 858 },
++      { .temp_c       = 110, .ohm     = 758 },
++      { .temp_c       = 115, .ohm     = 672 },
++      { .temp_c       = 120, .ohm     = 596 },
++      { .temp_c       = 125, .ohm     = 531 },
+ };
+ /*
+-- 
+2.39.5
+
diff --git a/queue-6.13/hwmon-pmbus-initialise-page-count-in-pmbus_identify.patch b/queue-6.13/hwmon-pmbus-initialise-page-count-in-pmbus_identify.patch
new file mode 100644 (file)
index 0000000..f1cbf90
--- /dev/null
@@ -0,0 +1,49 @@
+From 7ce8170a5ec0a60e03752fe2d4b892e0c382f52e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 22:24:55 +0000
+Subject: hwmon: (pmbus) Initialise page count in pmbus_identify()
+
+From: Titus Rwantare <titusr@google.com>
+
+[ Upstream commit 6b6e2e8fd0de3fa7c6f4f8fe6841b01770b2e7bc ]
+
+The `pmbus_identify()` function fails to correctly determine the number
+of supported pages on PMBus devices. This occurs because `info->pages`
+is implicitly zero-initialised, and `pmbus_set_page()` does not perform
+writes to the page register if `info->pages` is not yet initialised.
+Without this patch, `info->pages` is always set to the maximum after
+scanning.
+
+This patch initialises `info->pages` to `PMBUS_PAGES` before the probing
+loop, enabling `pmbus_set_page()` writes to make it out onto the bus
+correctly identifying the number of pages. `PMBUS_PAGES` seemed like a
+reasonable non-zero number because that's the current result of the
+identification process.
+
+Testing was done with a PMBus device in QEMU.
+
+Signed-off-by: Titus Rwantare <titusr@google.com>
+Fixes: 442aba78728e7 ("hwmon: PMBus device driver")
+Link: https://lore.kernel.org/r/20250227222455.2583468-1-titusr@google.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/pmbus/pmbus.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
+index 77cf268e7d2d6..920cd5408141a 100644
+--- a/drivers/hwmon/pmbus/pmbus.c
++++ b/drivers/hwmon/pmbus/pmbus.c
+@@ -103,6 +103,8 @@ static int pmbus_identify(struct i2c_client *client,
+               if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
+                       int page;
++                      info->pages = PMBUS_PAGES;
++
+                       for (page = 1; page < PMBUS_PAGES; page++) {
+                               if (pmbus_set_page(client, page, 0xff) < 0)
+                                       break;
+-- 
+2.39.5
+
diff --git a/queue-6.13/llc-do-not-use-skb_get-before-dev_queue_xmit.patch b/queue-6.13/llc-do-not-use-skb_get-before-dev_queue_xmit.patch
new file mode 100644 (file)
index 0000000..6fc2d56
--- /dev/null
@@ -0,0 +1,166 @@
+From bb1e1913a4f576d58a56b0b09f2b26ed0359e38a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 08:26:42 +0000
+Subject: llc: do not use skb_get() before dev_queue_xmit()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 64e6a754d33d31aa844b3ee66fb93ac84ca1565e ]
+
+syzbot is able to crash hosts [1], using llc and devices
+not supporting IFF_TX_SKB_SHARING.
+
+In this case, e1000 driver calls eth_skb_pad(), while
+the skb is shared.
+
+Simply replace skb_get() by skb_clone() in net/llc/llc_s_ac.c
+
+Note that e1000 driver might have an issue with pktgen,
+because it does not clear IFF_TX_SKB_SHARING, this is an
+orthogonal change.
+
+We need to audit other skb_get() uses in net/llc.
+
+[1]
+
+kernel BUG at net/core/skbuff.c:2178 !
+Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
+CPU: 0 UID: 0 PID: 16371 Comm: syz.2.2764 Not tainted 6.14.0-rc4-syzkaller-00052-gac9c34d1e45a #0
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
+ RIP: 0010:pskb_expand_head+0x6ce/0x1240 net/core/skbuff.c:2178
+Call Trace:
+ <TASK>
+  __skb_pad+0x18a/0x610 net/core/skbuff.c:2466
+  __skb_put_padto include/linux/skbuff.h:3843 [inline]
+  skb_put_padto include/linux/skbuff.h:3862 [inline]
+  eth_skb_pad include/linux/etherdevice.h:656 [inline]
+  e1000_xmit_frame+0x2d99/0x5800 drivers/net/ethernet/intel/e1000/e1000_main.c:3128
+  __netdev_start_xmit include/linux/netdevice.h:5151 [inline]
+  netdev_start_xmit include/linux/netdevice.h:5160 [inline]
+  xmit_one net/core/dev.c:3806 [inline]
+  dev_hard_start_xmit+0x9a/0x7b0 net/core/dev.c:3822
+  sch_direct_xmit+0x1ae/0xc30 net/sched/sch_generic.c:343
+  __dev_xmit_skb net/core/dev.c:4045 [inline]
+  __dev_queue_xmit+0x13d4/0x43e0 net/core/dev.c:4621
+  dev_queue_xmit include/linux/netdevice.h:3313 [inline]
+  llc_sap_action_send_test_c+0x268/0x320 net/llc/llc_s_ac.c:144
+  llc_exec_sap_trans_actions net/llc/llc_sap.c:153 [inline]
+  llc_sap_next_state net/llc/llc_sap.c:182 [inline]
+  llc_sap_state_process+0x239/0x510 net/llc/llc_sap.c:209
+  llc_ui_sendmsg+0xd0d/0x14e0 net/llc/af_llc.c:993
+  sock_sendmsg_nosec net/socket.c:718 [inline]
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+da65c993ae113742a25f@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/67c020c0.050a0220.222324.0011.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/llc/llc_s_ac.c | 49 +++++++++++++++++++++++++---------------------
+ 1 file changed, 27 insertions(+), 22 deletions(-)
+
+diff --git a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c
+index 06fb8e6944b06..7a0cae9a81114 100644
+--- a/net/llc/llc_s_ac.c
++++ b/net/llc/llc_s_ac.c
+@@ -24,7 +24,7 @@
+ #include <net/llc_s_ac.h>
+ #include <net/llc_s_ev.h>
+ #include <net/llc_sap.h>
+-
++#include <net/sock.h>
+ /**
+  *    llc_sap_action_unitdata_ind - forward UI PDU to network layer
+@@ -40,6 +40,26 @@ int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb)
+       return 0;
+ }
++static int llc_prepare_and_xmit(struct sk_buff *skb)
++{
++      struct llc_sap_state_ev *ev = llc_sap_ev(skb);
++      struct sk_buff *nskb;
++      int rc;
++
++      rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
++      if (rc)
++              return rc;
++
++      nskb = skb_clone(skb, GFP_ATOMIC);
++      if (!nskb)
++              return -ENOMEM;
++
++      if (skb->sk)
++              skb_set_owner_w(nskb, skb->sk);
++
++      return dev_queue_xmit(nskb);
++}
++
+ /**
+  *    llc_sap_action_send_ui - sends UI PDU resp to UNITDATA REQ to MAC layer
+  *    @sap: SAP
+@@ -52,17 +72,12 @@ int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb)
+ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
+ {
+       struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+-      int rc;
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
+                           ev->daddr.lsap, LLC_PDU_CMD);
+       llc_pdu_init_as_ui_cmd(skb);
+-      rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
+-      if (likely(!rc)) {
+-              skb_get(skb);
+-              rc = dev_queue_xmit(skb);
+-      }
+-      return rc;
++
++      return llc_prepare_and_xmit(skb);
+ }
+ /**
+@@ -77,17 +92,12 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
+ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
+ {
+       struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+-      int rc;
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U_XID, ev->saddr.lsap,
+                           ev->daddr.lsap, LLC_PDU_CMD);
+       llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
+-      rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
+-      if (likely(!rc)) {
+-              skb_get(skb);
+-              rc = dev_queue_xmit(skb);
+-      }
+-      return rc;
++
++      return llc_prepare_and_xmit(skb);
+ }
+ /**
+@@ -133,17 +143,12 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
+ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
+ {
+       struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+-      int rc;
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
+                           ev->daddr.lsap, LLC_PDU_CMD);
+       llc_pdu_init_as_test_cmd(skb);
+-      rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
+-      if (likely(!rc)) {
+-              skb_get(skb);
+-              rc = dev_queue_xmit(skb);
+-      }
+-      return rc;
++
++      return llc_prepare_and_xmit(skb);
+ }
+ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
+-- 
+2.39.5
+
diff --git a/queue-6.13/mctp-i3c-handle-null-header-address.patch b/queue-6.13/mctp-i3c-handle-null-header-address.patch
new file mode 100644 (file)
index 0000000..7f86703
--- /dev/null
@@ -0,0 +1,41 @@
+From 8bebee00886bbd5f75f50a5b8c171fbb090285f8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 13:59:51 +0800
+Subject: mctp i3c: handle NULL header address
+
+From: Matt Johnston <matt@codeconstruct.com.au>
+
+[ Upstream commit cf7ee25e70c6edfac4553d6b671e8b19db1d9573 ]
+
+daddr can be NULL if there is no neighbour table entry present,
+in that case the tx packet should be dropped.
+
+saddr will usually be set by MCTP core, but check for NULL in case a
+packet is transmitted by a different protocol.
+
+Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
+Fixes: c8755b29b58e ("mctp i3c: MCTP I3C driver")
+Link: https://patch.msgid.link/20250304-mctp-i3c-null-v1-1-4416bbd56540@codeconstruct.com.au
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/mctp/mctp-i3c.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/mctp/mctp-i3c.c b/drivers/net/mctp/mctp-i3c.c
+index d247fe483c588..c1e72253063b5 100644
+--- a/drivers/net/mctp/mctp-i3c.c
++++ b/drivers/net/mctp/mctp-i3c.c
+@@ -507,6 +507,9 @@ static int mctp_i3c_header_create(struct sk_buff *skb, struct net_device *dev,
+ {
+       struct mctp_i3c_internal_hdr *ihdr;
++      if (!daddr || !saddr)
++              return -EINVAL;
++
+       skb_push(skb, sizeof(struct mctp_i3c_internal_hdr));
+       skb_reset_mac_header(skb);
+       ihdr = (void *)skb_mac_header(skb);
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-dsa-mt7530-fix-traffic-flooding-for-mmio-devices.patch b/queue-6.13/net-dsa-mt7530-fix-traffic-flooding-for-mmio-devices.patch
new file mode 100644 (file)
index 0000000..f7e2b9c
--- /dev/null
@@ -0,0 +1,54 @@
+From ae00ca3bc84fbb027443abe4f42ea2ff5bd550a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 09:50:23 +0100
+Subject: net: dsa: mt7530: Fix traffic flooding for MMIO devices
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit ccc2f5a436fbb0ae1fb598932a9b8e48423c1959 ]
+
+On MMIO devices (e.g. MT7988 or EN7581) unicast traffic received on lanX
+port is flooded on all other user ports if the DSA switch is configured
+without VLAN support since PORT_MATRIX in PCR regs contains all user
+ports. Similar to MDIO devices (e.g. MT7530 and MT7531) fix the issue
+defining default VLAN-ID 0 for MT7530 MMIO devices.
+
+Fixes: 110c18bfed414 ("net: dsa: mt7530: introduce driver for MT7988 built-in switch")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Reviewed-by: Chester A. Unal <chester.a.unal@arinc9.com>
+Link: https://patch.msgid.link/20250304-mt7988-flooding-fix-v1-1-905523ae83e9@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
+index 086b8b3d5b40f..b05e38d19b212 100644
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2591,7 +2591,8 @@ mt7531_setup_common(struct dsa_switch *ds)
+       if (ret < 0)
+               return ret;
+-      return 0;
++      /* Setup VLAN ID 0 for VLAN-unaware bridges */
++      return mt7530_setup_vlan0(priv);
+ }
+ static int
+@@ -2687,11 +2688,6 @@ mt7531_setup(struct dsa_switch *ds)
+       if (ret)
+               return ret;
+-      /* Setup VLAN ID 0 for VLAN-unaware bridges */
+-      ret = mt7530_setup_vlan0(priv);
+-      if (ret)
+-              return ret;
+-
+       ds->assisted_learning_on_cpu_port = true;
+       ds->mtu_enforcement_ingress = true;
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ethtool-netlink-allow-null-nlattrs-when-getting-.patch b/queue-6.13/net-ethtool-netlink-allow-null-nlattrs-when-getting-.patch
new file mode 100644 (file)
index 0000000..9a72585
--- /dev/null
@@ -0,0 +1,239 @@
+From f4a6bdc6258e2d7647f29d67c24544dd75d06862 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Mar 2025 15:11:13 +0100
+Subject: net: ethtool: netlink: Allow NULL nlattrs when getting a phy_device
+
+From: Maxime Chevallier <maxime.chevallier@bootlin.com>
+
+[ Upstream commit 637399bf7e77797811adf340090b561a8f9d1213 ]
+
+ethnl_req_get_phydev() is used to lookup a phy_device, in the case an
+ethtool netlink command targets a specific phydev within a netdev's
+topology.
+
+It takes as a parameter a const struct nlattr *header that's used for
+error handling :
+
+       if (!phydev) {
+               NL_SET_ERR_MSG_ATTR(extack, header,
+                                   "no phy matching phyindex");
+               return ERR_PTR(-ENODEV);
+       }
+
+In the notify path after a ->set operation however, there's no request
+attributes available.
+
+The typical callsite for the above function looks like:
+
+       phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_XXX_HEADER],
+                                     info->extack);
+
+So, when tb is NULL (such as in the ethnl notify path), we have a nice
+crash.
+
+It turns out that there's only the PLCA command that is in that case, as
+the other phydev-specific commands don't have a notification.
+
+This commit fixes the crash by passing the cmd index and the nlattr
+array separately, allowing NULL-checking it directly inside the helper.
+
+Fixes: c15e065b46dc ("net: ethtool: Allow passing a phy index for some commands")
+Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
+Reported-by: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
+Link: https://patch.msgid.link/20250301141114.97204-1-maxime.chevallier@bootlin.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ethtool/cabletest.c | 8 ++++----
+ net/ethtool/linkstate.c | 2 +-
+ net/ethtool/netlink.c   | 6 +++---
+ net/ethtool/netlink.h   | 5 +++--
+ net/ethtool/phy.c       | 2 +-
+ net/ethtool/plca.c      | 6 +++---
+ net/ethtool/pse-pd.c    | 4 ++--
+ net/ethtool/stats.c     | 2 +-
+ net/ethtool/strset.c    | 2 +-
+ 9 files changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c
+index f22051f33868a..84096f6b0236e 100644
+--- a/net/ethtool/cabletest.c
++++ b/net/ethtool/cabletest.c
+@@ -72,8 +72,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
+       dev = req_info.dev;
+       rtnl_lock();
+-      phydev = ethnl_req_get_phydev(&req_info,
+-                                    tb[ETHTOOL_A_CABLE_TEST_HEADER],
++      phydev = ethnl_req_get_phydev(&req_info, tb,
++                                    ETHTOOL_A_CABLE_TEST_HEADER,
+                                     info->extack);
+       if (IS_ERR_OR_NULL(phydev)) {
+               ret = -EOPNOTSUPP;
+@@ -339,8 +339,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
+               goto out_dev_put;
+       rtnl_lock();
+-      phydev = ethnl_req_get_phydev(&req_info,
+-                                    tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
++      phydev = ethnl_req_get_phydev(&req_info, tb,
++                                    ETHTOOL_A_CABLE_TEST_TDR_HEADER,
+                                     info->extack);
+       if (IS_ERR_OR_NULL(phydev)) {
+               ret = -EOPNOTSUPP;
+diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c
+index af19e1bed303f..05a5f72c99fab 100644
+--- a/net/ethtool/linkstate.c
++++ b/net/ethtool/linkstate.c
+@@ -103,7 +103,7 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
+       struct phy_device *phydev;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_LINKSTATE_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER,
+                                     info->extack);
+       if (IS_ERR(phydev)) {
+               ret = PTR_ERR(phydev);
+diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
+index 4d18dc29b3043..e233dfc8ca4be 100644
+--- a/net/ethtool/netlink.c
++++ b/net/ethtool/netlink.c
+@@ -210,7 +210,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
+ }
+ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
+-                                      const struct nlattr *header,
++                                      struct nlattr **tb, unsigned int header,
+                                       struct netlink_ext_ack *extack)
+ {
+       struct phy_device *phydev;
+@@ -224,8 +224,8 @@ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
+               return req_info->dev->phydev;
+       phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
+-      if (!phydev) {
+-              NL_SET_ERR_MSG_ATTR(extack, header,
++      if (!phydev && tb) {
++              NL_SET_ERR_MSG_ATTR(extack, tb[header],
+                                   "no phy matching phyindex");
+               return ERR_PTR(-ENODEV);
+       }
+diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
+index 203b08eb6c6f6..5e176938d6d22 100644
+--- a/net/ethtool/netlink.h
++++ b/net/ethtool/netlink.h
+@@ -275,7 +275,8 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
+  * ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
+  *                        if any. Must be called under rntl_lock().
+  * @req_info: The ethnl request to get the phy from.
+- * @header:   The netlink header, used for error reporting.
++ * @tb:               The netlink attributes array, for error reporting.
++ * @header:   The netlink header index, used for error reporting.
+  * @extack:   The netlink extended ACK, for error reporting.
+  *
+  * The caller must hold RTNL, until it's done interacting with the returned
+@@ -289,7 +290,7 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
+  *       is returned.
+  */
+ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
+-                                      const struct nlattr *header,
++                                      struct nlattr **tb, unsigned int header,
+                                       struct netlink_ext_ack *extack);
+ /**
+diff --git a/net/ethtool/phy.c b/net/ethtool/phy.c
+index ed8f690f6bac8..e067cc234419d 100644
+--- a/net/ethtool/phy.c
++++ b/net/ethtool/phy.c
+@@ -125,7 +125,7 @@ static int ethnl_phy_parse_request(struct ethnl_req_info *req_base,
+       struct phy_req_info *req_info = PHY_REQINFO(req_base);
+       struct phy_device *phydev;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PHY_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER,
+                                     extack);
+       if (!phydev)
+               return 0;
+diff --git a/net/ethtool/plca.c b/net/ethtool/plca.c
+index d95d92f173a6d..e1f7820a6158f 100644
+--- a/net/ethtool/plca.c
++++ b/net/ethtool/plca.c
+@@ -62,7 +62,7 @@ static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
+       struct phy_device *phydev;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
+                                     info->extack);
+       // check that the PHY device is available and connected
+       if (IS_ERR_OR_NULL(phydev)) {
+@@ -152,7 +152,7 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
+       bool mod = false;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PLCA_HEADER],
++      phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PLCA_HEADER,
+                                     info->extack);
+       // check that the PHY device is available and connected
+       if (IS_ERR_OR_NULL(phydev))
+@@ -211,7 +211,7 @@ static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
+       struct phy_device *phydev;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
+                                     info->extack);
+       // check that the PHY device is available and connected
+       if (IS_ERR_OR_NULL(phydev)) {
+diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
+index a0705edca22a1..71843de832cca 100644
+--- a/net/ethtool/pse-pd.c
++++ b/net/ethtool/pse-pd.c
+@@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
+       if (ret < 0)
+               return ret;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PSE_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER,
+                                     info->extack);
+       if (IS_ERR(phydev))
+               return -ENODEV;
+@@ -261,7 +261,7 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
+       struct phy_device *phydev;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PSE_HEADER],
++      phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PSE_HEADER,
+                                     info->extack);
+       ret = ethnl_set_pse_validate(phydev, info);
+       if (ret)
+diff --git a/net/ethtool/stats.c b/net/ethtool/stats.c
+index f4d822c225db6..273ae4ff343fe 100644
+--- a/net/ethtool/stats.c
++++ b/net/ethtool/stats.c
+@@ -128,7 +128,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
+       struct phy_device *phydev;
+       int ret;
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_STATS_HEADER],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STATS_HEADER,
+                                     info->extack);
+       if (IS_ERR(phydev))
+               return PTR_ERR(phydev);
+diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
+index b3382b3cf325c..b9400d18f01d5 100644
+--- a/net/ethtool/strset.c
++++ b/net/ethtool/strset.c
+@@ -299,7 +299,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
+               return 0;
+       }
+-      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
++      phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS,
+                                     info->extack);
+       /* phydev can be NULL, check for errors only */
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ethtool-plumb-phy-stats-to-phy-drivers.patch b/queue-6.13/net-ethtool-plumb-phy-stats-to-phy-drivers.patch
new file mode 100644 (file)
index 0000000..7f3bc72
--- /dev/null
@@ -0,0 +1,343 @@
+From 166e1f64e88edd782fdce531e619f4aebdca354f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jan 2025 07:05:12 +0100
+Subject: net: ethtool: plumb PHY stats to PHY drivers
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit b7a2c1fe6b55364e61b4b54b991eb43a47bb1104 ]
+
+Introduce support for standardized PHY statistics reporting in ethtool
+by extending the PHYLIB framework. Add the functions
+phy_ethtool_get_phy_stats() and phy_ethtool_get_link_ext_stats() to
+provide a consistent interface for retrieving PHY-level and
+link-specific statistics. These functions are used within the ethtool
+implementation to avoid direct access to the phy_device structure
+outside of the PHYLIB framework.
+
+A new structure, ethtool_phy_stats, is introduced to standardize PHY
+statistics such as packet counts, byte counts, and error counters.
+Drivers are updated to include callbacks for retrieving PHY and
+link-specific statistics, ensuring values are explicitly set only for
+supported fields, initialized with ETHTOOL_STAT_NOT_SET to avoid
+ambiguity.
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 637399bf7e77 ("net: ethtool: netlink: Allow NULL nlattrs when getting a phy_device")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/phy.c        | 43 ++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/phy_device.c |  2 ++
+ include/linux/ethtool.h      | 23 +++++++++++++++++++
+ include/linux/phy.h          | 36 ++++++++++++++++++++++++++++++
+ include/linux/phylib_stubs.h | 42 +++++++++++++++++++++++++++++++++++
+ net/ethtool/linkstate.c      |  5 +++--
+ net/ethtool/stats.c          | 18 +++++++++++++++
+ 7 files changed, 167 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index 0d20b534122b2..ffd1da04d3ad1 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -615,6 +615,49 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
+ }
+ EXPORT_SYMBOL(phy_ethtool_get_stats);
++/**
++ * __phy_ethtool_get_phy_stats - Retrieve standardized PHY statistics
++ * @phydev: Pointer to the PHY device
++ * @phy_stats: Pointer to ethtool_eth_phy_stats structure
++ * @phydev_stats: Pointer to ethtool_phy_stats structure
++ *
++ * Fetches PHY statistics using a kernel-defined interface for consistent
++ * diagnostics. Unlike phy_ethtool_get_stats(), which allows custom stats,
++ * this function enforces a standardized format for better interoperability.
++ */
++void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
++                               struct ethtool_eth_phy_stats *phy_stats,
++                               struct ethtool_phy_stats *phydev_stats)
++{
++      if (!phydev->drv || !phydev->drv->get_phy_stats)
++              return;
++
++      mutex_lock(&phydev->lock);
++      phydev->drv->get_phy_stats(phydev, phy_stats, phydev_stats);
++      mutex_unlock(&phydev->lock);
++}
++
++/**
++ * __phy_ethtool_get_link_ext_stats - Retrieve extended link statistics for a PHY
++ * @phydev: Pointer to the PHY device
++ * @link_stats: Pointer to the structure to store extended link statistics
++ *
++ * Populates the ethtool_link_ext_stats structure with link down event counts
++ * and additional driver-specific link statistics, if available.
++ */
++void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
++                                    struct ethtool_link_ext_stats *link_stats)
++{
++      link_stats->link_down_events = READ_ONCE(phydev->link_down_events);
++
++      if (!phydev->drv || !phydev->drv->get_link_stats)
++              return;
++
++      mutex_lock(&phydev->lock);
++      phydev->drv->get_link_stats(phydev, link_stats);
++      mutex_unlock(&phydev->lock);
++}
++
+ /**
+  * phy_ethtool_get_plca_cfg - Get PLCA RS configuration
+  * @phydev: the phy_device struct
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index b26bb33cd1d48..5f1ad0c7fb534 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -3773,6 +3773,8 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
+ static const struct phylib_stubs __phylib_stubs = {
+       .hwtstamp_get = __phy_hwtstamp_get,
+       .hwtstamp_set = __phy_hwtstamp_set,
++      .get_phy_stats = __phy_ethtool_get_phy_stats,
++      .get_link_ext_stats = __phy_ethtool_get_link_ext_stats,
+ };
+ static void phylib_register_stubs(void)
+diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
+index b8b935b526033..b0ed740ca749b 100644
+--- a/include/linux/ethtool.h
++++ b/include/linux/ethtool.h
+@@ -412,6 +412,29 @@ struct ethtool_eth_phy_stats {
+       );
+ };
++/**
++ * struct ethtool_phy_stats - PHY-level statistics counters
++ * @rx_packets: Total successfully received frames
++ * @rx_bytes: Total successfully received bytes
++ * @rx_errors: Total received frames with errors (e.g., CRC errors)
++ * @tx_packets: Total successfully transmitted frames
++ * @tx_bytes: Total successfully transmitted bytes
++ * @tx_errors: Total transmitted frames with errors
++ *
++ * This structure provides a standardized interface for reporting
++ * PHY-level statistics counters. It is designed to expose statistics
++ * commonly provided by PHYs but not explicitly defined in the IEEE
++ * 802.3 standard.
++ */
++struct ethtool_phy_stats {
++      u64 rx_packets;
++      u64 rx_bytes;
++      u64 rx_errors;
++      u64 tx_packets;
++      u64 tx_bytes;
++      u64 tx_errors;
++};
++
+ /* Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*), not otherwise exposed
+  * via a more targeted API.
+  */
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index 563c462056857..bed2b81f8fb3f 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1090,6 +1090,35 @@ struct phy_driver {
+       int (*cable_test_get_status)(struct phy_device *dev, bool *finished);
+       /* Get statistics from the PHY using ethtool */
++      /**
++       * @get_phy_stats: Retrieve PHY statistics.
++       * @dev: The PHY device for which the statistics are retrieved.
++       * @eth_stats: structure where Ethernet PHY stats will be stored.
++       * @stats: structure where additional PHY-specific stats will be stored.
++       *
++       * Retrieves the supported PHY statistics and populates the provided
++       * structures. The input structures are pre-initialized with
++       * `ETHTOOL_STAT_NOT_SET`, and the driver must only modify members
++       * corresponding to supported statistics. Unmodified members will remain
++       * set to `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
++       */
++      void (*get_phy_stats)(struct phy_device *dev,
++                            struct ethtool_eth_phy_stats *eth_stats,
++                            struct ethtool_phy_stats *stats);
++
++      /**
++       * @get_link_stats: Retrieve link statistics.
++       * @dev: The PHY device for which the statistics are retrieved.
++       * @link_stats: structure where link-specific stats will be stored.
++       *
++       * Retrieves link-related statistics for the given PHY device. The input
++       * structure is pre-initialized with `ETHTOOL_STAT_NOT_SET`, and the
++       * driver must only modify members corresponding to supported
++       * statistics. Unmodified members will remain set to
++       * `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
++       */
++      void (*get_link_stats)(struct phy_device *dev,
++                             struct ethtool_link_ext_stats *link_stats);
+       /** @get_sset_count: Number of statistic counters */
+       int (*get_sset_count)(struct phy_device *dev);
+       /** @get_strings: Names of the statistic counters */
+@@ -2065,6 +2094,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
+ int phy_ethtool_get_sset_count(struct phy_device *phydev);
+ int phy_ethtool_get_stats(struct phy_device *phydev,
+                         struct ethtool_stats *stats, u64 *data);
++
++void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
++                       struct ethtool_eth_phy_stats *phy_stats,
++                       struct ethtool_phy_stats *phydev_stats);
++void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
++                                    struct ethtool_link_ext_stats *link_stats);
++
+ int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
+                            struct phy_plca_cfg *plca_cfg);
+ int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
+diff --git a/include/linux/phylib_stubs.h b/include/linux/phylib_stubs.h
+index 1279f48c8a707..9d2d6090c86d1 100644
+--- a/include/linux/phylib_stubs.h
++++ b/include/linux/phylib_stubs.h
+@@ -5,6 +5,9 @@
+ #include <linux/rtnetlink.h>
++struct ethtool_eth_phy_stats;
++struct ethtool_link_ext_stats;
++struct ethtool_phy_stats;
+ struct kernel_hwtstamp_config;
+ struct netlink_ext_ack;
+ struct phy_device;
+@@ -19,6 +22,11 @@ struct phylib_stubs {
+       int (*hwtstamp_set)(struct phy_device *phydev,
+                           struct kernel_hwtstamp_config *config,
+                           struct netlink_ext_ack *extack);
++      void (*get_phy_stats)(struct phy_device *phydev,
++                            struct ethtool_eth_phy_stats *phy_stats,
++                            struct ethtool_phy_stats *phydev_stats);
++      void (*get_link_ext_stats)(struct phy_device *phydev,
++                                 struct ethtool_link_ext_stats *link_stats);
+ };
+ static inline int phy_hwtstamp_get(struct phy_device *phydev,
+@@ -50,6 +58,29 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
+       return phylib_stubs->hwtstamp_set(phydev, config, extack);
+ }
++static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
++                                      struct ethtool_eth_phy_stats *phy_stats,
++                                      struct ethtool_phy_stats *phydev_stats)
++{
++      ASSERT_RTNL();
++
++      if (!phylib_stubs)
++              return;
++
++      phylib_stubs->get_phy_stats(phydev, phy_stats, phydev_stats);
++}
++
++static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
++                                  struct ethtool_link_ext_stats *link_stats)
++{
++      ASSERT_RTNL();
++
++      if (!phylib_stubs)
++              return;
++
++      phylib_stubs->get_link_ext_stats(phydev, link_stats);
++}
++
+ #else
+ static inline int phy_hwtstamp_get(struct phy_device *phydev,
+@@ -65,4 +96,15 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
+       return -EOPNOTSUPP;
+ }
++static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
++                                      struct ethtool_eth_phy_stats *phy_stats,
++                                      struct ethtool_phy_stats *phydev_stats)
++{
++}
++
++static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
++                                  struct ethtool_link_ext_stats *link_stats)
++{
++}
++
+ #endif
+diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c
+index 459cfea7652d4..af19e1bed303f 100644
+--- a/net/ethtool/linkstate.c
++++ b/net/ethtool/linkstate.c
+@@ -3,6 +3,7 @@
+ #include "netlink.h"
+ #include "common.h"
+ #include <linux/phy.h>
++#include <linux/phylib_stubs.h>
+ struct linkstate_req_info {
+       struct ethnl_req_info           base;
+@@ -135,8 +136,8 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
+       if (req_base->flags & ETHTOOL_FLAG_STATS) {
+               if (phydev)
+-                      data->link_stats.link_down_events =
+-                              READ_ONCE(phydev->link_down_events);
++                      phy_ethtool_get_link_ext_stats(phydev,
++                                                     &data->link_stats);
+               if (dev->ethtool_ops->get_link_ext_stats)
+                       dev->ethtool_ops->get_link_ext_stats(dev,
+diff --git a/net/ethtool/stats.c b/net/ethtool/stats.c
+index 912f0c4fff2fb..f4d822c225db6 100644
+--- a/net/ethtool/stats.c
++++ b/net/ethtool/stats.c
+@@ -1,5 +1,8 @@
+ // SPDX-License-Identifier: GPL-2.0-only
++#include <linux/phy.h>
++#include <linux/phylib_stubs.h>
++
+ #include "netlink.h"
+ #include "common.h"
+ #include "bitset.h"
+@@ -20,6 +23,7 @@ struct stats_reply_data {
+               struct ethtool_eth_mac_stats    mac_stats;
+               struct ethtool_eth_ctrl_stats   ctrl_stats;
+               struct ethtool_rmon_stats       rmon_stats;
++              struct ethtool_phy_stats        phydev_stats;
+       );
+       const struct ethtool_rmon_hist_range    *rmon_ranges;
+ };
+@@ -120,8 +124,15 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
+       struct stats_reply_data *data = STATS_REPDATA(reply_base);
+       enum ethtool_mac_stats_src src = req_info->src;
+       struct net_device *dev = reply_base->dev;
++      struct nlattr **tb = info->attrs;
++      struct phy_device *phydev;
+       int ret;
++      phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_STATS_HEADER],
++                                    info->extack);
++      if (IS_ERR(phydev))
++              return PTR_ERR(phydev);
++
+       ret = ethnl_ops_begin(dev);
+       if (ret < 0)
+               return ret;
+@@ -145,6 +156,13 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
+       data->ctrl_stats.src = src;
+       data->rmon_stats.src = src;
++      if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
++          src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) {
++              if (phydev)
++                      phy_ethtool_get_phy_stats(phydev, &data->phy_stats,
++                                                &data->phydev_stats);
++      }
++
+       if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
+           dev->ethtool_ops->get_eth_phy_stats)
+               dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-gso-fix-ownership-in-__udp_gso_segment.patch b/queue-6.13/net-gso-fix-ownership-in-__udp_gso_segment.patch
new file mode 100644 (file)
index 0000000..9d0161a
--- /dev/null
@@ -0,0 +1,73 @@
+From c0e2c29cabd13663a2362314e4a1946bba87c4f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 18:13:42 +0100
+Subject: net: gso: fix ownership in __udp_gso_segment
+
+From: Antoine Tenart <atenart@kernel.org>
+
+[ Upstream commit ee01b2f2d7d0010787c2343463965bbc283a497f ]
+
+In __udp_gso_segment the skb destructor is removed before segmenting the
+skb but the socket reference is kept as-is. This is an issue if the
+original skb is later orphaned as we can hit the following bug:
+
+  kernel BUG at ./include/linux/skbuff.h:3312!  (skb_orphan)
+  RIP: 0010:ip_rcv_core+0x8b2/0xca0
+  Call Trace:
+   ip_rcv+0xab/0x6e0
+   __netif_receive_skb_one_core+0x168/0x1b0
+   process_backlog+0x384/0x1100
+   __napi_poll.constprop.0+0xa1/0x370
+   net_rx_action+0x925/0xe50
+
+The above can happen following a sequence of events when using
+OpenVSwitch, when an OVS_ACTION_ATTR_USERSPACE action precedes an
+OVS_ACTION_ATTR_OUTPUT action:
+
+1. OVS_ACTION_ATTR_USERSPACE is handled (in do_execute_actions): the skb
+   goes through queue_gso_packets and then __udp_gso_segment, where its
+   destructor is removed.
+2. The segments' data are copied and sent to userspace.
+3. OVS_ACTION_ATTR_OUTPUT is handled (in do_execute_actions) and the
+   same original skb is sent to its path.
+4. If it later hits skb_orphan, we hit the bug.
+
+Fix this by also removing the reference to the socket in
+__udp_gso_segment.
+
+Fixes: ad405857b174 ("udp: better wmem accounting on gso")
+Signed-off-by: Antoine Tenart <atenart@kernel.org>
+Link: https://patch.msgid.link/20250226171352.258045-1-atenart@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/udp_offload.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index a5be6e4ed326f..ecfca59f31f13 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -321,13 +321,17 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
+       /* clear destructor to avoid skb_segment assigning it to tail */
+       copy_dtor = gso_skb->destructor == sock_wfree;
+-      if (copy_dtor)
++      if (copy_dtor) {
+               gso_skb->destructor = NULL;
++              gso_skb->sk = NULL;
++      }
+       segs = skb_segment(gso_skb, features);
+       if (IS_ERR_OR_NULL(segs)) {
+-              if (copy_dtor)
++              if (copy_dtor) {
+                       gso_skb->destructor = sock_wfree;
++                      gso_skb->sk = sk;
++              }
+               return segs;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-hns3-make-sure-ptp-clock-is-unregister-and-freed.patch b/queue-6.13/net-hns3-make-sure-ptp-clock-is-unregister-and-freed.patch
new file mode 100644 (file)
index 0000000..fbe95fc
--- /dev/null
@@ -0,0 +1,42 @@
+From 58a6b1734fd69417408b60bf345206563a357309 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 18:52:58 +0800
+Subject: net: hns3: make sure ptp clock is unregister and freed if
+ hclge_ptp_get_cycle returns an error
+
+From: Peiyang Wang <wangpeiyang1@huawei.com>
+
+[ Upstream commit b7365eab39831487a84e63a9638209b68dc54008 ]
+
+During the initialization of ptp, hclge_ptp_get_cycle might return an error
+and returned directly without unregister clock and free it. To avoid that,
+call hclge_ptp_destroy_clock to unregist and free clock if
+hclge_ptp_get_cycle failed.
+
+Fixes: 8373cd38a888 ("net: hns3: change the method of obtaining default ptp cycle")
+Signed-off-by: Peiyang Wang <wangpeiyang1@huawei.com>
+Signed-off-by: Jijie Shao <shaojijie@huawei.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250228105258.1243461-1-shaojijie@huawei.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
+index bab16c2191b2f..181af419b878d 100644
+--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
+@@ -483,7 +483,7 @@ int hclge_ptp_init(struct hclge_dev *hdev)
+               ret = hclge_ptp_get_cycle(hdev);
+               if (ret)
+-                      return ret;
++                      goto out;
+       }
+       ret = hclge_ptp_int_en(hdev, true);
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ipa-enable-checksum-for-ipa_endpoint_ap_modem_-r.patch b/queue-6.13/net-ipa-enable-checksum-for-ipa_endpoint_ap_modem_-r.patch
new file mode 100644 (file)
index 0000000..4146608
--- /dev/null
@@ -0,0 +1,46 @@
+From 6c7b68871205e53034f0aba85aafee3fda86d05c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 11:33:42 +0100
+Subject: net: ipa: Enable checksum for IPA_ENDPOINT_AP_MODEM_{RX,TX} for v4.7
+
+From: Luca Weiss <luca.weiss@fairphone.com>
+
+[ Upstream commit 934e69669e32eb653234898424ae007bae2f636e ]
+
+Enable the checksum option for these two endpoints in order to allow
+mobile data to actually work. Without this, no packets seem to make it
+through the IPA.
+
+Fixes: b310de784bac ("net: ipa: add IPA v4.7 support")
+Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
+Reviewed-by: Alex Elder <elder@riscstar.com>
+Link: https://patch.msgid.link/20250227-ipa-v4-7-fixes-v1-3-a88dd8249d8a@fairphone.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ipa/data/ipa_data-v4.7.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ipa/data/ipa_data-v4.7.c b/drivers/net/ipa/data/ipa_data-v4.7.c
+index e63dcf8d45567..41f212209993f 100644
+--- a/drivers/net/ipa/data/ipa_data-v4.7.c
++++ b/drivers/net/ipa/data/ipa_data-v4.7.c
+@@ -104,6 +104,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+                       .filter_support = true,
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
++                              .checksum       = true,
+                               .qmap           = true,
+                               .status_enable  = true,
+                               .tx = {
+@@ -127,6 +128,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+               .endpoint = {
+                       .config = {
+                               .resource_group = IPA_RSRC_GROUP_DST_UL_DL,
++                              .checksum       = true,
+                               .qmap           = true,
+                               .aggregation    = true,
+                               .rx = {
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ipa-fix-qsb-data-for-v4.7.patch b/queue-6.13/net-ipa-fix-qsb-data-for-v4.7.patch
new file mode 100644 (file)
index 0000000..19fe49c
--- /dev/null
@@ -0,0 +1,40 @@
+From 05b97fb2353433d34c143aa97ba0247fbd46f971 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 11:33:41 +0100
+Subject: net: ipa: Fix QSB data for v4.7
+
+From: Luca Weiss <luca.weiss@fairphone.com>
+
+[ Upstream commit 6a2843aaf551d87beb92d774f7d5b8ae007fe774 ]
+
+As per downstream reference, max_writes should be 12 and max_reads
+should be 13.
+
+Fixes: b310de784bac ("net: ipa: add IPA v4.7 support")
+Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
+Reviewed-by: Alex Elder <elder@riscstar.com>
+Link: https://patch.msgid.link/20250227-ipa-v4-7-fixes-v1-2-a88dd8249d8a@fairphone.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ipa/data/ipa_data-v4.7.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ipa/data/ipa_data-v4.7.c b/drivers/net/ipa/data/ipa_data-v4.7.c
+index 7e315779e6648..e63dcf8d45567 100644
+--- a/drivers/net/ipa/data/ipa_data-v4.7.c
++++ b/drivers/net/ipa/data/ipa_data-v4.7.c
+@@ -38,8 +38,8 @@ enum ipa_rsrc_group_id {
+ /* QSB configuration data for an SoC having IPA v4.7 */
+ static const struct ipa_qsb_data ipa_qsb_data[] = {
+       [IPA_QSB_MASTER_DDR] = {
+-              .max_writes             = 8,
+-              .max_reads              = 0,    /* no limit (hardware max) */
++              .max_writes             = 12,
++              .max_reads              = 13,
+               .max_reads_beats        = 120,
+       },
+ };
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ipa-fix-v4.7-resource-group-names.patch b/queue-6.13/net-ipa-fix-v4.7-resource-group-names.patch
new file mode 100644 (file)
index 0000000..af3224e
--- /dev/null
@@ -0,0 +1,76 @@
+From 8447f8402e8a2fa3b97a9390b742b970ddd1809b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 11:33:40 +0100
+Subject: net: ipa: Fix v4.7 resource group names
+
+From: Luca Weiss <luca.weiss@fairphone.com>
+
+[ Upstream commit 5eb3dc1396aa7e315486b24df80df782912334b7 ]
+
+In the downstream IPA driver there's only one group defined for source
+and destination, and the destination group doesn't have a _DPL suffix.
+
+Fixes: b310de784bac ("net: ipa: add IPA v4.7 support")
+Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
+Reviewed-by: Alex Elder <elder@riscstar.com>
+Link: https://patch.msgid.link/20250227-ipa-v4-7-fixes-v1-1-a88dd8249d8a@fairphone.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ipa/data/ipa_data-v4.7.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ipa/data/ipa_data-v4.7.c b/drivers/net/ipa/data/ipa_data-v4.7.c
+index c8c23d9be961b..7e315779e6648 100644
+--- a/drivers/net/ipa/data/ipa_data-v4.7.c
++++ b/drivers/net/ipa/data/ipa_data-v4.7.c
+@@ -28,12 +28,10 @@ enum ipa_resource_type {
+ enum ipa_rsrc_group_id {
+       /* Source resource group identifiers */
+       IPA_RSRC_GROUP_SRC_UL_DL                        = 0,
+-      IPA_RSRC_GROUP_SRC_UC_RX_Q,
+       IPA_RSRC_GROUP_SRC_COUNT,       /* Last in set; not a source group */
+       /* Destination resource group identifiers */
+-      IPA_RSRC_GROUP_DST_UL_DL_DPL                    = 0,
+-      IPA_RSRC_GROUP_DST_UNUSED_1,
++      IPA_RSRC_GROUP_DST_UL_DL                        = 0,
+       IPA_RSRC_GROUP_DST_COUNT,       /* Last; not a destination group */
+ };
+@@ -81,7 +79,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+               },
+               .endpoint = {
+                       .config = {
+-                              .resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
++                              .resource_group = IPA_RSRC_GROUP_DST_UL_DL,
+                               .aggregation    = true,
+                               .status_enable  = true,
+                               .rx = {
+@@ -128,7 +126,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+               },
+               .endpoint = {
+                       .config = {
+-                              .resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
++                              .resource_group = IPA_RSRC_GROUP_DST_UL_DL,
+                               .qmap           = true,
+                               .aggregation    = true,
+                               .rx = {
+@@ -197,12 +195,12 @@ static const struct ipa_resource ipa_resource_src[] = {
+ /* Destination resource configuration data for an SoC having IPA v4.7 */
+ static const struct ipa_resource ipa_resource_dst[] = {
+       [IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
+-              .limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
++              .limits[IPA_RSRC_GROUP_DST_UL_DL] = {
+                       .min = 7,       .max = 7,
+               },
+       },
+       [IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
+-              .limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
++              .limits[IPA_RSRC_GROUP_DST_UL_DL] = {
+                       .min = 2,       .max = 2,
+               },
+       },
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ipv6-fix-dst-ref-loop-in-ila-lwtunnel.patch b/queue-6.13/net-ipv6-fix-dst-ref-loop-in-ila-lwtunnel.patch
new file mode 100644 (file)
index 0000000..fdec224
--- /dev/null
@@ -0,0 +1,41 @@
+From 6067ab0f22c3025eed4d2374fbf04378385720df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 19:10:39 +0100
+Subject: net: ipv6: fix dst ref loop in ila lwtunnel
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 0e7633d7b95b67f1758aea19f8e85621c5f506a3 ]
+
+This patch follows commit 92191dd10730 ("net: ipv6: fix dst ref loops in
+rpl, seg6 and ioam6 lwtunnels") and, on a second thought, the same patch
+is also needed for ila (even though the config that triggered the issue
+was pathological, but still, we don't want that to happen).
+
+Fixes: 79ff2fc31e0f ("ila: Cache a route to translated address")
+Cc: Tom Herbert <tom@herbertland.com>
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Link: https://patch.msgid.link/20250304181039.35951-1-justin.iurman@uliege.be
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ila/ila_lwt.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
+index ff7e734e335b0..ac4bcc623603a 100644
+--- a/net/ipv6/ila/ila_lwt.c
++++ b/net/ipv6/ila/ila_lwt.c
+@@ -88,7 +88,8 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+                       goto drop;
+               }
+-              if (ilwt->connected) {
++              /* cache only if we don't create a dst reference loop */
++              if (ilwt->connected && orig_dst->lwtstate != dst->lwtstate) {
+                       local_bh_disable();
+                       dst_cache_set_ip6(&ilwt->dst_cache, dst, &fl6.saddr);
+                       local_bh_enable();
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-ipv6-fix-missing-dst-ref-drop-in-ila-lwtunnel.patch b/queue-6.13/net-ipv6-fix-missing-dst-ref-drop-in-ila-lwtunnel.patch
new file mode 100644 (file)
index 0000000..08f06da
--- /dev/null
@@ -0,0 +1,37 @@
+From 9cbc296718bc79af937ad53545dbf61182bf00ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 09:16:55 +0100
+Subject: net: ipv6: fix missing dst ref drop in ila lwtunnel
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 5da15a9c11c1c47ef573e6805b60a7d8a1687a2a ]
+
+Add missing skb_dst_drop() to drop reference to the old dst before
+adding the new dst to the skb.
+
+Fixes: 79ff2fc31e0f ("ila: Cache a route to translated address")
+Cc: Tom Herbert <tom@herbertland.com>
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Link: https://patch.msgid.link/20250305081655.19032-1-justin.iurman@uliege.be
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ila/ila_lwt.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
+index ac4bcc623603a..7d574f5132e2f 100644
+--- a/net/ipv6/ila/ila_lwt.c
++++ b/net/ipv6/ila/ila_lwt.c
+@@ -96,6 +96,7 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+               }
+       }
++      skb_dst_drop(skb);
+       skb_dst_set(skb, dst);
+       return dst_output(net, sk, skb);
+-- 
+2.39.5
+
diff --git a/queue-6.13/net-timestamp-support-tcp-gso-case-for-a-few-missing.patch b/queue-6.13/net-timestamp-support-tcp-gso-case-for-a-few-missing.patch
new file mode 100644 (file)
index 0000000..dbec058
--- /dev/null
@@ -0,0 +1,73 @@
+From 69681afbdb409e0684ec3c2a38a5a0e787a9025f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 08:44:29 +0800
+Subject: net-timestamp: support TCP GSO case for a few missing flags
+
+From: Jason Xing <kerneljasonxing@gmail.com>
+
+[ Upstream commit 3c9231ea6497dfc50ac0ef69fff484da27d0df66 ]
+
+When I read through the TSO codes, I found out that we probably
+miss initializing the tx_flags of last seg when TSO is turned
+off, which means at the following points no more timestamp
+(for this last one) will be generated. There are three flags
+to be handled in this patch:
+1. SKBTX_HW_TSTAMP
+2. SKBTX_BPF
+3. SKBTX_SCHED_TSTAMP
+Note that SKBTX_BPF[1] was added in 6.14.0-rc2 by commit
+6b98ec7e882af ("bpf: Add BPF_SOCK_OPS_TSTAMP_SCHED_CB callback")
+and only belongs to net-next branch material for now. The common
+issue of the above three flags can be fixed by this single patch.
+
+This patch initializes the tx_flags to SKBTX_ANY_TSTAMP like what
+the UDP GSO does to make the newly segmented last skb inherit the
+tx_flags so that requested timestamp will be generated in each
+certain layer, or else that last one has zero value of tx_flags
+which leads to no timestamp at all.
+
+Fixes: 4ed2d765dfacc ("net-timestamp: TCP timestamping")
+Signed-off-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_offload.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
+index 2308665b51c53..2dfac79dc78b8 100644
+--- a/net/ipv4/tcp_offload.c
++++ b/net/ipv4/tcp_offload.c
+@@ -13,12 +13,15 @@
+ #include <net/tcp.h>
+ #include <net/protocol.h>
+-static void tcp_gso_tstamp(struct sk_buff *skb, unsigned int ts_seq,
++static void tcp_gso_tstamp(struct sk_buff *skb, struct sk_buff *gso_skb,
+                          unsigned int seq, unsigned int mss)
+ {
++      u32 flags = skb_shinfo(gso_skb)->tx_flags & SKBTX_ANY_TSTAMP;
++      u32 ts_seq = skb_shinfo(gso_skb)->tskey;
++
+       while (skb) {
+               if (before(ts_seq, seq + mss)) {
+-                      skb_shinfo(skb)->tx_flags |= SKBTX_SW_TSTAMP;
++                      skb_shinfo(skb)->tx_flags |= flags;
+                       skb_shinfo(skb)->tskey = ts_seq;
+                       return;
+               }
+@@ -193,8 +196,8 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
+       th = tcp_hdr(skb);
+       seq = ntohl(th->seq);
+-      if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_SW_TSTAMP))
+-              tcp_gso_tstamp(segs, skb_shinfo(gso_skb)->tskey, seq, mss);
++      if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_ANY_TSTAMP))
++              tcp_gso_tstamp(segs, gso_skb, seq, mss);
+       newcheck = ~csum_fold(csum_add(csum_unfold(th->check), delta));
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvme-ioctl-fix-leaked-requests-on-mapping-error.patch b/queue-6.13/nvme-ioctl-fix-leaked-requests-on-mapping-error.patch
new file mode 100644 (file)
index 0000000..f8190c4
--- /dev/null
@@ -0,0 +1,57 @@
+From dadd055d5a61fc1f15e93db63af88201ea49af8c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 17:13:30 -0800
+Subject: nvme-ioctl: fix leaked requests on mapping error
+
+From: Keith Busch <kbusch@kernel.org>
+
+[ Upstream commit 00817f0f1c45b007965f5676b9a2013bb39c7228 ]
+
+All the callers assume nvme_map_user_request() frees the request on a
+failure. This wasn't happening on invalid metadata or io_uring command
+flags, so we've been leaking those requests.
+
+Fixes: 23fd22e55b767b ("nvme: wire up fixed buffer support for nvme passthrough")
+Fixes: 7c2fd76048e95d ("nvme: fix metadata handling in nvme-passthrough")
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/ioctl.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
+index b1b46c2713e1c..24e2c702da7a2 100644
+--- a/drivers/nvme/host/ioctl.c
++++ b/drivers/nvme/host/ioctl.c
+@@ -128,8 +128,10 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
+       if (!nvme_ctrl_sgl_supported(ctrl))
+               dev_warn_once(ctrl->device, "using unchecked data buffer\n");
+       if (has_metadata) {
+-              if (!supports_metadata)
+-                      return -EINVAL;
++              if (!supports_metadata) {
++                      ret = -EINVAL;
++                      goto out;
++              }
+               if (!nvme_ctrl_meta_sgl_supported(ctrl))
+                       dev_warn_once(ctrl->device,
+                                     "using unchecked metadata buffer\n");
+@@ -139,8 +141,10 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
+               struct iov_iter iter;
+               /* fixedbufs is only for non-vectored io */
+-              if (WARN_ON_ONCE(flags & NVME_IOCTL_VEC))
+-                      return -EINVAL;
++              if (WARN_ON_ONCE(flags & NVME_IOCTL_VEC)) {
++                      ret = -EINVAL;
++                      goto out;
++              }
+               ret = io_uring_cmd_import_fixed(ubuffer, bufflen,
+                               rq_data_dir(req), &iter, ioucmd);
+               if (ret < 0)
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvme-tcp-add-basic-support-for-the-c2htermreq-pdu.patch b/queue-6.13/nvme-tcp-add-basic-support-for-the-c2htermreq-pdu.patch
new file mode 100644 (file)
index 0000000..308c1ef
--- /dev/null
@@ -0,0 +1,104 @@
+From e3316b9433ce0459e640d6127e16b3c7f89c919b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 17:08:27 +0100
+Subject: nvme-tcp: add basic support for the C2HTermReq PDU
+
+From: Maurizio Lombardi <mlombard@redhat.com>
+
+[ Upstream commit 84e009042d0f3dfe91bec60bcd208ee3f866cbcd ]
+
+Previously, the NVMe/TCP host driver did not handle the C2HTermReq PDU,
+instead printing "unsupported pdu type (3)" when received. This patch adds
+support for processing the C2HTermReq PDU, allowing the driver
+to print the Fatal Error Status field.
+
+Example of output:
+nvme nvme4: Received C2HTermReq (FES = Invalid PDU Header Field)
+
+Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Stable-dep-of: ad95bab0cd28 ("nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/tcp.c  | 43 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/nvme-tcp.h |  2 ++
+ 2 files changed, 45 insertions(+)
+
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index d7c193028e7c3..8a9131c95a3da 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -763,6 +763,40 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
+       return 0;
+ }
++static void nvme_tcp_handle_c2h_term(struct nvme_tcp_queue *queue,
++              struct nvme_tcp_term_pdu *pdu)
++{
++      u16 fes;
++      const char *msg;
++      u32 plen = le32_to_cpu(pdu->hdr.plen);
++
++      static const char * const msg_table[] = {
++              [NVME_TCP_FES_INVALID_PDU_HDR] = "Invalid PDU Header Field",
++              [NVME_TCP_FES_PDU_SEQ_ERR] = "PDU Sequence Error",
++              [NVME_TCP_FES_HDR_DIGEST_ERR] = "Header Digest Error",
++              [NVME_TCP_FES_DATA_OUT_OF_RANGE] = "Data Transfer Out Of Range",
++              [NVME_TCP_FES_R2T_LIMIT_EXCEEDED] = "R2T Limit Exceeded",
++              [NVME_TCP_FES_UNSUPPORTED_PARAM] = "Unsupported Parameter",
++      };
++
++      if (plen < NVME_TCP_MIN_C2HTERM_PLEN ||
++          plen > NVME_TCP_MAX_C2HTERM_PLEN) {
++              dev_err(queue->ctrl->ctrl.device,
++                      "Received a malformed C2HTermReq PDU (plen = %u)\n",
++                      plen);
++              return;
++      }
++
++      fes = le16_to_cpu(pdu->fes);
++      if (fes && fes < ARRAY_SIZE(msg_table))
++              msg = msg_table[fes];
++      else
++              msg = "Unknown";
++
++      dev_err(queue->ctrl->ctrl.device,
++              "Received C2HTermReq (FES = %s)\n", msg);
++}
++
+ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
+               unsigned int *offset, size_t *len)
+ {
+@@ -784,6 +818,15 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
+               return 0;
+       hdr = queue->pdu;
++      if (unlikely(hdr->type == nvme_tcp_c2h_term)) {
++              /*
++               * C2HTermReq never includes Header or Data digests.
++               * Skip the checks.
++               */
++              nvme_tcp_handle_c2h_term(queue, (void *)queue->pdu);
++              return -EINVAL;
++      }
++
+       if (queue->hdr_digest) {
+               ret = nvme_tcp_verify_hdgst(queue, queue->pdu, hdr->hlen);
+               if (unlikely(ret))
+diff --git a/include/linux/nvme-tcp.h b/include/linux/nvme-tcp.h
+index e07e8978d691b..e435250fcb4d0 100644
+--- a/include/linux/nvme-tcp.h
++++ b/include/linux/nvme-tcp.h
+@@ -13,6 +13,8 @@
+ #define NVME_TCP_ADMIN_CCSZ   SZ_8K
+ #define NVME_TCP_DIGEST_LENGTH        4
+ #define NVME_TCP_MIN_MAXH2CDATA 4096
++#define NVME_TCP_MIN_C2HTERM_PLEN     24
++#define NVME_TCP_MAX_C2HTERM_PLEN     152
+ enum nvme_tcp_pfv {
+       NVME_TCP_PFV_1_0 = 0x0,
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvme-tcp-fix-potential-memory-corruption-in-nvme_tcp.patch b/queue-6.13/nvme-tcp-fix-potential-memory-corruption-in-nvme_tcp.patch
new file mode 100644 (file)
index 0000000..588548a
--- /dev/null
@@ -0,0 +1,87 @@
+From f1777e91068605db1ab0d3878ece353ab3f68d95 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 14:42:18 +0100
+Subject: nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()
+
+From: Maurizio Lombardi <mlombard@redhat.com>
+
+[ Upstream commit ad95bab0cd28ed77c2c0d0b6e76e03e031391064 ]
+
+nvme_tcp_recv_pdu() doesn't check the validity of the header length.
+When header digests are enabled, a target might send a packet with an
+invalid header length (e.g. 255), causing nvme_tcp_verify_hdgst()
+to access memory outside the allocated area and cause memory corruptions
+by overwriting it with the calculated digest.
+
+Fix this by rejecting packets with an unexpected header length.
+
+Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
+Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/tcp.c | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index 8a9131c95a3da..ade7f1af33d80 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -217,6 +217,19 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
+       return queue - queue->ctrl->queues;
+ }
++static inline bool nvme_tcp_recv_pdu_supported(enum nvme_tcp_pdu_type type)
++{
++      switch (type) {
++      case nvme_tcp_c2h_term:
++      case nvme_tcp_c2h_data:
++      case nvme_tcp_r2t:
++      case nvme_tcp_rsp:
++              return true;
++      default:
++              return false;
++      }
++}
++
+ /*
+  * Check if the queue is TLS encrypted
+  */
+@@ -818,6 +831,16 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
+               return 0;
+       hdr = queue->pdu;
++      if (unlikely(hdr->hlen != sizeof(struct nvme_tcp_rsp_pdu))) {
++              if (!nvme_tcp_recv_pdu_supported(hdr->type))
++                      goto unsupported_pdu;
++
++              dev_err(queue->ctrl->ctrl.device,
++                      "pdu type %d has unexpected header length (%d)\n",
++                      hdr->type, hdr->hlen);
++              return -EPROTO;
++      }
++
+       if (unlikely(hdr->type == nvme_tcp_c2h_term)) {
+               /*
+                * C2HTermReq never includes Header or Data digests.
+@@ -850,10 +873,13 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
+               nvme_tcp_init_recv_ctx(queue);
+               return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
+       default:
+-              dev_err(queue->ctrl->ctrl.device,
+-                      "unsupported pdu type (%d)\n", hdr->type);
+-              return -EINVAL;
++              goto unsupported_pdu;
+       }
++
++unsupported_pdu:
++      dev_err(queue->ctrl->ctrl.device,
++              "unsupported pdu type (%d)\n", hdr->type);
++      return -EINVAL;
+ }
+ static inline void nvme_tcp_end_request(struct request *rq, u16 status)
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvme-tcp-fix-signedness-bug-in-nvme_tcp_init_connect.patch b/queue-6.13/nvme-tcp-fix-signedness-bug-in-nvme_tcp_init_connect.patch
new file mode 100644 (file)
index 0000000..4da951a
--- /dev/null
@@ -0,0 +1,53 @@
+From b17d52d57b2895fd1feddd56ef46b19490b91551 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 18:52:59 +0300
+Subject: nvme-tcp: fix signedness bug in nvme_tcp_init_connection()
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+[ Upstream commit 528361c49962708a60f51a1afafeb00987cebedf ]
+
+The kernel_recvmsg() function returns an int which could be either
+negative error codes or the number of bytes received.  The problem is
+that the condition:
+
+        if (ret < sizeof(*icresp)) {
+
+is type promoted to type unsigned long and negative values are treated
+as high positive values which is success, when they should be treated as
+failure.  Handle invalid positive returns separately from negative
+error codes to avoid this problem.
+
+Fixes: 578539e09690 ("nvme-tcp: fix connect failure on receiving partial ICResp PDU")
+Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
+Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/tcp.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index ade7f1af33d80..5c50f1a5af957 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -1521,11 +1521,11 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
+       msg.msg_flags = MSG_WAITALL;
+       ret = kernel_recvmsg(queue->sock, &msg, &iov, 1,
+                       iov.iov_len, msg.msg_flags);
+-      if (ret < sizeof(*icresp)) {
++      if (ret >= 0 && ret < sizeof(*icresp))
++              ret = -ECONNRESET;
++      if (ret < 0) {
+               pr_warn("queue %d: failed to receive icresp, error %d\n",
+                       nvme_tcp_queue_id(queue), ret);
+-              if (ret >= 0)
+-                      ret = -ECONNRESET;
+               goto free_icresp;
+       }
+       ret = -ENOTCONN;
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvmet-remove-old-function-prototype.patch b/queue-6.13/nvmet-remove-old-function-prototype.patch
new file mode 100644 (file)
index 0000000..d7a3461
--- /dev/null
@@ -0,0 +1,34 @@
+From 42c3b8b87c03f12c5cbf1178787a74be1a957d8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Feb 2025 20:00:05 +0100
+Subject: nvmet: remove old function prototype
+
+From: Maurizio Lombardi <mlombard@redhat.com>
+
+[ Upstream commit 0979ff3676b1b4e6a20970bc265491d23c2da42b ]
+
+nvmet_subsys_nsid_exists() doesn't exist anymore
+
+Fixes: 74d16965d7ac ("nvmet-loop: avoid using mutex in IO hotpath")
+Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/target/nvmet.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index 7233549f7c8a0..016a5c2505464 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -607,7 +607,6 @@ void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
+               struct nvmet_host *host);
+ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
+               u8 event_info, u8 log_page);
+-bool nvmet_subsys_nsid_exists(struct nvmet_subsys *subsys, u32 nsid);
+ #define NVMET_MIN_QUEUE_SIZE  16
+ #define NVMET_MAX_QUEUE_SIZE  1024
+-- 
+2.39.5
+
diff --git a/queue-6.13/nvmet-tcp-fix-a-possible-sporadic-response-drops-in-.patch b/queue-6.13/nvmet-tcp-fix-a-possible-sporadic-response-drops-in-.patch
new file mode 100644 (file)
index 0000000..9516f96
--- /dev/null
@@ -0,0 +1,71 @@
+From b1d1aa466b08ca05f944e80325e967458a60d81a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 09:28:12 +0200
+Subject: nvmet-tcp: Fix a possible sporadic response drops in weakly ordered
+ arch
+
+From: Meir Elisha <meir.elisha@volumez.com>
+
+[ Upstream commit a16f88964c647103dad7743a484b216d488a6352 ]
+
+The order in which queue->cmd and rcv_state are updated is crucial.
+If these assignments are reordered by the compiler, the worker might not
+get queued in nvmet_tcp_queue_response(), hanging the IO. to enforce the
+the correct reordering, set rcv_state using smp_store_release().
+
+Fixes: bdaf13279192 ("nvmet-tcp: fix a segmentation fault during io parsing error")
+
+Signed-off-by: Meir Elisha <meir.elisha@volumez.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/target/tcp.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
+index 7c51c2a8c109a..4f9cac8a5abe0 100644
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -571,10 +571,16 @@ static void nvmet_tcp_queue_response(struct nvmet_req *req)
+       struct nvmet_tcp_cmd *cmd =
+               container_of(req, struct nvmet_tcp_cmd, req);
+       struct nvmet_tcp_queue  *queue = cmd->queue;
++      enum nvmet_tcp_recv_state queue_state;
++      struct nvmet_tcp_cmd *queue_cmd;
+       struct nvme_sgl_desc *sgl;
+       u32 len;
+-      if (unlikely(cmd == queue->cmd)) {
++      /* Pairs with store_release in nvmet_prepare_receive_pdu() */
++      queue_state = smp_load_acquire(&queue->rcv_state);
++      queue_cmd = READ_ONCE(queue->cmd);
++
++      if (unlikely(cmd == queue_cmd)) {
+               sgl = &cmd->req.cmd->common.dptr.sgl;
+               len = le32_to_cpu(sgl->length);
+@@ -583,7 +589,7 @@ static void nvmet_tcp_queue_response(struct nvmet_req *req)
+                * Avoid using helpers, this might happen before
+                * nvmet_req_init is completed.
+                */
+-              if (queue->rcv_state == NVMET_TCP_RECV_PDU &&
++              if (queue_state == NVMET_TCP_RECV_PDU &&
+                   len && len <= cmd->req.port->inline_data_size &&
+                   nvme_is_write(cmd->req.cmd))
+                       return;
+@@ -847,8 +853,9 @@ static void nvmet_prepare_receive_pdu(struct nvmet_tcp_queue *queue)
+ {
+       queue->offset = 0;
+       queue->left = sizeof(struct nvme_tcp_hdr);
+-      queue->cmd = NULL;
+-      queue->rcv_state = NVMET_TCP_RECV_PDU;
++      WRITE_ONCE(queue->cmd, NULL);
++      /* Ensure rcv_state is visible only after queue->cmd is set */
++      smp_store_release(&queue->rcv_state, NVMET_TCP_RECV_PDU);
+ }
+ static void nvmet_tcp_free_crypto(struct nvmet_tcp_queue *queue)
+-- 
+2.39.5
+
diff --git a/queue-6.13/perf-core-fix-pmus_lock-vs.-pmus_srcu-ordering.patch b/queue-6.13/perf-core-fix-pmus_lock-vs.-pmus_srcu-ordering.patch
new file mode 100644 (file)
index 0000000..c651fbe
--- /dev/null
@@ -0,0 +1,58 @@
+From 6784f5ed325dae0a086fada909b581c83dc496c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Nov 2024 14:39:11 +0100
+Subject: perf/core: Fix pmus_lock vs. pmus_srcu ordering
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 2565e42539b120b81a68a58da961ce5d1e34eac8 ]
+
+Commit a63fbed776c7 ("perf/tracing/cpuhotplug: Fix locking order")
+placed pmus_lock inside pmus_srcu, this makes perf_pmu_unregister()
+trip lockdep.
+
+Move the locking about such that only pmu_idr and pmus (list) are
+modified while holding pmus_lock. This avoids doing synchronize_srcu()
+while holding pmus_lock and all is well again.
+
+Fixes: a63fbed776c7 ("perf/tracing/cpuhotplug: Fix locking order")
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/20241104135517.679556858@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 0e6e16eb2d106..43a44a6e243b1 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -11896,6 +11896,8 @@ void perf_pmu_unregister(struct pmu *pmu)
+ {
+       mutex_lock(&pmus_lock);
+       list_del_rcu(&pmu->entry);
++      idr_remove(&pmu_idr, pmu->type);
++      mutex_unlock(&pmus_lock);
+       /*
+        * We dereference the pmu list under both SRCU and regular RCU, so
+@@ -11905,7 +11907,6 @@ void perf_pmu_unregister(struct pmu *pmu)
+       synchronize_rcu();
+       free_percpu(pmu->pmu_disable_count);
+-      idr_remove(&pmu_idr, pmu->type);
+       if (pmu_bus_running && pmu->dev && pmu->dev != PMU_NULL_DEV) {
+               if (pmu->nr_addr_filters)
+                       device_remove_file(pmu->dev, &dev_attr_nr_addr_filters);
+@@ -11913,7 +11914,6 @@ void perf_pmu_unregister(struct pmu *pmu)
+               put_device(pmu->dev);
+       }
+       free_pmu_context(pmu);
+-      mutex_unlock(&pmus_lock);
+ }
+ EXPORT_SYMBOL_GPL(perf_pmu_unregister);
+-- 
+2.39.5
+
diff --git a/queue-6.13/ppp-fix-kmsan-uninit-value-warning-with-bpf.patch b/queue-6.13/ppp-fix-kmsan-uninit-value-warning-with-bpf.patch
new file mode 100644 (file)
index 0000000..0bd6db0
--- /dev/null
@@ -0,0 +1,121 @@
+From f076a35d44e56cac10b4bb8c6911c438e89cb789 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Feb 2025 22:14:08 +0800
+Subject: ppp: Fix KMSAN uninit-value warning with bpf
+
+From: Jiayuan Chen <jiayuan.chen@linux.dev>
+
+[ Upstream commit 4c2d14c40a68678d885eab4008a0129646805bae ]
+
+Syzbot caught an "KMSAN: uninit-value" warning [1], which is caused by the
+ppp driver not initializing a 2-byte header when using socket filter.
+
+The following code can generate a PPP filter BPF program:
+'''
+struct bpf_program fp;
+pcap_t *handle;
+handle = pcap_open_dead(DLT_PPP_PPPD, 65535);
+pcap_compile(handle, &fp, "ip and outbound", 0, 0);
+bpf_dump(&fp, 1);
+'''
+Its output is:
+'''
+(000) ldh [2]
+(001) jeq #0x21 jt 2 jf 5
+(002) ldb [0]
+(003) jeq #0x1 jt 4 jf 5
+(004) ret #65535
+(005) ret #0
+'''
+Wen can find similar code at the following link:
+https://github.com/ppp-project/ppp/blob/master/pppd/options.c#L1680
+The maintainer of this code repository is also the original maintainer
+of the ppp driver.
+
+As you can see the BPF program skips 2 bytes of data and then reads the
+'Protocol' field to determine if it's an IP packet. Then it read the first
+byte of the first 2 bytes to determine the direction.
+
+The issue is that only the first byte indicating direction is initialized
+in current ppp driver code while the second byte is not initialized.
+
+For normal BPF programs generated by libpcap, uninitialized data won't be
+used, so it's not a problem. However, for carefully crafted BPF programs,
+such as those generated by syzkaller [2], which start reading from offset
+0, the uninitialized data will be used and caught by KMSAN.
+
+[1] https://syzkaller.appspot.com/bug?extid=853242d9c9917165d791
+[2] https://syzkaller.appspot.com/text?tag=ReproC&x=11994913980000
+
+Cc: Paul Mackerras <paulus@samba.org>
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+853242d9c9917165d791@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/bpf/000000000000dea025060d6bc3bc@google.com/
+Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250228141408.393864-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ppp/ppp_generic.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index 4583e15ad03a0..1420c4efa48e6 100644
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -72,6 +72,17 @@
+ #define PPP_PROTO_LEN 2
+ #define PPP_LCP_HDRLEN        4
++/* The filter instructions generated by libpcap are constructed
++ * assuming a four-byte PPP header on each packet, where the last
++ * 2 bytes are the protocol field defined in the RFC and the first
++ * byte of the first 2 bytes indicates the direction.
++ * The second byte is currently unused, but we still need to initialize
++ * it to prevent crafted BPF programs from reading them which would
++ * cause reading of uninitialized data.
++ */
++#define PPP_FILTER_OUTBOUND_TAG 0x0100
++#define PPP_FILTER_INBOUND_TAG  0x0000
++
+ /*
+  * An instance of /dev/ppp can be associated with either a ppp
+  * interface unit or a ppp channel.  In both cases, file->private_data
+@@ -1762,10 +1773,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
+       if (proto < 0x8000) {
+ #ifdef CONFIG_PPP_FILTER
+-              /* check if we should pass this packet */
+-              /* the filter instructions are constructed assuming
+-                 a four-byte PPP header on each packet */
+-              *(u8 *)skb_push(skb, 2) = 1;
++              /* check if the packet passes the pass and active filters.
++               * See comment for PPP_FILTER_OUTBOUND_TAG above.
++               */
++              *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_OUTBOUND_TAG);
+               if (ppp->pass_filter &&
+                   bpf_prog_run(ppp->pass_filter, skb) == 0) {
+                       if (ppp->debug & 1)
+@@ -2482,14 +2493,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
+               /* network protocol frame - give it to the kernel */
+ #ifdef CONFIG_PPP_FILTER
+-              /* check if the packet passes the pass and active filters */
+-              /* the filter instructions are constructed assuming
+-                 a four-byte PPP header on each packet */
+               if (ppp->pass_filter || ppp->active_filter) {
+                       if (skb_unclone(skb, GFP_ATOMIC))
+                               goto err;
+-
+-                      *(u8 *)skb_push(skb, 2) = 0;
++                      /* Check if the packet passes the pass and active filters.
++                       * See comment for PPP_FILTER_INBOUND_TAG above.
++                       */
++                      *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_INBOUND_TAG);
+                       if (ppp->pass_filter &&
+                           bpf_prog_run(ppp->pass_filter, skb) == 0) {
+                               if (ppp->debug & 1)
+-- 
+2.39.5
+
diff --git a/queue-6.13/sched-fair-fix-potential-memory-corruption-in-child_.patch b/queue-6.13/sched-fair-fix-potential-memory-corruption-in-child_.patch
new file mode 100644 (file)
index 0000000..51a2962
--- /dev/null
@@ -0,0 +1,70 @@
+From c9a453357b738f240dfe63a77f40e0f9dab8af71 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 21:40:31 +0000
+Subject: sched/fair: Fix potential memory corruption in child_cfs_rq_on_list
+
+From: Zecheng Li <zecheng@google.com>
+
+[ Upstream commit 3b4035ddbfc8e4521f85569998a7569668cccf51 ]
+
+child_cfs_rq_on_list attempts to convert a 'prev' pointer to a cfs_rq.
+This 'prev' pointer can originate from struct rq's leaf_cfs_rq_list,
+making the conversion invalid and potentially leading to memory
+corruption. Depending on the relative positions of leaf_cfs_rq_list and
+the task group (tg) pointer within the struct, this can cause a memory
+fault or access garbage data.
+
+The issue arises in list_add_leaf_cfs_rq, where both
+cfs_rq->leaf_cfs_rq_list and rq->leaf_cfs_rq_list are added to the same
+leaf list. Also, rq->tmp_alone_branch can be set to rq->leaf_cfs_rq_list.
+
+This adds a check `if (prev == &rq->leaf_cfs_rq_list)` after the main
+conditional in child_cfs_rq_on_list. This ensures that the container_of
+operation will convert a correct cfs_rq struct.
+
+This check is sufficient because only cfs_rqs on the same CPU are added
+to the list, so verifying the 'prev' pointer against the current rq's list
+head is enough.
+
+Fixes a potential memory corruption issue that due to current struct
+layout might not be manifesting as a crash but could lead to unpredictable
+behavior when the layout changes.
+
+Fixes: fdaba61ef8a2 ("sched/fair: Ensure that the CFS parent is added after unthrottling")
+Signed-off-by: Zecheng Li <zecheng@google.com>
+Reviewed-and-tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Vincent Guittot <vincent.guittot@linaro.org>
+Link: https://lore.kernel.org/r/20250304214031.2882646-1-zecheng@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 7d0a05660e5ef..4f850edf16401 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4046,15 +4046,17 @@ static inline bool child_cfs_rq_on_list(struct cfs_rq *cfs_rq)
+ {
+       struct cfs_rq *prev_cfs_rq;
+       struct list_head *prev;
++      struct rq *rq = rq_of(cfs_rq);
+       if (cfs_rq->on_list) {
+               prev = cfs_rq->leaf_cfs_rq_list.prev;
+       } else {
+-              struct rq *rq = rq_of(cfs_rq);
+-
+               prev = rq->tmp_alone_branch;
+       }
++      if (prev == &rq->leaf_cfs_rq_list)
++              return false;
++
+       prev_cfs_rq = container_of(prev, struct cfs_rq, leaf_cfs_rq_list);
+       return (prev_cfs_rq->tg->parent == cfs_rq->tg);
+-- 
+2.39.5
+
index 378d754d0840bab77e46fc58a222715b5b2e75a7..96c3da94484c12b221ef2ac98b980f67893a7a79 100644 (file)
@@ -78,3 +78,77 @@ mm-don-t-skip-arch_sync_kernel_mappings-in-error-paths.patch
 mm-fix-finish_fault-handling-for-large-folios.patch
 hwpoison-memory_hotplug-lock-folio-before-unmap-hwpoisoned-folio.patch
 mm-memory-hotplug-check-folio-ref-count-first-in-do_migrate_range.patch
+wifi-iwlwifi-fw-avoid-using-an-uninitialized-variabl.patch
+wifi-iwlwifi-mvm-clean-up-roc-on-failure.patch
+wifi-iwlwifi-mvm-log-error-for-failures-after-d3.patch
+wifi-iwlwifi-mvm-don-t-dump-the-firmware-state-upon-.patch
+wifi-iwlwifi-mvm-don-t-try-to-talk-to-a-dead-firmwar.patch
+wifi-iwlwifi-limit-printed-string-from-fw-file.patch
+wifi-iwlwifi-free-pages-allocated-when-failing-to-bu.patch
+wifi-iwlwifi-fix-a-msdu-tso-preparation.patch
+hid-google-fix-unused-variable-warning-under-config_.patch
+hid-intel-ish-hid-fix-use-after-free-issue-in-hid_is.patch
+hid-intel-ish-hid-fix-use-after-free-issue-in-ishtp_.patch
+coredump-only-sort-vmas-when-core_sort_vma-sysctl-is.patch
+nvme-ioctl-fix-leaked-requests-on-mapping-error.patch
+wifi-mac80211-support-parsing-epcs-ml-element.patch
+wifi-mac80211-fix-mle-non-inheritance-parsing.patch
+wifi-mac80211-fix-vendor-specific-inheritance.patch
+fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch
+fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch
+fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch
+tracing-add-ftrace_partial_regs-for-converting-ftrac.patch
+tracing-add-ftrace_fill_perf_regs-for-perf-event.patch
+fprobe-rewrite-fprobe-on-function-graph-tracer.patch
+tracing-fprobe-events-log-error-for-exceeding-the-nu.patch
+drm-nouveau-select-fw-caching.patch
+bluetooth-btusb-initialize-.owner-field-of-force_pol.patch
+nvmet-remove-old-function-prototype.patch
+nvme-tcp-add-basic-support-for-the-c2htermreq-pdu.patch
+nvme-tcp-fix-potential-memory-corruption-in-nvme_tcp.patch
+nvmet-tcp-fix-a-possible-sporadic-response-drops-in-.patch
+alsa-hda-realtek-remove-revert-duplicate-ally-x-conf.patch
+net-gso-fix-ownership-in-__udp_gso_segment.patch
+caif_virtio-fix-wrong-pointer-check-in-cfv_probe.patch
+perf-core-fix-pmus_lock-vs.-pmus_srcu-ordering.patch
+cred-return-old-creds-from-revert_creds_light.patch
+cred-fix-rcu-warnings-in-override-revert_creds.patch
+hwmon-pmbus-initialise-page-count-in-pmbus_identify.patch
+hwmon-ntc_thermistor-fix-the-ncpxxxh103-sensor-table.patch
+hwmon-ad7314-validate-leading-zero-bits-and-return-e.patch
+tracing-probe-events-remove-unused-max_arg_buf_len-m.patch
+drm-imagination-fix-timestamps-in-firmware-traces.patch
+alsa-usx2y-validate-nrpacks-module-parameter-on-prob.patch
+llc-do-not-use-skb_get-before-dev_queue_xmit.patch
+hwmon-fix-a-null-vs-is_err_or_null-check-in-xgene_hw.patch
+drm-sched-fix-preprocessor-guard.patch
+be2net-fix-sleeping-while-atomic-bugs-in-be_ndo_brid.patch
+net-hns3-make-sure-ptp-clock-is-unregister-and-freed.patch
+fs-pipe-read-pipe-head-tail-atomically-outside-pipe-.patch
+drm-xe-remove-double-pageflip.patch
+hid-hid-steam-fix-use-after-free-when-detaching-devi.patch
+net-ipa-fix-v4.7-resource-group-names.patch
+net-ipa-fix-qsb-data-for-v4.7.patch
+net-ipa-enable-checksum-for-ipa_endpoint_ap_modem_-r.patch
+ppp-fix-kmsan-uninit-value-warning-with-bpf.patch
+ethtool-linkstate-migrate-linkstate-functions-to-sup.patch
+net-ethtool-plumb-phy-stats-to-phy-drivers.patch
+net-ethtool-netlink-allow-null-nlattrs-when-getting-.patch
+vlan-enforce-underlying-device-type.patch
+x86-sgx-fix-size-overflows-in-sgx_encl_create.patch
+exfat-fix-just-enough-dentries-but-allocate-a-new-cl.patch
+exfat-fix-soft-lockup-in-exfat_clear_bitmap.patch
+exfat-short-circuit-zero-byte-writes-in-exfat_file_w.patch
+net-timestamp-support-tcp-gso-case-for-a-few-missing.patch
+ublk-set_params-properly-check-if-parameters-can-be-.patch
+sched-fair-fix-potential-memory-corruption-in-child_.patch
+fs-pipe-fix-pipe_occupancy-with-16-bit-indexes.patch
+nvme-tcp-fix-signedness-bug-in-nvme_tcp_init_connect.patch
+net-dsa-mt7530-fix-traffic-flooding-for-mmio-devices.patch
+drm-bochs-fix-dpms-regression.patch
+mctp-i3c-handle-null-header-address.patch
+net-ipv6-fix-dst-ref-loop-in-ila-lwtunnel.patch
+net-ipv6-fix-missing-dst-ref-drop-in-ila-lwtunnel.patch
+gpio-rcar-fix-missing-of_node_put-call.patch
+fs-pipe-do-not-open-code-pipe-head-tail-logic-in-fio.patch
+fs-pipe-fix-pipe-buffer-index-use-in-fuse.patch
diff --git a/queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch b/queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch
new file mode 100644 (file)
index 0000000..1921c31
--- /dev/null
@@ -0,0 +1,171 @@
+From 2dc177cc7af51eb92a7f8ee3b81edfcc1601d361 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:12:59 +0900
+Subject: tracing: Add ftrace_fill_perf_regs() for perf event
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit d5d01b71996ec03af51b3c0736c92d0fc89703b5 ]
+
+Add ftrace_fill_perf_regs() which should be compatible with the
+perf_fetch_caller_regs(). In other words, the pt_regs returned from the
+ftrace_fill_perf_regs() must satisfy 'user_mode(regs) == false' and can be
+used for stack tracing.
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Will Deacon <will@kernel.org>
+Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Florent Revest <revest@chromium.org>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Naveen N Rao <naveen@kernel.org>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: x86@kernel.org
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Link: https://lore.kernel.org/173518997908.391279.15910334347345106424.stgit@devnote2
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/ftrace.h   |  7 +++++++
+ arch/powerpc/include/asm/ftrace.h |  7 +++++++
+ arch/s390/include/asm/ftrace.h    |  6 ++++++
+ arch/x86/include/asm/ftrace.h     |  7 +++++++
+ include/linux/ftrace.h            | 31 +++++++++++++++++++++++++++++++
+ 5 files changed, 58 insertions(+)
+
+diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
+index 09210f853f12d..10e56522122aa 100644
+--- a/arch/arm64/include/asm/ftrace.h
++++ b/arch/arm64/include/asm/ftrace.h
+@@ -148,6 +148,13 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
+       return regs;
+ }
++#define arch_ftrace_fill_perf_regs(fregs, _regs) do {         \
++              (_regs)->pc = arch_ftrace_regs(fregs)->pc;                      \
++              (_regs)->regs[29] = arch_ftrace_regs(fregs)->fp;                \
++              (_regs)->sp = arch_ftrace_regs(fregs)->sp;                      \
++              (_regs)->pstate = PSR_MODE_EL1h;                \
++      } while (0)
++
+ int ftrace_regs_query_register_offset(const char *name);
+ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
+index db481b336bca4..fe181bafdca4f 100644
+--- a/arch/powerpc/include/asm/ftrace.h
++++ b/arch/powerpc/include/asm/ftrace.h
+@@ -43,6 +43,13 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *
+       return arch_ftrace_regs(fregs)->regs.msr ? &arch_ftrace_regs(fregs)->regs : NULL;
+ }
++#define arch_ftrace_fill_perf_regs(fregs, _regs) do {         \
++              (_regs)->result = 0;                            \
++              (_regs)->nip = arch_ftrace_regs(fregs)->regs.nip;               \
++              (_regs)->gpr[1] = arch_ftrace_regs(fregs)->regs.gpr[1];         \
++              asm volatile("mfmsr %0" : "=r" ((_regs)->msr)); \
++      } while (0)
++
+ static __always_inline void
+ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
+                                   unsigned long ip)
+diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
+index 5c94c1fc1bc1c..5b7cb49c41ee0 100644
+--- a/arch/s390/include/asm/ftrace.h
++++ b/arch/s390/include/asm/ftrace.h
+@@ -76,6 +76,12 @@ ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs)
+       return ftrace_regs_get_stack_pointer(fregs);
+ }
++#define arch_ftrace_fill_perf_regs(fregs, _regs)       do {           \
++              (_regs)->psw.mask = 0;                                  \
++              (_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr;             \
++              (_regs)->gprs[15] = arch_ftrace_regs(fregs)->regs.gprs[15];             \
++      } while (0)
++
+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+ /*
+  * When an ftrace registered caller is tracing a function that is
+diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
+index d61407c680c28..7e06f8c7937aa 100644
+--- a/arch/x86/include/asm/ftrace.h
++++ b/arch/x86/include/asm/ftrace.h
+@@ -47,6 +47,13 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs)
+       return &arch_ftrace_regs(fregs)->regs;
+ }
++#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \
++              (_regs)->ip = arch_ftrace_regs(fregs)->regs.ip;         \
++              (_regs)->sp = arch_ftrace_regs(fregs)->regs.sp;         \
++              (_regs)->cs = __KERNEL_CS;              \
++              (_regs)->flags = 0;                     \
++      } while (0)
++
+ #define ftrace_regs_set_instruction_pointer(fregs, _ip)       \
+       do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0)
+diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
+index 863c014dff683..56cb3d243c6c4 100644
+--- a/include/linux/ftrace.h
++++ b/include/linux/ftrace.h
+@@ -207,6 +207,37 @@ ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs)
+ #endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */
++#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
++
++/*
++ * Please define arch dependent pt_regs which compatible to the
++ * perf_arch_fetch_caller_regs() but based on ftrace_regs.
++ * This requires
++ *   - user_mode(_regs) returns false (always kernel mode).
++ *   - able to use the _regs for stack trace.
++ */
++#ifndef arch_ftrace_fill_perf_regs
++/* As same as perf_arch_fetch_caller_regs(), do nothing by default */
++#define arch_ftrace_fill_perf_regs(fregs, _regs) do {} while (0)
++#endif
++
++static __always_inline struct pt_regs *
++ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs)
++{
++      arch_ftrace_fill_perf_regs(fregs, regs);
++      return regs;
++}
++
++#else /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
++
++static __always_inline struct pt_regs *
++ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs)
++{
++      return &arch_ftrace_regs(fregs)->regs;
++}
++
++#endif
++
+ /*
+  * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs.
+  * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs.
+-- 
+2.39.5
+
diff --git a/queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch b/queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch
new file mode 100644 (file)
index 0000000..418f517
--- /dev/null
@@ -0,0 +1,124 @@
+From d610ad390f261355db36806d148174e492d32f0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:12:47 +0900
+Subject: tracing: Add ftrace_partial_regs() for converting ftrace_regs to
+ pt_regs
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit b9b55c8912ce1e5555715d126486bdd63ddfeaec ]
+
+Add ftrace_partial_regs() which converts the ftrace_regs to pt_regs.
+This is for the eBPF which needs this to keep the same pt_regs interface
+to access registers.
+Thus when replacing the pt_regs with ftrace_regs in fprobes (which is
+used by kprobe_multi eBPF event), this will be used.
+
+If the architecture defines its own ftrace_regs, this copies partial
+registers to pt_regs and returns it. If not, ftrace_regs is the same as
+pt_regs and ftrace_partial_regs() will return ftrace_regs::regs.
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Florent Revest <revest@chromium.org>
+Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Cc: Martin KaFai Lau <martin.lau@linux.dev>
+Cc: bpf <bpf@vger.kernel.org>
+Cc: Alexei Starovoitov <ast@kernel.org>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Alan Maguire <alan.maguire@oracle.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Link: https://lore.kernel.org/173518996761.391279.4987911298206448122.stgit@devnote2
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/ftrace.h | 13 +++++++++++++
+ arch/riscv/include/asm/ftrace.h | 14 ++++++++++++++
+ include/linux/ftrace.h          | 17 +++++++++++++++++
+ 3 files changed, 44 insertions(+)
+
+diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
+index b5fa57b61378e..09210f853f12d 100644
+--- a/arch/arm64/include/asm/ftrace.h
++++ b/arch/arm64/include/asm/ftrace.h
+@@ -135,6 +135,19 @@ ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
+       return arch_ftrace_regs(fregs)->fp;
+ }
++static __always_inline struct pt_regs *
++ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
++{
++      struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
++
++      memcpy(regs->regs, afregs->regs, sizeof(afregs->regs));
++      regs->sp = afregs->sp;
++      regs->pc = afregs->pc;
++      regs->regs[29] = afregs->fp;
++      regs->regs[30] = afregs->lr;
++      return regs;
++}
++
+ int ftrace_regs_query_register_offset(const char *name);
+ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h
+index 9372f8d7036f8..7064a530794b6 100644
+--- a/arch/riscv/include/asm/ftrace.h
++++ b/arch/riscv/include/asm/ftrace.h
+@@ -197,6 +197,20 @@ static __always_inline void ftrace_override_function_with_return(struct ftrace_r
+       arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra;
+ }
++static __always_inline struct pt_regs *
++ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
++{
++      struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
++
++      memcpy(&regs->a0, afregs->args, sizeof(afregs->args));
++      regs->epc = afregs->epc;
++      regs->ra = afregs->ra;
++      regs->sp = afregs->sp;
++      regs->s0 = afregs->s0;
++      regs->t1 = afregs->t1;
++      return regs;
++}
++
+ int ftrace_regs_query_register_offset(const char *name);
+ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
+index 46ac44366c90a..863c014dff683 100644
+--- a/include/linux/ftrace.h
++++ b/include/linux/ftrace.h
+@@ -190,6 +190,23 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs
+       return arch_ftrace_get_regs(fregs);
+ }
++#if !defined(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS) || \
++      defined(CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS)
++
++static __always_inline struct pt_regs *
++ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs)
++{
++      /*
++       * If CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y, ftrace_regs memory
++       * layout is including pt_regs. So always returns that address.
++       * Since arch_ftrace_get_regs() will check some members and may return
++       * NULL, we can not use it.
++       */
++      return &arch_ftrace_regs(fregs)->regs;
++}
++
++#endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */
++
+ /*
+  * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs.
+  * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs.
+-- 
+2.39.5
+
diff --git a/queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch b/queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch
new file mode 100644 (file)
index 0000000..5886cd0
--- /dev/null
@@ -0,0 +1,59 @@
+From b9d5ba4f995b836db2e9dfec82979f43671868b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 15:19:02 +0900
+Subject: tracing: fprobe-events: Log error for exceeding the number of entry
+ args
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit db5e228611b118cf7b1f8084063feda5c037f4a7 ]
+
+Add error message when the number of entry argument exceeds the
+maximum size of entry data.
+This is currently checked when registering fprobe, but in this case
+no error message is shown in the error_log file.
+
+Link: https://lore.kernel.org/all/174055074269.4079315.17809232650360988538.stgit@mhiramat.tok.corp.google.com/
+
+Fixes: 25f00e40ce79 ("tracing/probes: Support $argN in return probe (kprobe and fprobe)")
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_fprobe.c | 5 +++++
+ kernel/trace/trace_probe.h  | 3 ++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
+index d906baba2d40c..94fe261218771 100644
+--- a/kernel/trace/trace_fprobe.c
++++ b/kernel/trace/trace_fprobe.c
+@@ -1242,6 +1242,11 @@ static int __trace_fprobe_create(int argc, const char *argv[])
+       if (is_return && tf->tp.entry_arg) {
+               tf->fp.entry_handler = trace_fprobe_entry_handler;
+               tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp);
++              if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) {
++                      trace_probe_log_set_index(2);
++                      trace_probe_log_err(0, TOO_MANY_EARGS);
++                      return -E2BIG;
++              }
+       }
+       ret = traceprobe_set_print_fmt(&tf->tp,
+diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
+index fba3ede870541..c47ca002347a7 100644
+--- a/kernel/trace/trace_probe.h
++++ b/kernel/trace/trace_probe.h
+@@ -545,7 +545,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+       C(NO_BTF_FIELD,         "This field is not found."),    \
+       C(BAD_BTF_TID,          "Failed to get BTF type info."),\
+       C(BAD_TYPE4STR,         "This type does not fit for string."),\
+-      C(NEED_STRING_TYPE,     "$comm and immediate-string only accepts string type"),
++      C(NEED_STRING_TYPE,     "$comm and immediate-string only accepts string type"),\
++      C(TOO_MANY_EARGS,       "Too many entry arguments specified"),
+ #undef C
+ #define C(a, b)               TP_ERR_##a
+-- 
+2.39.5
+
diff --git a/queue-6.13/tracing-probe-events-remove-unused-max_arg_buf_len-m.patch b/queue-6.13/tracing-probe-events-remove-unused-max_arg_buf_len-m.patch
new file mode 100644 (file)
index 0000000..002ac61
--- /dev/null
@@ -0,0 +1,38 @@
+From 92c8502e7c5098d794a87fbfc144268d810f0959 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Feb 2025 15:19:18 +0900
+Subject: tracing: probe-events: Remove unused MAX_ARG_BUF_LEN macro
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit fd5ba38390c59e1c147480ae49b6133c4ac24001 ]
+
+Commit 18b1e870a496 ("tracing/probes: Add $arg* meta argument for all
+function args") introduced MAX_ARG_BUF_LEN but it is not used.
+Remove it.
+
+Link: https://lore.kernel.org/all/174055075876.4079315.8805416872155957588.stgit@mhiramat.tok.corp.google.com/
+
+Fixes: 18b1e870a496 ("tracing/probes: Add $arg* meta argument for all function args")
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_probe.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
+index c47ca002347a7..96792bc4b0924 100644
+--- a/kernel/trace/trace_probe.h
++++ b/kernel/trace/trace_probe.h
+@@ -36,7 +36,6 @@
+ #define MAX_BTF_ARGS_LEN      128
+ #define MAX_DENTRY_ARGS_LEN   256
+ #define MAX_STRING_SIZE               PATH_MAX
+-#define MAX_ARG_BUF_LEN               (MAX_TRACE_ARGS * MAX_ARG_NAME_LEN)
+ /* Reserved field names */
+ #define FIELD_STRING_IP               "__probe_ip"
+-- 
+2.39.5
+
diff --git a/queue-6.13/ublk-set_params-properly-check-if-parameters-can-be-.patch b/queue-6.13/ublk-set_params-properly-check-if-parameters-can-be-.patch
new file mode 100644 (file)
index 0000000..ff801b6
--- /dev/null
@@ -0,0 +1,54 @@
+From c6515b32626cf47865e135ed278aa2a91b42de39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Mar 2025 14:34:26 -0700
+Subject: ublk: set_params: properly check if parameters can be applied
+
+From: Uday Shankar <ushankar@purestorage.com>
+
+[ Upstream commit 5ac60242b0173be83709603ebaf27a473f16c4e4 ]
+
+The parameters set by the set_params call are only applied to the block
+device in the start_dev call. So if a device has already been started, a
+subsequently issued set_params on that device will not have the desired
+effect, and should return an error. There is an existing check for this
+- set_params fails on devices in the LIVE state. But this check is not
+sufficient to cover the recovery case. In this case, the device will be
+in the QUIESCED or FAIL_IO states, so set_params will succeed. But this
+success is misleading, because the parameters will not be applied, since
+the device has already been started (by a previous ublk server). The bit
+UB_STATE_USED is set on completion of the start_dev; use it to detect
+and fail set_params commands which arrive too late to be applied (after
+start_dev).
+
+Signed-off-by: Uday Shankar <ushankar@purestorage.com>
+Fixes: 0aa73170eba5 ("ublk_drv: add SET_PARAMS/GET_PARAMS control command")
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/20250304-set_params-v1-1-17b5e0887606@purestorage.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/ublk_drv.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index 934ab9332c80a..d9e8bf9f5e5a8 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -2716,9 +2716,12 @@ static int ublk_ctrl_set_params(struct ublk_device *ub,
+       if (ph.len > sizeof(struct ublk_params))
+               ph.len = sizeof(struct ublk_params);
+-      /* parameters can only be changed when device isn't live */
+       mutex_lock(&ub->mutex);
+-      if (ub->dev_info.state == UBLK_S_DEV_LIVE) {
++      if (test_bit(UB_STATE_USED, &ub->state)) {
++              /*
++               * Parameters can only be changed when device hasn't
++               * been started yet
++               */
+               ret = -EACCES;
+       } else if (copy_from_user(&ub->params, argp, ph.len)) {
+               ret = -EFAULT;
+-- 
+2.39.5
+
diff --git a/queue-6.13/vlan-enforce-underlying-device-type.patch b/queue-6.13/vlan-enforce-underlying-device-type.patch
new file mode 100644 (file)
index 0000000..fa89075
--- /dev/null
@@ -0,0 +1,69 @@
+From 1bd7b77cd2bd91f88c5461afb48bbf2e6f462bc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Mar 2025 16:56:19 +0100
+Subject: vlan: enforce underlying device type
+
+From: Oscar Maes <oscmaes92@gmail.com>
+
+[ Upstream commit b33a534610067ade2bdaf2052900aaad99701353 ]
+
+Currently, VLAN devices can be created on top of non-ethernet devices.
+
+Besides the fact that it doesn't make much sense, this also causes a
+bug which leaks the address of a kernel function to usermode.
+
+When creating a VLAN device, we initialize GARP (garp_init_applicant)
+and MRP (mrp_init_applicant) for the underlying device.
+
+As part of the initialization process, we add the multicast address of
+each applicant to the underlying device, by calling dev_mc_add.
+
+__dev_mc_add uses dev->addr_len to determine the length of the new
+multicast address.
+
+This causes an out-of-bounds read if dev->addr_len is greater than 6,
+since the multicast addresses provided by GARP and MRP are only 6
+bytes long.
+
+This behaviour can be reproduced using the following commands:
+
+ip tunnel add gretest mode ip6gre local ::1 remote ::2 dev lo
+ip l set up dev gretest
+ip link add link gretest name vlantest type vlan id 100
+
+Then, the following command will display the address of garp_pdu_rcv:
+
+ip maddr show | grep 01:80:c2:00:00:21
+
+Fix the bug by enforcing the type of the underlying device during VLAN
+device initialization.
+
+Fixes: 22bedad3ce11 ("net: convert multicast list to list_head")
+Reported-by: syzbot+91161fe81857b396c8a0@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/000000000000ca9a81061a01ec20@google.com/
+Signed-off-by: Oscar Maes <oscmaes92@gmail.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Link: https://patch.msgid.link/20250303155619.8918-1-oscmaes92@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/8021q/vlan.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
+index e45187b882206..41be38264493d 100644
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -131,7 +131,8 @@ int vlan_check_real_dev(struct net_device *real_dev,
+ {
+       const char *name = real_dev->name;
+-      if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
++      if (real_dev->features & NETIF_F_VLAN_CHALLENGED ||
++          real_dev->type != ARPHRD_ETHER) {
+               pr_info("VLANs not supported on %s\n", name);
+               NL_SET_ERR_MSG_MOD(extack, "VLANs not supported on device");
+               return -EOPNOTSUPP;
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-fix-a-msdu-tso-preparation.patch b/queue-6.13/wifi-iwlwifi-fix-a-msdu-tso-preparation.patch
new file mode 100644 (file)
index 0000000..e98c54d
--- /dev/null
@@ -0,0 +1,145 @@
+From 15b9eb6e9b77ef803943832538e1cb4cd74856f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:53 +0200
+Subject: wifi: iwlwifi: Fix A-MSDU TSO preparation
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 3640dbc1f75ce15d128ea4af44226960d894f3fd ]
+
+The TSO preparation assumed that the skb head contained the headers
+while the rest of the data was in the fragments. Since this is not
+always true, e.g., it is possible that the data was linearised, modify
+the TSO preparation to start the data processing after the network
+headers.
+
+Fixes: 7f5e3038f029 ("wifi: iwlwifi: map entire SKB when sending AMSDUs")
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Benjamin Berg <benjamin.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.75769a4769bf.Iaf79e8538093cdf8c446c292cc96164ad6498f61@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../wireless/intel/iwlwifi/pcie/internal.h    |  5 +++--
+ .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c |  5 +++--
+ drivers/net/wireless/intel/iwlwifi/pcie/tx.c  | 20 +++++++++++--------
+ 3 files changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+index 27a7e0b5b3d51..ebe9b25cc53a9 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2003-2015, 2018-2024 Intel Corporation
++ * Copyright (C) 2003-2015, 2018-2025 Intel Corporation
+  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+  * Copyright (C) 2016-2017 Intel Deutschland GmbH
+  */
+@@ -643,7 +643,8 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
+                                   unsigned int len);
+ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
+                                  struct iwl_cmd_meta *cmd_meta,
+-                                 u8 **hdr, unsigned int hdr_room);
++                                 u8 **hdr, unsigned int hdr_room,
++                                 unsigned int offset);
+ void iwl_pcie_free_tso_pages(struct iwl_trans *trans, struct sk_buff *skb,
+                            struct iwl_cmd_meta *cmd_meta);
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+index 7bb74a480d7f1..477a05cd1288b 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+  * Copyright (C) 2017 Intel Deutschland GmbH
+- * Copyright (C) 2018-2020, 2023-2024 Intel Corporation
++ * Copyright (C) 2018-2020, 2023-2025 Intel Corporation
+  */
+ #include <net/tso.h>
+ #include <linux/tcp.h>
+@@ -188,7 +188,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
+               (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr));
+       /* Our device supports 9 segments at most, it will fit in 1 page */
+-      sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room);
++      sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room,
++                              snap_ip_tcp_hdrlen + hdr_len);
+       if (!sgt)
+               return -ENOMEM;
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+index 1ef14340953c3..f46bdc0a5fec9 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /*
+- * Copyright (C) 2003-2014, 2018-2021, 2023-2024 Intel Corporation
++ * Copyright (C) 2003-2014, 2018-2021, 2023-2025 Intel Corporation
+  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+  * Copyright (C) 2016-2017 Intel Deutschland GmbH
+  */
+@@ -1853,6 +1853,7 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
+  * @cmd_meta: command meta to store the scatter list information for unmapping
+  * @hdr: output argument for TSO headers
+  * @hdr_room: requested length for TSO headers
++ * @offset: offset into the data from which mapping should start
+  *
+  * Allocate space for a scatter gather list and TSO headers and map the SKB
+  * using the scatter gather list. The SKB is unmapped again when the page is
+@@ -1862,18 +1863,20 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
+  */
+ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
+                                  struct iwl_cmd_meta *cmd_meta,
+-                                 u8 **hdr, unsigned int hdr_room)
++                                 u8 **hdr, unsigned int hdr_room,
++                                 unsigned int offset)
+ {
+       struct sg_table *sgt;
++      unsigned int n_segments;
+       if (WARN_ON_ONCE(skb_has_frag_list(skb)))
+               return NULL;
++      n_segments = DIV_ROUND_UP(skb->len - offset, skb_shinfo(skb)->gso_size);
+       *hdr = iwl_pcie_get_page_hdr(trans,
+                                    hdr_room + __alignof__(struct sg_table) +
+                                    sizeof(struct sg_table) +
+-                                   (skb_shinfo(skb)->nr_frags + 1) *
+-                                   sizeof(struct scatterlist),
++                                   n_segments * sizeof(struct scatterlist),
+                                    skb);
+       if (!*hdr)
+               return NULL;
+@@ -1881,11 +1884,11 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
+       sgt = (void *)PTR_ALIGN(*hdr + hdr_room, __alignof__(struct sg_table));
+       sgt->sgl = (void *)(sgt + 1);
+-      sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1);
++      sg_init_table(sgt->sgl, n_segments);
+       /* Only map the data, not the header (it is copied to the TSO page) */
+-      sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, skb_headlen(skb),
+-                                     skb->data_len);
++      sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, offset,
++                                     skb->len - offset);
+       if (WARN_ON_ONCE(sgt->orig_nents <= 0))
+               return NULL;
+@@ -1937,7 +1940,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
+               (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len;
+       /* Our device supports 9 segments at most, it will fit in 1 page */
+-      sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room);
++      sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room,
++                              snap_ip_tcp_hdrlen + hdr_len + iv_len);
+       if (!sgt)
+               return -ENOMEM;
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-free-pages-allocated-when-failing-to-bu.patch b/queue-6.13/wifi-iwlwifi-free-pages-allocated-when-failing-to-bu.patch
new file mode 100644 (file)
index 0000000..1f29cf5
--- /dev/null
@@ -0,0 +1,38 @@
+From 62379e5f7f7056fe984ff74f17706127ffdf24b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:52 +0200
+Subject: wifi: iwlwifi: Free pages allocated when failing to build A-MSDU
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 3b08e608d50c44ca1135beed179f266aa0461da7 ]
+
+When failing to prepare the data needed for A-MSDU transmission, the memory
+allocated for the TSO management was not freed. Fix it.
+
+Fixes: 7f5e3038f029 ("wifi: iwlwifi: map entire SKB when sending AMSDUs")
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.bc27fad9b3d5.Ibf43dd18fb652b1a59061204e081f11c9fa34a3f@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+index b1846abb99b78..7bb74a480d7f1 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+@@ -347,6 +347,7 @@ iwl_tfh_tfd *iwl_txq_gen2_build_tx_amsdu(struct iwl_trans *trans,
+       return tfd;
+ out_err:
++      iwl_pcie_free_tso_pages(trans, skb, out_meta);
+       iwl_txq_gen2_tfd_unmap(trans, out_meta, tfd);
+       return NULL;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-fw-avoid-using-an-uninitialized-variabl.patch b/queue-6.13/wifi-iwlwifi-fw-avoid-using-an-uninitialized-variabl.patch
new file mode 100644 (file)
index 0000000..ca72ee7
--- /dev/null
@@ -0,0 +1,43 @@
+From 045f29e06349f1e5413ae2f994929d487cf5bf89 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:46 +0200
+Subject: wifi: iwlwifi: fw: avoid using an uninitialized variable
+
+From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+[ Upstream commit 3f8aa0b8a53df2247a84eaf3b3aa38b6ef86cb1c ]
+
+iwl_fwrt_read_err_table can return true also when it failed to read
+the memory. In this case, err_id argument is not initialized,
+but the callers are still using it.
+
+Simply initialize it to 0. If the error table was read successfully it'll
+be overridden.
+
+Fixes: 43e0b2ada519 ("wifi: iwlwifi: fw: add an error table status getter")
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Link: https://patch.msgid.link/20250209143303.37cdbba4eb56.I95fe9bd95303b8179f946766558a9f15f4fe254c@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/dump.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+index 8e0c85a1240d7..c7b261c8ec969 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+@@ -540,6 +540,9 @@ bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id)
+       } err_info = {};
+       int ret;
++      if (err_id)
++              *err_id = 0;
++
+       if (!base)
+               return false;
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-limit-printed-string-from-fw-file.patch b/queue-6.13/wifi-iwlwifi-limit-printed-string-from-fw-file.patch
new file mode 100644 (file)
index 0000000..37e3f82
--- /dev/null
@@ -0,0 +1,43 @@
+From e54505d4f4a09d72d9dbeff0f870330747a6f787 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:51 +0200
+Subject: wifi: iwlwifi: limit printed string from FW file
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit e0dc2c1bef722cbf16ae557690861e5f91208129 ]
+
+There's no guarantee here that the file is always with a
+NUL-termination, so reading the string may read beyond the
+end of the TLV. If that's the last TLV in the file, it can
+perhaps even read beyond the end of the file buffer.
+
+Fix that by limiting the print format to the size of the
+buffer we have.
+
+Fixes: aee1b6385e29 ("iwlwifi: support fseq tlv and print fseq version")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.cb5f9d0c2f5d.Idec695d53c6c2234aade306f7647b576c7e3d928@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+index c620911a11933..754e01688900d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+@@ -1197,7 +1197,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
+                       if (tlv_len != sizeof(*fseq_ver))
+                               goto invalid_tlv_len;
+-                      IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %s\n",
++                      IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n",
+                                fseq_ver->version);
+                       }
+                       break;
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-mvm-clean-up-roc-on-failure.patch b/queue-6.13/wifi-iwlwifi-mvm-clean-up-roc-on-failure.patch
new file mode 100644 (file)
index 0000000..dd48552
--- /dev/null
@@ -0,0 +1,48 @@
+From c16f5f3d92d23385951af6bddb5ce39abd1d264c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:47 +0200
+Subject: wifi: iwlwifi: mvm: clean up ROC on failure
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit f9751163bffd3fe60794929829f810968c6de73d ]
+
+If the firmware fails to start the session protection, then we
+do call iwl_mvm_roc_finished() here, but that won't do anything
+at all because IWL_MVM_STATUS_ROC_P2P_RUNNING was never set.
+Set IWL_MVM_STATUS_ROC_P2P_RUNNING in the failure/stop path.
+If it started successfully before, it's already set, so that
+doesn't matter, and if it didn't start it needs to be set to
+clean up.
+
+Not doing so will lead to a WARN_ON() later on a fresh remain-
+on-channel, since the link is already active when activated as
+it was never deactivated.
+
+Fixes: 35c1bbd93c4e ("wifi: iwlwifi: mvm: remove IWL_MVM_STATUS_NEED_FLUSH_P2P")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.0fe36c291068.I67f5dac742170dd937f11e4d4f937f45f71b7cb4@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+index 72fa7ac86516c..17b8ccc275693 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+@@ -1030,6 +1030,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
+               /* End TE, notify mac80211 */
+               mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
+               mvmvif->time_event_data.link_id = -1;
++              /* set the bit so the ROC cleanup will actually clean up */
++              set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status);
+               iwl_mvm_roc_finished(mvm);
+               ieee80211_remain_on_channel_expired(mvm->hw);
+       } else if (le32_to_cpu(notif->start)) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-mvm-don-t-dump-the-firmware-state-upon-.patch b/queue-6.13/wifi-iwlwifi-mvm-don-t-dump-the-firmware-state-upon-.patch
new file mode 100644 (file)
index 0000000..0e75180
--- /dev/null
@@ -0,0 +1,167 @@
+From 244ba27c92af735706ab8207f5487b36339571c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:48 +0200
+Subject: wifi: iwlwifi: mvm: don't dump the firmware state upon RFKILL while
+ suspend
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit d48ff3ce92259bae7e77732c7cfd7cbc7992c021 ]
+
+This is not really a firmware error. We need to reload the firmware, but
+this doesn't mean that we should consider this as a firmware error.
+When the firmware was restarted upon resume, this wasn't felt by the
+driver. Now that we keep the firmware running during suspend even if we
+don't have wowlan, this started to pop-up.
+
+Fixes: e8bb19c1d590 ("wifi: iwlwifi: support fast resume")
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.a10463a40318.I14131781c3124b58e60e1f5e9d793a2bc88b464c@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 77 ++++++++++++++-------
+ 1 file changed, 51 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+index 33794780d5c9e..5797d28b6a0d1 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+@@ -3099,8 +3099,14 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
+               ieee80211_resume_disconnect(vif);
+ }
+-static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
+-                                 struct ieee80211_vif *vif)
++enum rt_status {
++      FW_ALIVE,
++      FW_NEEDS_RESET,
++      FW_ERROR,
++};
++
++static enum rt_status iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
++                                            struct ieee80211_vif *vif)
+ {
+       u32 err_id;
+@@ -3108,29 +3114,35 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
+       if (iwl_fwrt_read_err_table(mvm->trans,
+                                   mvm->trans->dbg.lmac_error_event_table[0],
+                                   &err_id)) {
+-              if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {
+-                      struct cfg80211_wowlan_wakeup wakeup = {
+-                              .rfkill_release = true,
+-                      };
+-                      ieee80211_report_wowlan_wakeup(vif, &wakeup,
+-                                                     GFP_KERNEL);
++              if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
++                      IWL_WARN(mvm, "Rfkill was toggled during suspend\n");
++                      if (vif) {
++                              struct cfg80211_wowlan_wakeup wakeup = {
++                                      .rfkill_release = true,
++                              };
++
++                              ieee80211_report_wowlan_wakeup(vif, &wakeup,
++                                                             GFP_KERNEL);
++                      }
++
++                      return FW_NEEDS_RESET;
+               }
+-              return true;
++              return FW_ERROR;
+       }
+       /* check if we have lmac2 set and check for error */
+       if (iwl_fwrt_read_err_table(mvm->trans,
+                                   mvm->trans->dbg.lmac_error_event_table[1],
+                                   NULL))
+-              return true;
++              return FW_ERROR;
+       /* check for umac error */
+       if (iwl_fwrt_read_err_table(mvm->trans,
+                                   mvm->trans->dbg.umac_error_event_table,
+                                   NULL))
+-              return true;
++              return FW_ERROR;
+-      return false;
++      return FW_ALIVE;
+ }
+ /*
+@@ -3499,6 +3511,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
+       bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,
+                                     IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);
+       bool resume_notif_based = iwl_mvm_d3_resume_notif_based(mvm);
++      enum rt_status rt_status;
+       bool keep = false;
+       mutex_lock(&mvm->mutex);
+@@ -3522,14 +3535,19 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
+       iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+-      if (iwl_mvm_check_rt_status(mvm, vif)) {
+-              IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
++      rt_status = iwl_mvm_check_rt_status(mvm, vif);
++      if (rt_status != FW_ALIVE) {
+               set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+-              iwl_mvm_dump_nic_error_log(mvm);
+-              iwl_dbg_tlv_time_point(&mvm->fwrt,
+-                                     IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
+-              iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+-                                      false, 0);
++              if (rt_status == FW_ERROR) {
++                      IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
++                      iwl_mvm_dump_nic_error_log(mvm);
++                      iwl_dbg_tlv_time_point(&mvm->fwrt,
++                                             IWL_FW_INI_TIME_POINT_FW_ASSERT,
++                                             NULL);
++                      iwl_fw_dbg_collect_desc(&mvm->fwrt,
++                                              &iwl_dump_desc_assert,
++                                              false, 0);
++              }
+               ret = 1;
+               goto err;
+       }
+@@ -3686,6 +3704,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
+               .notif_expected =
+                       IWL_D3_NOTIF_D3_END_NOTIF,
+       };
++      enum rt_status rt_status;
+       int ret;
+       lockdep_assert_held(&mvm->mutex);
+@@ -3695,14 +3714,20 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
+       mvm->last_reset_or_resume_time_jiffies = jiffies;
+       iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+-      if (iwl_mvm_check_rt_status(mvm, NULL)) {
+-              IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
++      rt_status = iwl_mvm_check_rt_status(mvm, NULL);
++      if (rt_status != FW_ALIVE) {
+               set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+-              iwl_mvm_dump_nic_error_log(mvm);
+-              iwl_dbg_tlv_time_point(&mvm->fwrt,
+-                                     IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
+-              iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+-                                      false, 0);
++              if (rt_status == FW_ERROR) {
++                      IWL_ERR(mvm,
++                              "iwl_mvm_check_rt_status failed, device is gone during suspend\n");
++                      iwl_mvm_dump_nic_error_log(mvm);
++                      iwl_dbg_tlv_time_point(&mvm->fwrt,
++                                             IWL_FW_INI_TIME_POINT_FW_ASSERT,
++                                             NULL);
++                      iwl_fw_dbg_collect_desc(&mvm->fwrt,
++                                              &iwl_dump_desc_assert,
++                                              false, 0);
++              }
+               mvm->trans->state = IWL_TRANS_NO_FW;
+               ret = -ENODEV;
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-mvm-don-t-try-to-talk-to-a-dead-firmwar.patch b/queue-6.13/wifi-iwlwifi-mvm-don-t-try-to-talk-to-a-dead-firmwar.patch
new file mode 100644 (file)
index 0000000..ac4256b
--- /dev/null
@@ -0,0 +1,53 @@
+From 169fd9c12e2d2fd8c39d34c7992aa57558dad7d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Feb 2025 14:34:49 +0200
+Subject: wifi: iwlwifi: mvm: don't try to talk to a dead firmware
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit d73d2c6e3313f0ba60711ab4f4b9044eddca9ca5 ]
+
+This fixes:
+
+ bad state = 0
+ WARNING: CPU: 10 PID: 702 at drivers/net/wireless/inel/iwlwifi/iwl-trans.c:178 iwl_trans_send_cmd+0xba/0xe0 [iwlwifi]
+ Call Trace:
+  <TASK>
+  ? __warn+0xca/0x1c0
+  ? iwl_trans_send_cmd+0xba/0xe0 [iwlwifi 64fa9ad799a0e0d2ba53d4af93a53ad9a531f8d4]
+  iwl_fw_dbg_clear_monitor_buf+0xd7/0x110 [iwlwifi 64fa9ad799a0e0d2ba53d4af93a53ad9a531f8d4]
+  _iwl_dbgfs_fw_dbg_clear_write+0xe2/0x120 [iwlmvm 0e8adb18cea92d2c341766bcc10b18699290068a]
+
+Ask whether the firmware is alive before sending a command.
+
+Fixes: 268712dc3b34 ("wifi: iwlwifi: mvm: add a debugfs hook to clear the monitor data")
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250209143303.8e1597b62c70.I12ea71dd9b805b095c9fc12a10c9f34a4e801b61@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+index 91ca830a7b603..f4276fdee6bea 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+@@ -1518,6 +1518,13 @@ static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm,
+       if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)
+               return -EOPNOTSUPP;
++      /*
++       * If the firmware is not running, silently succeed since there is
++       * no data to clear.
++       */
++      if (!iwl_mvm_firmware_running(mvm))
++              return count;
++
+       mutex_lock(&mvm->mutex);
+       iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt);
+       mutex_unlock(&mvm->mutex);
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-iwlwifi-mvm-log-error-for-failures-after-d3.patch b/queue-6.13/wifi-iwlwifi-mvm-log-error-for-failures-after-d3.patch
new file mode 100644 (file)
index 0000000..467d568
--- /dev/null
@@ -0,0 +1,51 @@
+From 9f5b5a7a1f2c247cd8772d626a56a48739bcd553 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 17:44:46 +0200
+Subject: wifi: iwlwifi: mvm: log error for failures after D3
+
+From: Benjamin Berg <benjamin.berg@intel.com>
+
+[ Upstream commit f8f13ea27fffff51ee257171a8604f944c876fd4 ]
+
+We only logged an error in the fast resume path. However, as the
+hardware is being restarted it makes sense to log an error to make it
+easier to understand what is happening.
+
+Add a new error message into the normal resume path and update the
+error in the fast resume path to match.
+
+Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20241226174257.df1e451d4928.Ibe286bc010ad7fecebba5650097e16ed22a654e4@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Stable-dep-of: d48ff3ce9225 ("wifi: iwlwifi: mvm: don't dump the firmware state upon RFKILL while suspend")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+index 4d1daff1e070d..33794780d5c9e 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+@@ -3523,6 +3523,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
+       iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+       if (iwl_mvm_check_rt_status(mvm, vif)) {
++              IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
+               set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+               iwl_mvm_dump_nic_error_log(mvm);
+               iwl_dbg_tlv_time_point(&mvm->fwrt,
+@@ -3695,8 +3696,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
+       iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+       if (iwl_mvm_check_rt_status(mvm, NULL)) {
+-              IWL_ERR(mvm,
+-                      "iwl_mvm_check_rt_status failed, device is gone during suspend\n");
++              IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
+               set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+               iwl_mvm_dump_nic_error_log(mvm);
+               iwl_dbg_tlv_time_point(&mvm->fwrt,
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-mac80211-fix-mle-non-inheritance-parsing.patch b/queue-6.13/wifi-mac80211-fix-mle-non-inheritance-parsing.patch
new file mode 100644 (file)
index 0000000..cba7ec2
--- /dev/null
@@ -0,0 +1,265 @@
+From c60fb5bcd7db88ce8b26ad5d4845057ee9852c5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 11:24:50 +0100
+Subject: wifi: mac80211: fix MLE non-inheritance parsing
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 99ca2c28e6b68084a0fb65585df09b9e28c3ec16 ]
+
+The code is erroneously applying the non-inheritance element
+to the inner elements rather than the outer, which is clearly
+completely wrong. Fix it by finding the MLE basic element at
+the beginning, and then applying the non-inheritance for the
+outer parsing.
+
+While at it, do some general cleanups such as not allowing
+callers to try looking for a specific non-transmitted BSS
+and link at the same time.
+
+Fixes: 45ebac4f059b ("wifi: mac80211: Parse station profile from association response")
+Reviewed-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250221112451.b46d42f45b66.If5b95dc3c80208e0c62d8895fb6152aa54b6620b@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/mlme.c  |   1 +
+ net/mac80211/parse.c | 127 ++++++++++++++++++++++++++++---------------
+ 2 files changed, 83 insertions(+), 45 deletions(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 61c318f5239fa..0e3db0c2920bc 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4825,6 +4825,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
+               parse_params.start = bss_ies->data;
+               parse_params.len = bss_ies->len;
+               parse_params.bss = cbss;
++              parse_params.link_id = -1;
+               bss_elems = ieee802_11_parse_elems_full(&parse_params);
+               if (!bss_elems) {
+                       ret = false;
+diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
+index cd318c1c67bec..3d5d6658fe8d5 100644
+--- a/net/mac80211/parse.c
++++ b/net/mac80211/parse.c
+@@ -47,6 +47,8 @@ struct ieee80211_elems_parse {
+       /* The EPCS Multi-Link element in the original elements */
+       const struct element *ml_epcs_elem;
++      bool multi_link_inner;
++
+       /*
+        * scratch buffer that can be used for various element parsing related
+        * tasks, e.g., element de-fragmentation etc.
+@@ -152,12 +154,11 @@ ieee80211_parse_extension_element(u32 *crc,
+                       switch (le16_get_bits(mle->control,
+                                             IEEE80211_ML_CONTROL_TYPE)) {
+                       case IEEE80211_ML_CONTROL_TYPE_BASIC:
+-                              if (elems_parse->ml_basic_elem) {
++                              if (elems_parse->multi_link_inner) {
+                                       elems->parse_error |=
+                                               IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC;
+                                       break;
+                               }
+-                              elems_parse->ml_basic_elem = elem;
+                               break;
+                       case IEEE80211_ML_CONTROL_TYPE_RECONF:
+                               elems_parse->ml_reconf_elem = elem;
+@@ -866,21 +867,36 @@ ieee80211_mle_get_sta_prof(struct ieee80211_elems_parse *elems_parse,
+       }
+ }
+-static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
+-                                   struct ieee80211_elems_parse_params *params)
++static const struct element *
++ieee80211_prep_mle_link_parse(struct ieee80211_elems_parse *elems_parse,
++                            struct ieee80211_elems_parse_params *params,
++                            struct ieee80211_elems_parse_params *sub)
+ {
+       struct ieee802_11_elems *elems = &elems_parse->elems;
+       struct ieee80211_mle_per_sta_profile *prof;
+-      struct ieee80211_elems_parse_params sub = {
+-              .mode = params->mode,
+-              .action = params->action,
+-              .from_ap = params->from_ap,
+-              .link_id = -1,
+-      };
+-      ssize_t ml_len = elems->ml_basic_len;
+-      const struct element *non_inherit = NULL;
++      const struct element *tmp;
++      ssize_t ml_len;
+       const u8 *end;
++      if (params->mode < IEEE80211_CONN_MODE_EHT)
++              return NULL;
++
++      for_each_element_extid(tmp, WLAN_EID_EXT_EHT_MULTI_LINK,
++                             elems->ie_start, elems->total_len) {
++              const struct ieee80211_multi_link_elem *mle =
++                      (void *)tmp->data + 1;
++
++              if (!ieee80211_mle_size_ok(tmp->data + 1, tmp->datalen - 1))
++                      continue;
++
++              if (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE) !=
++                  IEEE80211_ML_CONTROL_TYPE_BASIC)
++                      continue;
++
++              elems_parse->ml_basic_elem = tmp;
++              break;
++      }
++
+       ml_len = cfg80211_defragment_element(elems_parse->ml_basic_elem,
+                                            elems->ie_start,
+                                            elems->total_len,
+@@ -891,26 +907,26 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
+                                            WLAN_EID_FRAGMENT);
+       if (ml_len < 0)
+-              return;
++              return NULL;
+       elems->ml_basic = (const void *)elems_parse->scratch_pos;
+       elems->ml_basic_len = ml_len;
+       elems_parse->scratch_pos += ml_len;
+       if (params->link_id == -1)
+-              return;
++              return NULL;
+       ieee80211_mle_get_sta_prof(elems_parse, params->link_id);
+       prof = elems->prof;
+       if (!prof)
+-              return;
++              return NULL;
+       /* check if we have the 4 bytes for the fixed part in assoc response */
+       if (elems->sta_prof_len < sizeof(*prof) + prof->sta_info_len - 1 + 4) {
+               elems->prof = NULL;
+               elems->sta_prof_len = 0;
+-              return;
++              return NULL;
+       }
+       /*
+@@ -919,13 +935,17 @@ static void ieee80211_mle_parse_link(struct ieee80211_elems_parse *elems_parse,
+        * the -1 is because the 'sta_info_len' is accounted to as part of the
+        * per-STA profile, but not part of the 'u8 variable[]' portion.
+        */
+-      sub.start = prof->variable + prof->sta_info_len - 1 + 4;
++      sub->start = prof->variable + prof->sta_info_len - 1 + 4;
+       end = (const u8 *)prof + elems->sta_prof_len;
+-      sub.len = end - sub.start;
++      sub->len = end - sub->start;
+-      non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
+-                                           sub.start, sub.len);
+-      _ieee802_11_parse_elems_full(&sub, elems_parse, non_inherit);
++      sub->mode = params->mode;
++      sub->action = params->action;
++      sub->from_ap = params->from_ap;
++      sub->link_id = -1;
++
++      return cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
++                                    sub->start, sub->len);
+ }
+ static void
+@@ -973,15 +993,19 @@ ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
+ struct ieee802_11_elems *
+ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
+ {
++      struct ieee80211_elems_parse_params sub = {};
+       struct ieee80211_elems_parse *elems_parse;
+-      struct ieee802_11_elems *elems;
+       const struct element *non_inherit = NULL;
+-      u8 *nontransmitted_profile;
+-      int nontransmitted_profile_len = 0;
++      struct ieee802_11_elems *elems;
+       size_t scratch_len = 3 * params->len;
++      bool multi_link_inner = false;
+       BUILD_BUG_ON(offsetof(typeof(*elems_parse), elems) != 0);
++      /* cannot parse for both a specific link and non-transmitted BSS */
++      if (WARN_ON(params->link_id >= 0 && params->bss))
++              return NULL;
++
+       elems_parse = kzalloc(struct_size(elems_parse, scratch, scratch_len),
+                             GFP_ATOMIC);
+       if (!elems_parse)
+@@ -998,34 +1022,47 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
+       ieee80211_clear_tpe(&elems->tpe);
+       ieee80211_clear_tpe(&elems->csa_tpe);
+-      nontransmitted_profile = elems_parse->scratch_pos;
+-      nontransmitted_profile_len =
+-              ieee802_11_find_bssid_profile(params->start, params->len,
+-                                            elems, params->bss,
+-                                            nontransmitted_profile);
+-      elems_parse->scratch_pos += nontransmitted_profile_len;
+-      non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
+-                                           nontransmitted_profile,
+-                                           nontransmitted_profile_len);
++      /*
++       * If we're looking for a non-transmitted BSS then we cannot at
++       * the same time be looking for a second link as the two can only
++       * appear in the same frame carrying info for different BSSes.
++       *
++       * In any case, we only look for one at a time, as encoded by
++       * the WARN_ON above.
++       */
++      if (params->bss) {
++              int nontx_len =
++                      ieee802_11_find_bssid_profile(params->start,
++                                                    params->len,
++                                                    elems, params->bss,
++                                                    elems_parse->scratch_pos);
++              sub.start = elems_parse->scratch_pos;
++              sub.mode = params->mode;
++              sub.len = nontx_len;
++              sub.action = params->action;
++              sub.link_id = params->link_id;
++
++              /* consume the space used for non-transmitted profile */
++              elems_parse->scratch_pos += nontx_len;
++
++              non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
++                                                   sub.start, nontx_len);
++      } else {
++              /* must always parse to get elems_parse->ml_basic_elem */
++              non_inherit = ieee80211_prep_mle_link_parse(elems_parse, params,
++                                                          &sub);
++              multi_link_inner = true;
++      }
+       elems->crc = _ieee802_11_parse_elems_full(params, elems_parse,
+                                                 non_inherit);
+-      /* Override with nontransmitted profile, if found */
+-      if (nontransmitted_profile_len) {
+-              struct ieee80211_elems_parse_params sub = {
+-                      .mode = params->mode,
+-                      .start = nontransmitted_profile,
+-                      .len = nontransmitted_profile_len,
+-                      .action = params->action,
+-                      .link_id = params->link_id,
+-              };
+-
++      /* Override with nontransmitted/per-STA profile if found */
++      if (sub.len) {
++              elems_parse->multi_link_inner = multi_link_inner;
+               _ieee802_11_parse_elems_full(&sub, elems_parse, NULL);
+       }
+-      ieee80211_mle_parse_link(elems_parse, params);
+-
+       ieee80211_mle_defrag_reconf(elems_parse);
+       ieee80211_mle_defrag_epcs(elems_parse);
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-mac80211-fix-vendor-specific-inheritance.patch b/queue-6.13/wifi-mac80211-fix-vendor-specific-inheritance.patch
new file mode 100644 (file)
index 0000000..a295bc5
--- /dev/null
@@ -0,0 +1,68 @@
+From 0182b2d363f5525363f365718a997e6a435b0d92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 11:24:51 +0100
+Subject: wifi: mac80211: fix vendor-specific inheritance
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 130067e9c13bdc4820748ef16076a6972364745f ]
+
+If there's any vendor-specific element in the subelements
+then the outer element parsing must not parse any vendor
+element at all. This isn't implemented correctly now due
+to parsing into the pointers and then overriding them, so
+explicitly skip vendor elements if any exist in the sub-
+elements (non-transmitted profile or per-STA profile).
+
+Fixes: 671042a4fb77 ("mac80211: support non-inheritance element")
+Reviewed-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250221112451.fd71e5268840.I9db3e6a3367e6ff38d052d07dc07005f0dd3bd5c@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/parse.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
+index 3d5d6658fe8d5..6da39c864f45b 100644
+--- a/net/mac80211/parse.c
++++ b/net/mac80211/parse.c
+@@ -48,6 +48,7 @@ struct ieee80211_elems_parse {
+       const struct element *ml_epcs_elem;
+       bool multi_link_inner;
++      bool skip_vendor;
+       /*
+        * scratch buffer that can be used for various element parsing related
+@@ -400,6 +401,9 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
+                                       IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
+                       break;
+               case WLAN_EID_VENDOR_SPECIFIC:
++                      if (elems_parse->skip_vendor)
++                              break;
++
+                       if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+                           pos[2] == 0xf2) {
+                               /* Microsoft OUI (00:50:F2) */
+@@ -1054,12 +1058,16 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
+               multi_link_inner = true;
+       }
++      elems_parse->skip_vendor =
++              cfg80211_find_elem(WLAN_EID_VENDOR_SPECIFIC,
++                                 sub.start, sub.len);
+       elems->crc = _ieee802_11_parse_elems_full(params, elems_parse,
+                                                 non_inherit);
+       /* Override with nontransmitted/per-STA profile if found */
+       if (sub.len) {
+               elems_parse->multi_link_inner = multi_link_inner;
++              elems_parse->skip_vendor = false;
+               _ieee802_11_parse_elems_full(&sub, elems_parse, NULL);
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.13/wifi-mac80211-support-parsing-epcs-ml-element.patch b/queue-6.13/wifi-mac80211-support-parsing-epcs-ml-element.patch
new file mode 100644 (file)
index 0000000..37ef8da
--- /dev/null
@@ -0,0 +1,109 @@
+From 177c46c46dcf9e0865c6d6a0a4c2082a5ca5de4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Jan 2025 16:20:01 +0200
+Subject: wifi: mac80211: Support parsing EPCS ML element
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 24711d60f8492a30622e419cee643d59264ea939 ]
+
+Add support for parsing an ML element of type EPCS priority
+access, which can optionally be included in EHT protected action
+frames used to configure EPCS.
+
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250102161730.5afdf65cff46.I0ffa30b40fbad47bc5b608b5fd46047a8c44e904@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Stable-dep-of: 99ca2c28e6b6 ("wifi: mac80211: fix MLE non-inheritance parsing")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/ieee80211_i.h |  2 ++
+ net/mac80211/parse.c       | 29 +++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 9f0db39b28ffc..c39b813a81992 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1749,6 +1749,7 @@ struct ieee802_11_elems {
+       const struct ieee80211_eht_operation *eht_operation;
+       const struct ieee80211_multi_link_elem *ml_basic;
+       const struct ieee80211_multi_link_elem *ml_reconf;
++      const struct ieee80211_multi_link_elem *ml_epcs;
+       const struct ieee80211_bandwidth_indication *bandwidth_indication;
+       const struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT];
+@@ -1779,6 +1780,7 @@ struct ieee802_11_elems {
+       /* mult-link element can be de-fragmented and thus u8 is not sufficient */
+       size_t ml_basic_len;
+       size_t ml_reconf_len;
++      size_t ml_epcs_len;
+       u8 ttlm_num;
+diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
+index 279c5143b3356..cd318c1c67bec 100644
+--- a/net/mac80211/parse.c
++++ b/net/mac80211/parse.c
+@@ -44,6 +44,9 @@ struct ieee80211_elems_parse {
+       /* The reconfiguration Multi-Link element in the original elements */
+       const struct element *ml_reconf_elem;
++      /* The EPCS Multi-Link element in the original elements */
++      const struct element *ml_epcs_elem;
++
+       /*
+        * scratch buffer that can be used for various element parsing related
+        * tasks, e.g., element de-fragmentation etc.
+@@ -159,6 +162,9 @@ ieee80211_parse_extension_element(u32 *crc,
+                       case IEEE80211_ML_CONTROL_TYPE_RECONF:
+                               elems_parse->ml_reconf_elem = elem;
+                               break;
++                      case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
++                              elems_parse->ml_epcs_elem = elem;
++                              break;
+                       default:
+                               break;
+                       }
+@@ -943,6 +949,27 @@ ieee80211_mle_defrag_reconf(struct ieee80211_elems_parse *elems_parse)
+       elems_parse->scratch_pos += ml_len;
+ }
++static void
++ieee80211_mle_defrag_epcs(struct ieee80211_elems_parse *elems_parse)
++{
++      struct ieee802_11_elems *elems = &elems_parse->elems;
++      ssize_t ml_len;
++
++      ml_len = cfg80211_defragment_element(elems_parse->ml_epcs_elem,
++                                           elems->ie_start,
++                                           elems->total_len,
++                                           elems_parse->scratch_pos,
++                                           elems_parse->scratch +
++                                              elems_parse->scratch_len -
++                                              elems_parse->scratch_pos,
++                                           WLAN_EID_FRAGMENT);
++      if (ml_len < 0)
++              return;
++      elems->ml_epcs = (void *)elems_parse->scratch_pos;
++      elems->ml_epcs_len = ml_len;
++      elems_parse->scratch_pos += ml_len;
++}
++
+ struct ieee802_11_elems *
+ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
+ {
+@@ -1001,6 +1028,8 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
+       ieee80211_mle_defrag_reconf(elems_parse);
++      ieee80211_mle_defrag_epcs(elems_parse);
++
+       if (elems->tim && !elems->parse_error) {
+               const struct ieee80211_tim_ie *tim_ie = elems->tim;
+-- 
+2.39.5
+
diff --git a/queue-6.13/x86-sgx-fix-size-overflows-in-sgx_encl_create.patch b/queue-6.13/x86-sgx-fix-size-overflows-in-sgx_encl_create.patch
new file mode 100644 (file)
index 0000000..2e54079
--- /dev/null
@@ -0,0 +1,55 @@
+From e2410f530d4731a10c7b3d55a5e8f21ea050b32d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Mar 2025 07:00:05 +0200
+Subject: x86/sgx: Fix size overflows in sgx_encl_create()
+
+From: Jarkko Sakkinen <jarkko@kernel.org>
+
+[ Upstream commit 0d3e0dfd68fb9e6b0ec865be9f3377cc3ff55733 ]
+
+The total size calculated for EPC can overflow u64 given the added up page
+for SECS.  Further, the total size calculated for shmem can overflow even
+when the EPC size stays within limits of u64, given that it adds the extra
+space for 128 byte PCMD structures (one for each page).
+
+Address this by pre-evaluating the micro-architectural requirement of
+SGX: the address space size must be power of two. This is eventually
+checked up by ECREATE but the pre-check has the additional benefit of
+making sure that there is some space for additional data.
+
+Fixes: 888d24911787 ("x86/sgx: Add SGX_IOC_ENCLAVE_CREATE")
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Dave Hansen <dave.hansen@intel.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Link: https://lore.kernel.org/r/20250305050006.43896-1-jarkko@kernel.org
+
+Closes: https://lore.kernel.org/linux-sgx/c87e01a0-e7dd-4749-a348-0980d3444f04@stanley.mountain/
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/sgx/ioctl.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
+index b65ab214bdf57..776a20172867e 100644
+--- a/arch/x86/kernel/cpu/sgx/ioctl.c
++++ b/arch/x86/kernel/cpu/sgx/ioctl.c
+@@ -64,6 +64,13 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
+       struct file *backing;
+       long ret;
++      /*
++       * ECREATE would detect this too, but checking here also ensures
++       * that the 'encl_size' calculations below can never overflow.
++       */
++      if (!is_power_of_2(secs->size))
++              return -EINVAL;
++
+       va_page = sgx_encl_grow(encl, true);
+       if (IS_ERR(va_page))
+               return PTR_ERR(va_page);
+-- 
+2.39.5
+