6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 536/1376 firmware: arm_scmi: Clean up channels on setup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 687d67be3d87894ef12e8a164434612e0b53cfae ]
scmi_channels_setup() can fail after the common BASE channel or earlier protocol channels have already been registered in the TX/RX IDRs.
Route this failure through the existing channel cleanup label so the transport channels, transport devices and IDR state created before the failure are released before the probe error path frees the SCMI instance ID.
--- drivers/firmware/arm_scmi/driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/firmware/arm_scmi/driver.c +1 -2
@@ -3114,7 +3114,7 @@ static int scmi_probe(struct platform_device *pdev) ret =scmi_channels_setup (info);if (ret) { err_str ="failed to setup channels\n" ; - goto clear_ida; + goto clear_txrx_setup; } ret =bus_register_notifier (&scmi_bus_type, &info->bus_nb);
@@ -3228,7 +3228,6 @@ static int scmi_probe(struct platform_device *pdev)scmi_notification_quiesce (&info->handle);scmi_cleanup_txrx_channels (info);scmi_notification_exit (&info->handle); -clear_ida:ida_free (&scmi_id, info->id); out_err:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 537/1376 firmware: arm_scmi: Free transport channel on IDR failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit d72e7e5f24687c0490aabf317653caffe0447aeb ]
If transport channel setup succeeds but the following IDR insertion fails, the error path destroys the transport device and frees the channel info without invoking the transport cleanup callback.
Call chan_free() before destroying the device so transport specific resources such as IRQs, mailbox channels and mapped shared memory are released consistently with the normal teardown path.
--- drivers/firmware/arm_scmi/driver.c | 1 + 1 file changed, 1 insertion(+)
drivers/firmware/arm_scmi/driver.c +1 -0
@@ -2683,6 +2683,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, "unable to allocate SCMI idr slot err %d\n", ret);/* Destroy channel and device only if created by this call. */ if (tdev) { + info->desc->ops->chan_free (prot_id, cinfo, idr);of_node_put (of_node);scmi_device_destroy (info->dev, prot_id, name);devm_kfree (info->dev, cinfo);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 538/1376 firmware: arm_scmi: Avoid IDR updates while cleaning channels
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit c38b1e19485aaa820e52cfe162525a8af67563da ]
scmi_cleanup_channels() walks the TX/RX channel IDRs with idr_for_each() to free transport resources and destroy the dedicated transport devices before calling idr_destroy().
The destroy callback removed each entry from the same IDR being walked. That is not needed for this cleanup path, and it is unsafe because idr_for_each() has not advanced its radix-tree iterator while the callback is running. Removing the current entry from the callback can invalidate the iterator state. The callback also cannot be protected by rcu_read_lock(), because scmi_device_destroy() may sleep.
Leave IDR teardown to the following idr_destroy() call and keep the callback limited to device destruction.
--- drivers/firmware/arm_scmi/driver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/firmware/arm_scmi/driver.c +1 -3
@@ -2760,7 +2760,7 @@ static int scmi_channels_setup(struct scmi_info *info)return 0 ; } -static int scmi_chan_destroy (int id,void *p,void *idr) +static int scmi_chan_destroy (int id,void *p,void *data) {struct scmi_chan_info *cinfo = p;
@@ -2773,8 +2773,6 @@ static int scmi_chan_destroy(int id, void *p, void *idr) cinfo->dev =NULL ; } -idr_remove (idr, id); -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 539/1376 firmware: arm_scmi: Reject out of range DT protocol IDs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 59407ccb52130f2c81f4b3cbe4f14114afceb54f ]
SCMI protocol IDs carried in message headers are limited by MSG_PROTOCOL_ID_MASK. The DT parsing paths noticed protocol IDs outside that range, but only logged an error and then kept processing the invalid value.
That lets a malformed 32-bit DT reg value reach helpers which take a u8 protocol ID, where it can be truncated and/or treated as a different protocol.
For channel setup, two different out-of-range values can also be used as distinct IDR keys while aliasing the generated SCMI protocol identity.
Skip DT protocol nodes whose reg value does not fit the SCMI protocol ID field before setting up channels or creating protocol devices.
--- drivers/firmware/arm_scmi/driver.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/firmware/arm_scmi/driver.c +6 -2
@@ -2748,9 +2748,11 @@ static int scmi_channels_setup(struct scmi_info *info)if (of_property_read_u32 (child,"reg" , &prot_id))continue ; -if (!FIELD_FIT (MSG_PROTOCOL_ID_MASK , prot_id)) +if (!FIELD_FIT (MSG_PROTOCOL_ID_MASK , prot_id)) {dev_err (info->dev,"Out of range protocol %d\n" , prot_id); +continue ; + } ret =scmi_txrx_setup (info, child, prot_id);if (ret)
@@ -3188,8 +3190,10 @@ static int scmi_probe(struct platform_device *pdev)if (of_property_read_u32 (child,"reg" , &prot_id))continue ; -if (!FIELD_FIT (MSG_PROTOCOL_ID_MASK , prot_id)) +if (!FIELD_FIT (MSG_PROTOCOL_ID_MASK , prot_id)) {dev_err (dev,"Out of range protocol %d\n" , prot_id); +continue ; + }if (!scmi_is_protocol_implemented (handle, prot_id)) { dev_err(dev, "SCMI protocol %d not implemented\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 540/1376 firmware: arm_scmi: Use channel ID for transport teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit a71a3d4d8a6e9e399fd988c0e6da47a6ee21c99e ]
SCMI protocols can share the BASE transport channel when firmware does not describe a dedicated channel for the protocol. In that case multiple IDR entries can point at the same scmi_chan_info, whose owning transport device was created with cinfo->id.
scmi_chan_destroy() used the IDR iterator key when destroying the transport device. If an alias entry is visited before the owning channel entry, the lookup can miss the device because the iterator key does not match the protocol ID used when the transport device was created. The code then clears cinfo->dev, so the later owning entry skips teardown and leaks the transport device.
Destroy the transport device using cinfo->id, which is the protocol ID that owns the channel and was used when creating the transport device.
--- drivers/firmware/arm_scmi/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/firmware/arm_scmi/driver.c +1 -1
@@ -2771,7 +2771,7 @@ static int scmi_chan_destroy(int id, void *p, void *data)struct scmi_device *sdev =to_scmi_dev (cinfo->dev);of_node_put (cinfo->dev->of_node); -scmi_device_destroy (info->dev, id, sdev->name); +scmi_device_destroy (info->dev, cinfo->id, sdev->name); cinfo->dev =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 541/1376 firmware: arm_scmi: Protect device request lookup with RCU
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit e6a0e7a49d83e4fa4e1db68d74f99282eb97aa49 ]
The SCMI device request notifier looks up protocol OF nodes from the active_protocols IDR. The IDR lookup can run concurrently with protocol activation while probe is still registering protocols and creating their SCMI devices.
Wrap the lookup in an RCU read-side critical section as required by the IDR API for lockless readers.
--- drivers/firmware/arm_scmi/driver.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/firmware/arm_scmi/driver.c +3 -0
@@ -31,6 +31,7 @@#include <linux/of.h> #include <linux/platform_device.h> #include <linux/processor.h> +#include <linux/rcupdate.h> #include <linux/refcount.h> #include <linux/slab.h> #include <linux/xarray.h>
@@ -2834,7 +2835,9 @@ static int scmi_device_request_notifier(struct notifier_block *nb,struct scmi_device_id *id_table = data;struct scmi_info *info =req_nb_to_scmi_info (nb); +rcu_read_lock (); np =idr_find (&info->active_protocols, id_table->protocol_id); +rcu_read_unlock ();if (!np)return NOTIFY_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 542/1376 firmware: arm_scmi: Drop handle on protocol bind failures
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit e3a5c30d233ca5d3e799a80da806554c703bda13 ]
The SCMI bus notifier acquires an SCMI handle when the driver core emits BUS_NOTIFY_BIND_DRIVER, before invoking the protocol driver probe callback. The protocol probe path only checks whether sdev->handle is set.
If device_link_add() fails after the handle has been acquired, the protocol device can still bind with a valid handle but without the dependency link to the SCMI parent. A concurrent parent unbind can then miss the child and tear down the SCMI instance while the child still holds a handle into it.
If the protocol driver probe later fails, for example with -EPROBE_DEFER, the driver core emits BUS_NOTIFY_DRIVER_NOT_BOUND rather than BUS_NOTIFY_UNBOUND_DRIVER. The SCMI notifier only released the handle on BUS_NOTIFY_UNBOUND_DRIVER, so each failed protocol-device bind leaked the SCMI instance users refcount and left sdev->handle set after the failed probe.
Make the link helper report failure and drop the acquired handle if the link cannot be created. Also handle BUS_NOTIFY_DRIVER_NOT_BOUND in the same cleanup path used for unbind so failed probes balance the earlier BUS_NOTIFY_BIND_DRIVER acquisition.
--- drivers/firmware/arm_scmi/driver.c | 31 ++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-)
drivers/firmware/arm_scmi/driver.c +23 -8
@@ -2506,21 +2506,31 @@ static int scmi_handle_put(const struct scmi_handle *handle)return 0 ; } -static void scmi_device_link_add (struct device *consumer, +static bool scmi_device_link_add (struct device *consumer,struct device *supplier) {struct device_link *link; link =device_link_add (consumer, supplier,DL_FLAG_AUTOREMOVE_CONSUMER ); -WARN_ON (!link); +return !WARN_ON (!link); +} + +static void scmi_clear_handle (struct scmi_device *scmi_dev) +{ +if (!scmi_dev->handle) +return ; + +scmi_handle_put (scmi_dev->handle); + scmi_dev->handle =NULL ; }static void scmi_set_handle (struct scmi_device *scmi_dev) { scmi_dev->handle =scmi_handle_get (&scmi_dev->dev); -if (scmi_dev->handle) -scmi_device_link_add (&scmi_dev->dev, scmi_dev->handle->dev); +if (scmi_dev->handle && + !scmi_device_link_add (&scmi_dev->dev, scmi_dev->handle->dev)) +scmi_clear_handle (scmi_dev); } static int __scmi_xfer_info_init(struct scmi_info *sinfo,
@@ -2802,6 +2812,7 @@ static int scmi_bus_notifier(struct notifier_block *nb, {struct scmi_info *info =bus_nb_to_scmi_info (nb);struct scmi_device *sdev =to_scmi_dev (data); +const char *status;/* Skip transport devices and devices of different SCMI instances */ if (!strncmp(sdev->name, "__scmi_transport_device", 23) ||
@@ -2812,18 +2823,22 @@ static int scmi_bus_notifier(struct notifier_block *nb,case BUS_NOTIFY_BIND_DRIVER :/* setup handle now as the transport is ready */ scmi_set_handle (sdev); + status ="about to be BOUND." ; +break ; +case BUS_NOTIFY_DRIVER_NOT_BOUND : +scmi_clear_handle (sdev); + status ="NOT BOUND." ;break ;case BUS_NOTIFY_UNBOUND_DRIVER : -scmi_handle_put (sdev->handle); - sdev->handle =NULL ; +scmi_clear_handle (sdev); + status ="UNBOUND." ;break ;default :return NOTIFY_DONE ; }dev_dbg (info->dev,"Device %s (%s) is now %s\n" ,dev_name (&sdev->dev), - sdev->name, action ==BUS_NOTIFY_BIND_DRIVER ? -"about to be BOUND." :"UNBOUND." ); + sdev->name, status);return NOTIFY_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 543/1376 firmware: arm_scmi: Unwind TX receiver mailbox setup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 6f7c06744d53dc8e047725d411d7f915d9ec35ae ]
mailbox_chan_setup() can request an additional unidirectional TX receiver channel after successfully acquiring the primary channel. If that second request fails, the function returns immediately and leaves the primary channel allocated.
Unwind the primary mailbox channel before returning the error so probe deferral or other setup failures do not leave the channel busy for later probe attempts.
--- drivers/firmware/arm_scmi/transports/mailbox.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/firmware/arm_scmi/transports/mailbox.c +4 -1
@@ -227,9 +227,10 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, smbox->chan_receiver =mbox_request_channel (cl, a2p_rx_chan);if (IS_ERR (smbox->chan_receiver)) { ret =PTR_ERR (smbox->chan_receiver); + smbox->chan_receiver =NULL ;if (ret != -EPROBE_DEFER )dev_err (cdev,"failed to request SCMI Tx Receiver mailbox\n" ); -return ret; + goto err_free_chan; } }
@@ -245,6 +246,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,return 0 ; +err_free_chan: +mbox_free_channel (smbox->chan); err_clear_cinfo: cinfo->transport_info =NULL ; smbox->cinfo =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 544/1376 firmware: arm_scmi: Unwind P2A receiver mailbox setup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit f3e3773c4e5e96549d7540d8ddeb4fcd534f6f1d ]
mailbox_chan_setup() can request an additional P2A receiver channel after successfully acquiring the primary P2A channel. If that later request fails, the function returns immediately and leaves the primary channel allocated.
Unwind the primary mailbox channel before returning the error so probe deferral or other setup failures do not leave the channel busy for later probe attempts.
--- drivers/firmware/arm_scmi/transports/mailbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/firmware/arm_scmi/transports/mailbox.c +2 -1
@@ -238,9 +238,10 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, smbox->chan_platform_receiver =mbox_request_channel (cl, p2a_rx_chan);if (IS_ERR (smbox->chan_platform_receiver)) { ret =PTR_ERR (smbox->chan_platform_receiver); + smbox->chan_platform_receiver =NULL ;if (ret != -EPROBE_DEFER )dev_err (cdev,"failed to request SCMI P2A Receiver mailbox\n" ); -return ret; + goto err_free_chan; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 545/1376 libnvdimm/labels: Bound the on-media label size before the shift
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit 18f9124248ed7a9da1c31973b629dceef76a9b0c ]
For a v1.2+ index, __nd_label_validate() computes the label size as 1 << (7 + nsindex[i]->labelsize), where labelsize is a u8 read from the label storage medium. A value of 25 or more makes the shift count reach or exceed the width of int -- undefined behavior -- and 24 already shifts into the sign bit. Only 0 (128-byte) and 1 (256-byte) are valid.
Reject a labelsize above 1 before the shift. The result was rejected by the following size comparison anyway, so this only removes the undefined shift on a crafted or corrupted medium; conforming labels are unaffected.
--- drivers/nvdimm/label.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/nvdimm/label.c +13 -2
@@ -145,10 +145,21 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd)/* label sizes larger than 128 arrived with v1.2 */ version =__le16_to_cpu (nsindex[i]->major) *100 +__le16_to_cpu (nsindex[i]->minor); -if (version >=102 ) +if (version >=102 ) { +/* +* labelsize feeds the shift below; only 0 (128-byte) +* and 1 (256-byte) are valid -- a larger value would +* overflow or exceed the width of int. +*/ +if (nsindex[i]->labelsize >1 ) { +dev_dbg (dev,"nsindex%d labelsize: %d invalid\n" , + i, nsindex[i]->labelsize); +continue ; + } labelsize =1 << (7 + nsindex[i]->labelsize); -else + }else { labelsize =128 ; + }if (labelsize !=sizeof_namespace_label (ndd)) { dev_dbg(dev, "nsindex%d labelsize %d invalid\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 546/1376 dax: read holder_ops once in dax_holder_notify_failure()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Groves <[email protected]>
[ Upstream commit 7ae9d15bdcde0f2955ae13b6a95587f9e23b2359 ]
dax_holder_notify_failure() reads dax_dev->holder_ops twice without READ_ONCE() -- once for the NULL check and once for the indirect notify_failure() call. A concurrent fs_put_dax() can clear holder_ops between the two reads, so the check can observe a non-NULL pointer while the call dereferences NULL. (kill_dax() also clears holder_ops, but only after synchronize_srcu(), so it cannot race a reader that is inside dax_read_lock(); fs_put_dax() does no such synchronization.)
Fetch holder_ops once into a local with READ_ONCE() so the NULL check and the indirect call observe the same value.
--- drivers/dax/super.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/dax/super.c +10 -2
@@ -233,6 +233,7 @@ EXPORT_SYMBOL_GPL(dax_recovery_write);int dax_holder_notify_failure (struct dax_device *dax_dev,u64 off,u64 len,int mf_flags) { +const struct dax_holder_operations *ops;int rc, id; id =dax_read_lock ();
@@ -241,12 +242,19 @@ int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off, goto out; } -if (!dax_dev->holder_ops) { +/* +* Read holder_ops once: a concurrent fs_put_dax() can clear it without +* synchronizing against readers. Without the single fetch the compiler +* could reload between the NULL check and the call and dereference a +* NULL ops. +*/ + ops =READ_ONCE (dax_dev->holder_ops); +if (!ops) { rc = -EOPNOTSUPP ; goto out; } - rc = dax_dev->holder_ops->notify_failure (dax_dev, off, len, mf_flags); + rc = ops->notify_failure (dax_dev, off, len, mf_flags); out:dax_read_unlock (id);return rc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 547/1376 cpufreq: spear: Fix an IS_ERR() vs NULL bug in spear1340_set_cpu_rate()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 6a9e0e0f7592313ace66303cf5eca68e04c10f30 ]
The clk_get_parent() function doesn't return error pointers, it returns NULL on error. Update the error checking to match.
--- drivers/cpufreq/spear-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/cpufreq/spear-cpufreq.c +2 -2
@@ -79,9 +79,9 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq)int ret =0 ; sys_clk =clk_get_parent (spear_cpufreq.clk); -if (IS_ERR (sys_clk)) { +if (!sys_clk) {pr_err ("failed to get cpu's parent (sys) clock\n" ); -return PTR_ERR (sys_clk); +return -EINVAL ; }/* Set the rate of the source clock before changing the parent */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 548/1376 PCI: xgene: Drop XGENE_PCIE_IP_VER_UNKN
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
[ Upstream commit fddf72ed7b52c91da37fe5f1d4faed11251b714f ]
XGENE_PCIE_IP_VER_UNKN is only refered to when probing for the original XGene PCIe implementation, and get immediately overridden if the device has the "apm,xgene-pcie" compatible string.
Given that the only way to get there is by finding this very string in the DT, it is obvious that we will always overwrite the version with XGENE_PCIE_IP_VER_1.
Drop the whole thing.
Stable-dep-of: 4869db344e76 ("PCI: xgene: Drop unnecessary OF node reference")
--- drivers/pci/controller/pci-xgene.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/pci/controller/pci-xgene.c +1 -5
@@ -53,7 +53,6 @@#define XGENE_V1_PCI_EXP_CAP 0x40/* PCIe IP version */ -#define XGENE_PCIE_IP_VER_UNKN 0#define XGENE_PCIE_IP_VER_1 1#define XGENE_PCIE_IP_VER_2 2
@@ -610,10 +609,7 @@ static int xgene_pcie_probe(struct platform_device *pdev) port->node =of_node_get (dn); port->dev = dev; - - port->version =XGENE_PCIE_IP_VER_UNKN ; -if (of_device_is_compatible (port->node,"apm,xgene-pcie" )) - port->version =XGENE_PCIE_IP_VER_1 ; + port->version =XGENE_PCIE_IP_VER_1 ; ret =xgene_pcie_map_reg (port, pdev);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 549/1376 PCI: xgene: Drop unnecessary OF node reference
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 4869db344e76c9adfb1d9654df442db5371fac71 ]
xgene_pcie_probe() stores dev->of_node in port->node with of_node_get(), but the cached node is only used during probe by xgene_pcie_parse_map_dma_ranges(). The driver never releases the extra reference, so the node reference is leaked.
There is no need for private OF node ownership here. Use the device's existing of_node directly in xgene_pcie_parse_map_dma_ranges() and remove the cached port->node pointer.
--- drivers/pci/controller/pci-xgene.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/pci/controller/pci-xgene.c +1 -4
@@ -58,7 +58,6 @@ #if defined(CONFIG_PCI_XGENE) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) struct xgene_pcie { - struct device_node *node; struct device *dev; struct clk *clk; void __iomem *csr_base;
@@ -528,7 +527,7 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie *port,static int xgene_pcie_parse_map_dma_ranges (struct xgene_pcie *port) { -struct device_node *np = port->node; +struct device_node *np = port->dev->of_node;struct of_pci_range range;struct of_pci_range_parser parser;struct device *dev = port->dev;
@@ -596,7 +595,6 @@ static struct pci_ops xgene_pcie_ops = {static int xgene_pcie_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev; -struct device_node *dn = dev->of_node;struct xgene_pcie *port;struct pci_host_bridge *bridge;int ret;
@@ -607,7 +605,6 @@ static int xgene_pcie_probe(struct platform_device *pdev) port =pci_host_bridge_priv (bridge); - port->node =of_node_get (dn); port->dev = dev; port->version =XGENE_PCIE_IP_VER_1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 550/1376 irqchip/renesas-irqc: Fix generic interrupt chip leak on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingshuang Fu <[email protected]>
[ Upstream commit 616dd89d81ad9a3cf1cfff4088a4c43e4e00d6ba ]
The driver allocates domain generic chips probe. However, on driver removal, the generic chips are not automatically freed when the interrupt domain is removed because the domain flags do not include IRQ_DOMAIN_FLAG_DESTROY_GC.
This causes both the domain generic chips structure and the associated generic chips to be leaked. Additionally, the generic chips remain on the global list and may later be accessed by generic interrupt chip suspend, resume, or shutdown callbacks after the driver has been removed, potentially resulting in a use-after-free and kernel crash.
Fix the resource leak by setting IRQ_DOMAIN_FLAG_DESTROY_GC on the interrupt domain; this lets the interrupt domain core automatically release all generic chips when irq_domain_remove() is invoked, removing the need for manual cleanup calls in error paths and remove callback.
--- drivers/irqchip/irq-renesas-irqc.c | 1 + 1 file changed, 1 insertion(+)
drivers/irqchip/irq-renesas-irqc.c +1 -0
@@ -176,6 +176,7 @@ static int irqc_probe(struct platform_device *pdev) goto err_runtime_pm_disable; } + p->irq_domain->flags |=IRQ_DOMAIN_FLAG_DESTROY_GC ; ret =irq_alloc_domain_generic_chips (p->irq_domain, p->number_of_irqs,1 ,"irqc" , handle_level_irq,0 ,0 ,IRQ_GC_INIT_NESTED_LOCK );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 551/1376 media: i2c: rdacm21: Fix missing media_entity_cleanup()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biren Pandya <[email protected]>
[ Upstream commit 04c053379c3a33460b581953c4f5b36de39439ac ]
The driver misses calling media_entity_cleanup() on the probe error path and during remove, leaking resources if probe fails after entity initialization or when the driver is unloaded.
Fix this by adding media_entity_cleanup() to the rdacm21_probe() error handling path and to rdacm21_remove().
--- drivers/media/i2c/rdacm21.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/media/i2c/rdacm21.c +4 -1
@@ -589,10 +589,12 @@ static int rdacm21_probe(struct i2c_client *client) ret =v4l2_async_register_subdev (&dev->sd);if (ret) - goto error_free_ctrls; + goto error_entity_cleanup;return 0 ; +error_entity_cleanup: +media_entity_cleanup (&dev->sd.entity); error_free_ctrls:v4l2_ctrl_handler_free (&dev->ctrls); error:
@@ -607,6 +609,7 @@ static void rdacm21_remove(struct i2c_client *client)v4l2_async_unregister_subdev (&dev->sd);v4l2_ctrl_handler_free (&dev->ctrls); +media_entity_cleanup (&dev->sd.entity);i2c_unregister_device (dev->isp); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 552/1376 media: bcm2835-unicam: Fix asc leaked in error/remove path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugen Hristev <[email protected]>
[ Upstream commit 253c9659e25131b0169f718e7d094ac1aa0d9279 ]
v4l2_async_nf_add_fwnode_remote() allocates the asc, which is freed when v4l2_async_nf_cleanup() is called.
Call v4l2_async_nf_cleanup() properly in the driver paths.
Discovered with kmemleak after rmmod:
unreferenced object 0xffff000084526b80 (size 64):
comm "modprobe", pid 185, jiffies 4295013512
hex dump (first 32 bytes):
01 00 00 00 00 00 00 00 e8 0d ff bf 00 00 ff ff ................
40 83 bc 84 00 00 ff ff 60 83 bc 84 00 00 ff ff @.......`.......
backtrace (crc ac584083):
[<00000000ffb081a7>] kmemleak_alloc+0x38/0x44
[<00000000d2fd9301>] __kmalloc+0x1b0/0x250
[<000000004dd5354d>] __v4l2_async_nf_add_fwnode+0x28/0x9c
[<0000000067587657>] __v4l2_async_nf_add_fwnode_remote+0x3c/0x64--- drivers/media/platform/broadcom/bcm2835-unicam.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/platform/broadcom/bcm2835-unicam.c +2 -0
@@ -2570,6 +2570,7 @@ static int unicam_async_nf_init(struct unicam_device *unicam)return 0 ; error: +v4l2_async_nf_cleanup (&unicam->notifier);fwnode_handle_put (ep_handle);return ret; }
@@ -2702,6 +2703,7 @@ static void unicam_remove(struct platform_device *pdev)v4l2_device_unregister (&unicam->v4l2_dev);media_device_unregister (&unicam->mdev);v4l2_async_nf_unregister (&unicam->notifier); +v4l2_async_nf_cleanup (&unicam->notifier);unicam_subdev_cleanup (unicam);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 553/1376 media: ipu6: Do not free aux device pdata after init
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 9be07216af4cfc4813e1a46ce26407d31ea845de ]
ipu6_bus_initialize_device() stores the isys/psys pdata pointer in struct ipu6_bus_device and initializes the auxiliary device. After that point, error unwinding must drop the auxiliary device reference and let ipu6_bus_release() free both the bus device and adev->pdata.
The isys and psys init paths already call put_device() when MMU initialization fails, and ipu6_bus_add_device() calls auxiliary_device_uninit() on auxiliary_device_add() failure. Both paths therefore run the bus release callback. The extra kfree(pdata) in the callers can release the same object a second time.
Remove the manual pdata frees after the auxiliary device has been initialized.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/media/pci/intel/ipu6/ipu6.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/media/pci/intel/ipu6/ipu6.c +2 -8
@@ -399,7 +399,6 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant);if (IS_ERR (isys_adev->mmu)) {put_device (&isys_adev->auxdev.dev); -kfree (pdata);return dev_err_cast_probe (dev, isys_adev->mmu,"ipu6_mmu_init(isys_adev->mmu) failed\n" ); }
@@ -407,10 +406,8 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, isys_adev->mmu->dev = &isys_adev->auxdev.dev; ret =ipu6_bus_add_device (isys_adev); -if (ret) { -kfree (pdata); +if (ret)return ERR_PTR (ret); - }return isys_adev; }
@@ -443,7 +440,6 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant);if (IS_ERR (psys_adev->mmu)) {put_device (&psys_adev->auxdev.dev); -kfree (pdata);return dev_err_cast_probe (&pdev->dev, psys_adev->mmu,"ipu6_mmu_init(psys_adev->mmu) failed\n" ); }
@@ -451,10 +447,8 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, psys_adev->mmu->dev = &psys_adev->auxdev.dev; ret =ipu6_bus_add_device (psys_adev); -if (ret) { -kfree (pdata); +if (ret)return ERR_PTR (ret); - }return psys_adev; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 554/1376 drm/amd/display: Remove unused-but-set variable hubp from
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gleb Markov <[email protected]>
[ Upstream commit b736792e5bd4a62f24e8d1e310bf4a75bfbeaaaa ]
The final check of hubp for NULL covers all remaining lines of code, since the value of hubp does not change until the end of the method.
This check is redundant because hubp1 is already dereferenced within the macro.
If it were NULL, the program would have already failed to proceed.
Remove the left part of the expression with the logical "&&".
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c +1 -2
@@ -755,8 +755,7 @@ bool hubp1_is_flip_pending(struct hubp *hubp)if (flip_pending)return true; -if (hubp && - earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) +if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part)return true;return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 555/1376 cpufreq: intel_pstate: Fix setting minimum P-state at init time
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit db53c573d31d07d5d782c5312d37cb33be788eba ]
If HWP is enabled, writes to MSR_IA32_PERF_CTL have no effect, so intel_pstate_get_cpu_pstates() should not attempt to call intel_pstate_set_min_pstate() to set the minimum P-state for the given CPU in that case.
Accordingly, remove the intel_pstate_set_min_pstate() call from intel_pstate_get_cpu_pstates() and make both intel_pstate_cpu_init() and intel_cpufreq_cpu_init() call that function in their non-HWP code paths.
The HWP code path in intel_pstate_cpu_init() does not need to update the current P-state of the CPU directly at all because it is taken care of the processor automatically, but the HWP code path of intel_cpufreq_cpu_init() should update it in principle to initialize the DESIRED_PERF field in MSR_HWP_REQUEST. For this purpose, make it call intel_cpufreq_hwp_update() and pass the minimum P-state limit to it as the current target value along with the current minimum and maximum limits.
--- drivers/cpufreq/intel_pstate.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
drivers/cpufreq/intel_pstate.c +11 -8
@@ -2300,8 +2300,6 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)if (pstate_funcs.get_vid) pstate_funcs.get_vid (cpu); - -intel_pstate_set_min_pstate (cpu); }/*
@@ -3008,6 +3006,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)static int intel_pstate_cpu_init (struct cpufreq_policy *policy) {int ret =__intel_pstate_cpu_init (policy); +struct cpudata *cpu;if (ret)return ret;
@@ -3018,11 +3017,11 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)*/ policy->policy =CPUFREQ_POLICY_POWERSAVE ; -if (hwp_active) { -struct cpudata *cpu = all_cpu_data[policy->cpu]; - + cpu = all_cpu_data[policy->cpu]; +if (hwp_active) cpu->epp_cached =intel_pstate_get_epp (cpu,0 ); - } +else +intel_pstate_set_min_pstate (cpu);return 0 ; }
@@ -3246,8 +3245,6 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)return ret; policy->cpuinfo.transition_latency =INTEL_CPUFREQ_TRANSITION_LATENCY ; -/* This reflects the intel_pstate_get_cpu_pstates() setting. */ - policy->cur = policy->cpuinfo.min_freq; req =kcalloc (2 ,sizeof (*req),GFP_KERNEL );if (!req) {
@@ -3268,9 +3265,15 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)WRITE_ONCE (cpu->hwp_req_cached, value); cpu->epp_cached =intel_pstate_get_epp (cpu, value); + +intel_cpufreq_hwp_update (cpu, cpu->pstate.min_pstate, + cpu->pstate.max_pstate, + cpu->pstate.min_pstate, false); }else { policy->transition_delay_us =INTEL_CPUFREQ_TRANSITION_DELAY ; +intel_pstate_set_min_pstate (cpu); } + policy->cur = policy->cpuinfo.min_freq; freq =DIV_ROUND_UP (cpu->pstate.turbo_freq * global.min_perf_pct,100 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 556/1376 cpufreq: schedutil: Fix self-contradictory comment in sugov_iowait_apply()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhongqiu Han <[email protected]>
[ Upstream commit db6a017c91b774c15b1b890db45981eacfff540e ]
The kerneldoc of sugov_iowait_apply() says the IO boost value is increased in sugov_iowait_apply() and, in the same sentence, that it is decreased by the same function. That is self-contradictory, and the first part is wrong:sugov_iowait_apply() only decreases the boost.
The boost is actually increased in sugov_iowait_boost(). Fix the comment to name sugov_iowait_boost() as the place where the boost is increased, so it matches the code.
No functional change.
--- kernel/sched/cpufreq_schedutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/cpufreq_schedutil.c +1 -1
@@ -320,7 +320,7 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,* A CPU running a task which woken up after an IO operation can have its * utilization boosted to speed up the completion of those IO operations. * The IO boost value is increased each time a task wakes up from IO, in -* sugov_iowait_apply(), and it's instead decreased by this function, +* sugov_iowait_boost(), and it's instead decreased by this function, * each time an increase has not been requested (!iowait_boost_pending). * * A CPU which also appears to have been idle for at least one tick has also
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 557/1376 remoteproc: qcom: Fix glink->node reference leak in qcom_add_glink_subdev
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
[ Upstream commit 44f4911ab8e6f4d69afad5f2571bbd2da421c918 ]
In qcom_add_glink_subdev(), the device node reference acquired via of_get_child_by_name() is stored in glink->node. If the subsequent kstrdup_const() allocation for glink->ssr_name fails, the function returns early without calling of_node_put() on glink->node, leaking the reference count.
Fix this by adding of_node_put(glink->node) on the error path before returning.
--- drivers/remoteproc/qcom_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/remoteproc/qcom_common.c +3 -1
@@ -242,8 +242,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,return ; glink->ssr_name =kstrdup_const (ssr_name,GFP_KERNEL ); -if (!glink->ssr_name) +if (!glink->ssr_name) { +of_node_put (glink->node);return ; + } glink->dev = dev; glink->subdev.start = glink_subdev_start;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 558/1376 drm/bridge: tc358767: clamp the reported AUX read size to the request
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
[ Upstream commit ec6444a00c49e6c2b5e9a507272a28126677f9ee ]
tc_aux_transfer() clamps an AUX read to the payload limit:
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
After the transfer it replaces size with the byte count the controller reports in AUX_BYTES:
if (size) size = FIELD_GET(AUX_BYTES, auxstatus);
AUX_BYTES is GENMASK(15, 8), so it can be up to 255. Nothing clamps it back to the request. tc_aux_read_data() reads that many bytes into the 16-byte auxrdata stack buffer, then copies them into the caller buffer. A reported count of 255 makes the read run to 256 bytes and overruns both.
The controller should never report more than it was asked to transfer, so this is defense in depth rather than a live hole. The reported count is only lightly trusted, and the check is cheap. Clamp it back to the request, the same way ti-sn65dsi86 does in commit aca58eac52b8 ("drm/bridge:
ti-sn65dsi86: Never store more than msg->size bytes in AUX xfer").
--- drivers/gpu/drm/bridge/tc358767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/bridge/tc358767.c +1 -1
@@ -519,7 +519,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,* address-only transfer */ if (size) - size =FIELD_GET (AUX_BYTES , auxstatus); + size =min_t (size_t, size,FIELD_GET (AUX_BYTES , auxstatus)); msg->reply =FIELD_GET (AUX_STATUS , auxstatus);switch (request) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 559/1376 arm64: dts: qcom: msm8996-xiaomi-gemini: Fix up ti,drv2604 enable GPIO
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 569413a98a1761782a0770aa85d20a2c78893279 ]
Update the 'enable-gpio' property name to 'enable-gpios' to conform to the bindings for the TI DRV2604 haptics module. While at it, use the GPIO_ACTIVE_HIGH define instead of the raw literal.
--- arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts +1 -1
@@ -39,7 +39,7 @@ &blsp2_i2c3 { haptics: drv2604@5a { compatible = "ti,drv2604"; reg = <0x5a>; - enable-gpio = <&tlmm 93 0x00>; + enable-gpios = <&tlmm 93 GPIO_ACTIVE_HIGH>; mode = <DRV260X_LRA_MODE>; library-sel = <DRV260X_LIB_LRA>; pinctrl-names = "default","sleep";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 560/1376 arm64: dts: qcom: sc8280xp-x13s: Fix the drive-strength of mclk pin
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengyu Luo <[email protected]>
[ Upstream commit 09531bb8e0de5081fdbe215877dd7f2ec8b2f0e1 ]
The value can be retrieve via windbg on Windows.
lkd> !dd f111000 L8
ctl_reg => 0x284
in drivers/pinctrl/qcom/pinctrl-msm.c
function msm_gpio_dbg_show_one()
...
drive = (ctl_reg >> g->drv_bit) & 7; // (0x284 >> 6) & 7 == 2
...seq_printf(s, " %dmA", msm_regval_to_drive(drive)); // (drive + 1) * 2 == 6;
...
So the value is 6, not 16, it matches Windows now.
--- arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +1 -1
@@ -1488,7 +1488,7 @@ cam_rgb_default: cam-rgb-default-state { mclk-pins { pins = "gpio17"; function = "cam_mclk"; - drive-strength = <16>; + drive-strength = <6>; bias-disable; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 561/1376 arm64: dts: qcom: sm8250: sort out Iris power domains
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit d5c8efda722eb1f67cfe299b71f13dab93746934 ]
On SM8250 Iris core requires two power rails to function, MX (for PLLs) and MMCX (for everything else). The commit fa245b3f06cd ("arm64: dts:
qcom: sm8250: Add venus DT node") added only MX power rail, but omitted MMCX voltage levels.
Add MMCX domain to the Iris device node.
--- arch/arm64/boot/dts/qcom/sm8250.dtsi | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
arch/arm64/boot/dts/qcom/sm8250.dtsi +14 -6
@@ -4310,8 +4310,12 @@ venus: video-codec@aa00000 { interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; power-domains = <&videocc MVS0C_GDSC>, <&videocc MVS0_GDSC>, - <&rpmhpd RPMHPD_MX>; - power-domain-names = "venus", "vcodec0", "mx"; + <&rpmhpd RPMHPD_MX>, + <&rpmhpd RPMHPD_MMCX>; + power-domain-names = "venus", + "vcodec0", + "mx", + "mmcx"; operating-points-v2 = <&venus_opp_table>; clocks = <&gcc GCC_VIDEO_AXI0_CLK>,
@@ -4345,22 +4349,26 @@ venus_opp_table: opp-table { opp-720000000 { opp-hz = /bits/ 64 <720000000>; - required-opps = <&rpmhpd_opp_low_svs>; + required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_low_svs>; }; opp-1014000000 { opp-hz = /bits/ 64 <1014000000>; - required-opps = <&rpmhpd_opp_svs>; + required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs>; }; opp-1098000000 { opp-hz = /bits/ 64 <1098000000>; - required-opps = <&rpmhpd_opp_svs_l1>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs_l1>; }; opp-1332000000 { opp-hz = /bits/ 64 <1332000000>; - required-opps = <&rpmhpd_opp_nom>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; }; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 562/1376 arm64: dts: qcom: sm8250: correct frequencies in the Iris OPP table
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit 68ea007df9293fcb29d38219d73094bbf4b59673 ]
The OPP table for the Iris core is wrong, it copies the VDD table from the downstream kernel, but that table is written for the video_cc_mvs0_clk_src, while the upstream uses video_cc_mvs0_clk for OPP rate setting (which is clk_src divided by 3). Specify correct frequencies in the OPP table.
--- arch/arm64/boot/dts/qcom/sm8250.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
arch/arm64/boot/dts/qcom/sm8250.dtsi +8 -8
@@ -4347,26 +4347,26 @@ video-encoder { venus_opp_table: opp-table { compatible = "operating-points-v2"; - opp-720000000 { - opp-hz = /bits/ 64 <720000000>; + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; required-opps = <&rpmhpd_opp_svs>, <&rpmhpd_opp_low_svs>; }; - opp-1014000000 { - opp-hz = /bits/ 64 <1014000000>; + opp-338000000 { + opp-hz = /bits/ 64 <338000000>; required-opps = <&rpmhpd_opp_svs>, <&rpmhpd_opp_svs>; }; - opp-1098000000 { - opp-hz = /bits/ 64 <1098000000>; + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; required-opps = <&rpmhpd_opp_svs_l1>, <&rpmhpd_opp_svs_l1>; }; - opp-1332000000 { - opp-hz = /bits/ 64 <1332000000>; + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; required-opps = <&rpmhpd_opp_svs_l1>, <&rpmhpd_opp_nom>; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 563/1376 perf jevents: Add more components to the metric sorting order
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 557f8b3ca8c8e58d5bc3084734bc7a470b043922 ]
Nazar Kazakov reported non-deterministic builds due to the metrics being reordered in the jevents.py output. The metrics were largely only being sorted by name, add in the expressions and descriptions.
--- tools/perf/pmu-events/jevents.py | 5 +++-- tools/perf/pmu-events/metric.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-)
tools/perf/pmu-events/jevents.py +3 -2
@@ -540,13 +540,14 @@ const struct pmu_table_entry {_pending_events_tblname}[] = {{ def print_pending_metrics() -> None: """Optionally close metrics table.""" - def metric_cmp_key(j: JsonEvent) -> Tuple[bool, str, str]: + def metric_cmp_key(j: JsonEvent) -> Tuple[str, str, str, str]: def fix_none(s: Optional[str]) -> str: if s is None: return '' return s - return (j.desc is not None, fix_none(j.pmu), fix_none(j.metric_name)) + return (fix_none(j.pmu), fix_none(j.metric_name), j.metric_expr.ToPerfJson(), + fix_none(j.desc)) global _pending_metrics if not _pending_metrics:
tools/perf/pmu-events/metric.py +5 -1
@@ -445,7 +445,11 @@ class Metric: def __lt__(self, other): """Sort order.""" - return self.name < other.name + if self.name != other.name: + return self.name < other.name + if not self.expr.Equals(other.expr): + return self.expr.ToPerfJson() < other.expr.ToPerfJson() + return self.description < other.description def AddToMetricGroup(self, group): """Callback used when being added to a MetricGroup."""
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 564/1376 wifi: iwlwifi: fix counter type in iwl_fwrt_dump_error_logs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 71e67b4b59337b2f9f4fef976a27de2dad7aabf2 ]
The loop counter 'count' was declared as u8 while num_pc is u32. If firmware advertises more than 255 PC entries the counter wraps back to zero and the loop never terminates potentially causing an infinite loop or reading past the allocated pc_data array.
Change the declaration to u32 to match num_pc.
--- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/fw/dump.c +1 -1
@@ -488,7 +488,7 @@ static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)void iwl_fwrt_dump_error_logs (struct iwl_fw_runtime *fwrt) {struct iwl_pc_data *pc_data; -u8 count; +u32 count;if (!test_bit (STATUS_DEVICE_ENABLED , &fwrt->trans->status)) { IWL_ERR(fwrt,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 565/1376 wifi: iwlwifi: mvm: fix off-by-one in TXF key sanitiser
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit f6a6c01cbc046f68e6916a7e047a1bc881c8c9ab ]
iwl_mvm_frob_txf_key_iter() tracks the last matched byte position in loop variable 'i'. When a full key match is found (match == keylen), 'i' points at the last byte of the matched key. The memset start offset should therefore be i + 1 - keylen, not i - keylen; the current code zeroes one byte before the match and leaves the final key byte un-sanitised.
--- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mvm/ops.c +1 -1
@@ -1010,7 +1010,7 @@ static void iwl_mvm_frob_txf_key_iter(struct ieee80211_hw *hw, } match++;if (match == keylen) { -memset (txf->buf + i - keylen,0xAA , keylen); +memset (txf->buf + i +1 - keylen,0xAA , keylen); match =0 ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 566/1376 wifi: iwlwifi: mei: check SAP message length before reading it
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avraham Stern <[email protected]>
[ Upstream commit 7d8cc301bcba233f31b589a45f4c1c97f2bb90d6 ]
Verify the SAP message size is not larger than the local buffer before reading the message to avoid buffer overflow.
--- drivers/net/wireless/intel/iwlwifi/mei/main.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/wireless/intel/iwlwifi/mei/main.c +6 -0
@@ -1,6 +1,7 @@// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2021-2024 Intel Corporation +* Copyright (C) 2026 Intel Corporation */ #include <linux/etherdevice.h>
@@ -1147,6 +1148,11 @@ static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev,iwl_mei_read_from_q (q_head, q_sz, &rd, wr, hdr,sizeof (*hdr)); valid_rx_sz -=sizeof (*hdr); len =le16_to_cpu (hdr->len); +if (len +sizeof (*hdr) >PAGE_SIZE ) { +dev_err (&cldev->dev, +"SAP message is too big: %u\n" , len); +break ; + }if (valid_rx_sz < len)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 567/1376 wifi: iwlwifi: guard against division by zero in iwl_dbg_tlv_alloc_fragments
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit 9318bc0c41b24705690cf80d1596cf6b711e7027 ]
Make sure we don't end-up with a num_frags = 0 situation. For that, check that the required size is not 0 and put a checker on num_frags as well.
--- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +7 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* -* Copyright (C) 2018-2025 Intel Corporation +* Copyright (C) 2018-2026 Intel Corporation */ #include <linux/firmware.h> #include "iwl-drv.h"
@@ -602,6 +602,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))return 0 ; +if (!fw_mon_cfg->req_size) +return -EIO ; + num_frags =le32_to_cpu (fw_mon_cfg->max_frags_num);if (fwrt->trans->trans_cfg->device_family <IWL_DEVICE_FAMILY_AX210 ) {if (alloc_id !=IWL_FW_INI_ALLOCATION_ID_DBGC1 )
@@ -612,6 +615,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,return -EIO ; } +if (!num_frags) +return -EIO ; + remain_pages =DIV_ROUND_UP (le32_to_cpu (fw_mon_cfg->req_size),PAGE_SIZE ); num_frags =min_t (u32, num_frags,BUF_ALLOC_MAX_NUM_FRAGS );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 568/1376 wifi: iwlwifi: mei: pass correct argument to function
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avraham Stern <[email protected]>
[ Upstream commit 905f57aefde4f4092a411c8a55856182fb1c7598 ]
The first argument to iwl_mei_write_cyclic_buf() should be the cldev but the q_head pointer is passed instead. Fix it.
--- drivers/net/wireless/intel/iwlwifi/mei/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mei/main.c +1 -1
@@ -458,7 +458,7 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev, notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF ]; q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME ][SAP_QUEUE_IDX_NOTIF ]; q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME ][SAP_QUEUE_IDX_NOTIF ]; - ret =iwl_mei_write_cyclic_buf (q_head, notif_q, q_head, hdr, q_sz); + ret =iwl_mei_write_cyclic_buf (cldev, notif_q, q_head, hdr, q_sz);if (ret <0 )return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 569/1376 gpu: host1x: Fix offset calculation in trace_write_gather
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikko Perttunen <[email protected]>
[ Upstream commit eb896850964d3dfce291b4fdff9c2d42d85e564b ]
When a gather longer than 2*TRACE_MAX_LENGTH (256) words is traced through host1x_cdma_push_gather, the reported BO offset drifts from the third iteration onward.
Fix the calculation by properly calculating the value on each loop rather than accumulating.
In reality, gathers tend to be pretty short so this is unlikely to ever have been observed.
--- drivers/gpu/host1x/hw/channel_hw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/gpu/host1x/hw/channel_hw.c +2 -3
@@ -36,10 +36,9 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,for (i =0 ; i < words; i +=TRACE_MAX_LENGTH ) {u32 num_words =min (words - i,TRACE_MAX_LENGTH ); - offset += i *sizeof (u32); -trace_host1x_cdma_push_gather (dev_name (dev), bo, - num_words, offset, + num_words, + offset + i *sizeof (u32), mem); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 570/1376 gpu: host1x: Avoid stack over-read in debug output helpers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikko Perttunen <[email protected]>
[ Upstream commit bc17ac285fb708f22a8fa2c0ed32eceb1d37e6d6 ]
host1x_debug_output() and host1x_debug_cont() used vsnprintf(), which returns the length the formatted string would have reached with an unbounded buffer. That return value was passed straight to o->fn as the number of bytes to emit.
This could cause a read past end of the output buffer if a call to host1x_debug_* produced a string longer than 256 bytes. This only affected the debugfs files as the printk debug sink ignores the number of bytes. In practice, this is very unlikely to occur.
Fix by switching to vscnprintf(), which returns the number of bytes actually written.
--- drivers/gpu/host1x/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/host1x/debug.c +2 -2
@@ -31,7 +31,7 @@ void host1x_debug_output(struct output *o, const char *fmt, ...)int len;va_start (args, fmt); - len =vsnprintf (o->buf,sizeof (o->buf), fmt, args); + len =vscnprintf (o->buf,sizeof (o->buf), fmt, args);va_end (args); o->fn (o->ctx, o->buf, len, false);
@@ -43,7 +43,7 @@ void host1x_debug_cont(struct output *o, const char *fmt, ...)int len;va_start (args, fmt); - len =vsnprintf (o->buf,sizeof (o->buf), fmt, args); + len =vscnprintf (o->buf,sizeof (o->buf), fmt, args);va_end (args); o->fn (o->ctx, o->buf, len, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 571/1376 drm/msm/a6xx: Fix stale rpmh votes after suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivam Rawat <[email protected]>
[ Upstream commit d9108bfdb746edacdb05bd27959a4ae63c6c7f3f ]
There are stale RPMH votes (BCM votes) observed after GMU suspend. This is because the rpmh stop sequences are skipped during gmu suspend. Fix this and also move GMU to reset state to avoid any further activity.
Patchwork: https://patchwork.freedesktop.org/patch/730652/
Message-ID: <[email protected]>
--- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/msm/adreno/a6xx_gmu.c +4 -1
@@ -514,7 +514,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)int ret;u32 val; -if (test_and_clear_bit (GMU_STATUS_FW_START , &gmu->status)) +if (!test_and_clear_bit (GMU_STATUS_FW_START , &gmu->status))return ;gmu_write (gmu,REG_A6XX_GMU_RSCC_CONTROL_REQ ,1 );
@@ -1186,6 +1186,9 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)/* Stop the interrupts and mask the hardware */ a6xx_gmu_irq_disable (gmu); +/* Halt the gmu cm3 core */ +gmu_write (gmu,REG_A6XX_GMU_CM3_SYSRESET ,1 ); +/* Tell RPMh to power off the GPU */ a6xx_rpmh_stop (gmu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 572/1376 bpf: Sync tail_call_reachable with callee state on entry
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 3513ea9dab6c1a3d2dc8e6160c41f690206948b6 ]
Currently in check_max_stack_depth_subprog, when the verifier enters a new callee branch, the local tail_call_reachable is not properly synchronized with the callee's state.
Consider a main prog branching into multiple subprogs:
subprog0 -> tailcall
main <
subprog1 -> subprog2When the verifier finishes checking subprog0 and backtracks to main prog, the local tail_call_reachable state is left as true. As it proceeds to subprog1, this uncleared state leaks into the new branch, falsely marking subprog1 and subprog2 as tailcall reachable.
Fix this by explicitly syncing tail_call_reachable with the callee's has_tail_call state on entry. The caller's state is safely preserved and restored via the existing backtracking logic.
--- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/bpf/verifier.c +2 -2
@@ -6294,8 +6294,8 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,if (!priv_stack_supported) subprog[idx].priv_stack_mode =NO_PRIV_STACK ; -if (subprog[idx].has_tail_call) - tail_call_reachable = true; +/* sync tail_call_reachable with callee state on entry */ + tail_call_reachable = subprog[idx].has_tail_call; frame++;if (frame >=MAX_CALL_FRAMES ) {
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0572/1376] bpf: Sync tail_call_reachable with callee state on entry
Please hold this patch unless a 6.12 backport of upstream commit 54c27ea6dadb ("bpf: Fix tail_call_reachable leak") can also be included.
This patch resets tail_call_reachable on callee entry, but 6.12 lacks the parent-state restoration it relies on. Returning from a clean callee can leave the root state incorrect and make the x86 JIT omit required tail-call counter handling.
I reproduced this on 6.12.110-rc1 in QEMU: the unmodified kernel hit a NULL dereference in generated JIT code at ffffffffa0000114 with CR2=0.
With the applicable 54c27ea6dadb hunk applied, the same bounded test completed normally and stopped at 34 program entries: the initial invocation plus the 33 permitted tail calls.
Thanks,
Karl
Re: [PATCH 6.12 0572/1376] bpf: Sync tail_call_reachable with callee state on entry
In reply to Greg Kroah-HartmanQuoted 42 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit
3513ea9dab6c1a3d2dc8e6160c41f690206948b6]Currently in
check_max_stack_depth_subprog, when the verifier enters a new callee branch, the localtail_call_reachableis not properly synchronized with the callee's state.Consider a main prog branching into multiple subprogs:
subprog0 -> tailcall main < subprog1 -> subprog2When the verifier finishes checking subprog0 and backtracks to main prog, the local
tail_call_reachablestate is left as true. As it proceeds to subprog1, this uncleared state leaks into the new branch, falsely marking subprog1 and subprog2 as tailcall reachable.Fix this by explicitly syncing
tail_call_reachablewith the callee'shas_tail_callstate on entry. The caller's state is safely preserved and restored via the existing backtracking logic.Fixes ebf7d1f508a7 ("bpf, x64: rework pro/epilogue and tailcall handling in JIT")Reported-by Sashiko <[email protected]>Signed-off-by Pu Lehui <[email protected]>Signed-off-by Eduard Zingerman <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)kernel/bpf/verifier.c +0
-0
kernel/bpf/verifier.c static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx, · line 6298
Quoted 7 lines
kernel/bpf/verifier.c +2
-2@@ -6294,8 +6294,8 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,if (!priv_stack_supported) subprog[idx].priv_stack_mode =NO_PRIV_STACK ; -if (subprog[idx].has_tail_call) - tail_call_reachable = true; +/* sync tail_call_reachable with callee state on entry */ + tail_call_reachable = subprog[idx].has_tail_call;
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch correctly replaces the traversal state with the entered
callee's has_tail_call value. Upstream also has 54c27ea6dadb, which restores tail_call_reachable when the traversal pops to the caller. That restoration is absent from 6.12.
Upstream unwind code after 54c27ea6dadb:
tail_call_reachable = subprog[idx].tail_call_reachable;
Downstream 6.12.y unwind code:
frame--;
i = ret_insn[frame];
idx = ret_prog[frame];
goto continue_func;The downstream unwind never restores the caller's recorded state.
A caller containing a tail call can enter a child without one, return with the local state still false, and fail to mark its own callers. The JIT then receives incorrect tail-call reachability metadata.
Maybe we should be adding the 6.12-equivalent restoration immediately after the ret_prog[] unwind before retaining this backport. Thoughts?
thanks,
Harshit>
Quoted 2 lines
kernel/bpf/verifier.c +0
-0frame++;if (frame >=MAX_CALL_FRAMES ) {
Greg Kroah-Hartman
maintainerPATCH 573/1376 crypto: sl3516 - drop invalid sg_dma_len checks before DMA mapping
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 3ae59a2eba64b3648f069aa52eeaaeefdfe4bb2f ]
sg_dma_len() is only valid after mapping the scatterlist with dma_map_sg(). However, sl3516_ce_need_fallback() checks it before the source and destination scatterlists are mapped. Thus, a stale DMA length that is not a multiple of 16 could incorrectly force a software fallback when CONFIG_NEED_SG_DMA_LENGTH=y.
Remove the invalid checks; the existing scatterlist length checks are sufficient.
--- drivers/crypto/gemini/sl3516-ce-cipher.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/crypto/gemini/sl3516-ce-cipher.c +0 -8
@@ -56,10 +56,6 @@ static bool sl3516_ce_need_fallback(struct skcipher_request *areq) ce->fallback_mod16++;return true; } -if ((sg_dma_len (sg) %16 ) !=0 ) { - ce->fallback_mod16++; -return true; - }if (!IS_ALIGNED (sg->offset,16 )) { ce->fallback_align16++;return true;
@@ -72,10 +68,6 @@ static bool sl3516_ce_need_fallback(struct skcipher_request *areq) ce->fallback_mod16++;return true; } -if ((sg_dma_len (sg) %16 ) !=0 ) { - ce->fallback_mod16++; -return true; - }if (!IS_ALIGNED (sg->offset,16 )) { ce->fallback_align16++;return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 574/1376 ACPI: processor: idle: Expand _LPI package sanity checks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit d5c13047a132162d2649be876906ead691d12948 ]
The _LPI package sanity checks in acpi_processor_evaluate_lpi() miss a couple of things, so expand them by adding a buffer size check before retrieving a struct acpi_power_register from it (and skip the given state if the buffer is not large enough to hold a register structure) and making the function avoid copying the state description from the ACPI table if there are too few elements in the package supposed to hold it.
While at it, relocate and rephrase a comment about skipping _LPI state package elements [7-8].
--- drivers/acpi/processor_idle.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
drivers/acpi/processor_idle.c +21 -7
@@ -950,6 +950,13 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle,if (obj->type ==ACPI_TYPE_BUFFER ) {struct acpi_power_register *reg; +if (obj->buffer.length <sizeof (*reg)) { +acpi_handle_debug (handle, +"Invalid register data for _LPI state %d\n" , + state_idx); +continue ; + } + reg = (struct acpi_power_register *)obj->buffer.pointer;if (reg->space_id !=ACPI_ADR_SPACE_SYSTEM_IO && reg->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE )
@@ -966,13 +973,6 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle,continue ; } -/* elements[7,8] skipped for now i.e. Residency/Usage counter*/ - - obj = pkg_elem +9 ; -if (obj->type ==ACPI_TYPE_STRING ) -strscpy (lpi_state->desc, obj->string.pointer, -ACPI_CX_DESC_LEN ); - lpi_state->index = state_idx;if (obj_get_integer (pkg_elem +0 , &lpi_state->min_residency)) {pr_debug ("No min. residency found, assuming 10 us\n" );
@@ -995,6 +995,20 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle,if (obj_get_integer (pkg_elem +5 , &lpi_state->enable_parent_state)) lpi_state->enable_parent_state =0 ; + +/* Skip elements [7-8] i.e. Residency/Usage counters. */ + +/* +* Avoid out-of-bounds access if the size of the package is less +* than expected. +*/ +if (element->package.count <10 ) +continue ; + + obj = pkg_elem +9 ; +if (obj->type ==ACPI_TYPE_STRING ) +strscpy (lpi_state->desc, obj->string.pointer, +ACPI_CX_DESC_LEN ); }acpi_handle_debug (handle,"Found %d power states\n" , state_idx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 575/1376 usb: gadget: f_uac1_legacy: remove broken string configfs attributes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
[ Upstream commit 590d74ec8f488e06b9f1c0f8f0941f45531f3a55 ]
The UAC1_STR_ATTRIBUTE macro defines configfs show/store handlers for the fn_play, fn_cap, and fn_cntl string options. The store function contains an inverted null check on the kstrndup() return value.
This means every write attempt returns -ENOMEM on success and dereferences a NULL pointer on allocation failure. The attributes have been broken and unused for many years.
Remove the UAC1_STR_ATTRIBUTE macro and the three attributes it generated. The internal defaults (FILE_PCM_PLAYBACK, FILE_PCM_CAPTURE, FILE_CONTROL) set in f_audio_alloc_inst() are unaffected.
--- .../testing/configfs-usb-gadget-uac1_legacy | 3 - Documentation/usb/gadget-testing.rst | 3 - drivers/usb/gadget/function/f_uac1_legacy.c | 56 ------------------- drivers/usb/gadget/function/u_uac1_legacy.h | 3 - 4 files changed, 65 deletions(-)
Documentation/ABI/testing/configfs-usb-gadget-uac1_legacy +0 -3
@@ -5,8 +5,5 @@ Description: The attributes: audio_buf_size - audio buffer size - fn_cap - capture pcm device file name - fn_cntl - control device file name - fn_play - playback pcm device file name req_buf_size - ISO OUT endpoint request buffer size req_count - ISO OUT endpoint request count
Documentation/usb/gadget-testing.rst +0 -3
@@ -712,9 +712,6 @@ The uac1 function provides these attributes in its function directory: =============== ==================================== audio_buf_size audio buffer size - fn_cap capture pcm device file name - fn_cntl control device file name - fn_play playback pcm device file name req_buf_size ISO OUT endpoint request buffer size req_count ISO OUT endpoint request count =============== ====================================
drivers/usb/gadget/function/f_uac1_legacy.c +0 -56
72 lines not on this page · raw message
drivers/usb/gadget/function/u_uac1_legacy.h +0 -3
@@ -62,9 +62,6 @@ struct f_uac1_legacy_opts {char *fn_cap;char *fn_cntl; unsigned bound:1; - unsigned fn_play_alloc:1; - unsigned fn_cap_alloc:1; - unsigned fn_cntl_alloc:1;struct mutex lock;int refcnt; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 576/1376 tty: hvc: restrict HVC_DCC to ARMv6+ and ARM64
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 782f4dbd1794b4f30dc116a7ca42c5962c409be8 ]
hvc_dcc drives the JTAG DCC via the ARMv6/v7 CP14 debug registers (mrc/mcr p14, 0, rX, c0, c1/c5, 0 in asm/dcc.h). That encoding is undefined on older ARM cores, and also on ARMv7-M, but HVC_DCC only depends on ARM, so it can be enabled on e.g. ARM926 (ARCH_MULTI_V5), where hvc_dcc_console_init() runs __dcc_putchar() at boot and takes an undefined-instruction trap before the console is up:
Internal error: Oops - undefined instruction: 0 [#1] ARM PC is at hvc_dcc_check+0x50/0x8c hvc_dcc_check from hvc_dcc_console_init+0x18/0x48 hvc_dcc_console_init from console_init+0x58/0x170 Kernel panic - not syncing: Fatal exception
Restrict HVC_DCC to the CPUs where that encoding is valid: the CPU_V6 || CPU_V6K || CPU_V7 set that arch/arm/include/debug/icedcc.S guards it with, plus ARM64.
--- drivers/tty/hvc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/hvc/Kconfig +1 -1
@@ -79,7 +79,7 @@ config HVC_UDBG config HVC_DCC bool "ARM JTAG DCC console" - depends on ARM || ARM64 + depends on (ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || ARM64 select HVC_DRIVER select SERIAL_CORE_CONSOLE help
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 577/1376 UDF symlink pathComponent header OOB read
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
[ Upstream commit d23eb7380d1594cda31a5dc8487dd2a5c8def8c7 ]
udf_symlink_filler() can enter udf_pc_to_char() with a partial pathComponent header.
Validate that enough input remains for a complete pathComponent header before accessing it. Reject malformed symlink data that would otherwise make udf_pc_to_char() perform an out-of-bounds read.
--- fs/udf/symlink.c | 2 ++ 1 file changed, 2 insertions(+)
fs/udf/symlink.c +2 -0
@@ -36,6 +36,8 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,/* Reserve one byte for terminating \0 */ tolen--;while (elen < fromlen) { +if (fromlen - elen <sizeof (struct pathComponent )) +return -EIO ; pc = (struct pathComponent *)(from + elen); elen +=sizeof (struct pathComponent );switch (pc->componentType) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 578/1376 uio: Fix stale info pointer in failed registration path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 67b6fc084b034a91c3ec7907a3fed89a2450f30b ]
After device_add(), the UIO device is visible to userspace and /dev/uioX can be opened. If a later setup step fails, __uio_register_device() unwinds the device but leaves idev->info pointing at the caller-owned struct uio_info.
That is unsafe when an opener races with the failed registration path. The open file keeps a reference to the uio_device, while the caller sees registration failure and may free its struct uio_info. Later file operations can then follow idev->info and dereference freed memory.
Handle post-device_add() failures like unregister: remove UIO attributes while the info pointer is still valid, then clear idev->info under info_lock and wake existing waiters/async users before removing the device and minor. This makes already-open file descriptors observe the same "device gone" state as normal uio_unregister_device().
--- drivers/uio/uio.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/uio/uio.c +5 -0
@@ -1051,6 +1051,11 @@ int __uio_register_device(struct module *owner, err_request_irq:uio_dev_del_attributes (idev); err_uio_dev_add_attributes: +mutex_lock (&idev->info_lock); + idev->info =NULL ; +mutex_unlock (&idev->info_lock); +wake_up_interruptible (&idev->wait); +kill_fasync (&idev->async_queue,SIGIO ,POLL_HUP );device_del (&idev->dev); err_device_create:uio_free_minor (idev->minor);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 579/1376 accessibility: speakup: Fix incorrect string length computation in report_char_chartab_status()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe JAILLET <[email protected]>
[ Upstream commit bce0e640623372520d9d90c42f33ddbfb576ce69 ]
snprintf() returns the "number of characters which *would* be generated for the given input", not the size *really* generated.
In order to avoid too large values for 'len' (and potential negative values for "sizeof(buf) - (len - 1)") use scnprintf() instead of snprintf().
--- drivers/accessibility/speakup/kobjects.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/accessibility/speakup/kobjects.c +3 -3
@@ -92,9 +92,9 @@ static void report_char_chartab_status(int reset, int received, int used,if (reset) {pr_info ("%s reset to defaults\n" , object_type[do_characters]); }else if (received) { - len =snprintf (buf,sizeof (buf), -" updated %d of %d %s\n" , - used, received, object_type[do_characters]); + len =scnprintf (buf,sizeof (buf), +" updated %d of %d %s\n" , + used, received, object_type[do_characters]);if (rejected) snprintf(buf + (len - 1), sizeof(buf) - (len - 1), " with %d reject%s\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 580/1376 speakup: keyhelp: guard letter_offsets possible out-of-range indexing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Zhigulin <[email protected]>
[ Upstream commit 6a19ad4d68c95185308cd9e5d169b10a2cf236c8 ]
help_init() builds letter_offsets[] by using the first byte of each function name as an index via (start & 31) - 1. If function_names are overridden from sysfs (root) with a name starting outside [a–z], the index underflows or exceeds the array, leading to OOB write.
Function names can be overridden with the following commands as root:
modprobe speakup_soft
echo "0 _bad" > /sys/accessibility/speakup/i18n/function_names # then press Insert+2 on /dev/tty
This fix checks the first letter in help_init(), and if it is not in the [a–z] range the function returns an error to the caller. Eventually this error is propagated to drivers/accessibility/speakup/main.c:2217, which causes a bleep sound.
--- drivers/accessibility/speakup/keyhelp.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/accessibility/speakup/keyhelp.c +12 -5
@@ -8,6 +8,7 @@*/ #include <linux/keyboard.h> +#include <linux/ctype.h> #include "spk_priv.h" #include "speakup.h"
@@ -111,7 +112,7 @@ static void say_key(int key) spk_msg_get(MSG_KEYNAMES_START + (key - 1))); } -static int help_init (void ) +static void help_init (void ) {char start =SPACE ;int i;
@@ -120,13 +121,19 @@ static int help_init(void) state_tbl = spk_our_keys[0 ] +SHIFT_TBL_SIZE +2 ;for (i =0 ; i < num_funcs; i++) {char *cur_funcname =spk_msg_get (MSG_FUNCNAMES_START + i); +char first_letter; -if (start == *cur_funcname) + first_letter =tolower (*cur_funcname); + +/* Accept only 'a'..'z' to index letter_offsets[] safely */ +if (first_letter <'a' || first_letter >'z' ) +continue ; + +if (start == first_letter)continue ; - start = *cur_funcname; + start = first_letter; letter_offsets[(start &31 ) -1 ] = i; } -return 0 ; }int spk_handle_help (struct vc_data *vc,u_char type,u_char ch,u_short key)
@@ -144,7 +151,7 @@ int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)synth_printf ("%s\n" ,spk_msg_get (MSG_LEAVING_HELP ));return 1 ; } - ch |=32 ;/* lower case */ + ch =tolower (ch);if (ch <'a' || ch >'z' )return -1 ;if (letter_offsets[ch -'a' ] ==-1 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 581/1376 misc: bcm-vk: Use acquire/release for msgq_inited
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit 61b101c6a150057b6d512421ed108aed16e822ea ]
bcm_vk_sync_msgq() fills the message queue information and then sets msgq_inited. Readers call bcm_vk_drv_access_ok() before accessing the message queues and their cached queue information.
atomic_set()/atomic_read() do not order those accesses. A reader can see msgq_inited set while still seeing stale queue information. Use release when publishing the initialized queues and acquire when checking the gate.
Keep the clear in bcm_vk_blk_drv_access() as atomic_set(). It closes the gate and does not publish queue state to readers.
--- drivers/misc/bcm-vk/bcm_vk_msg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/misc/bcm-vk/bcm_vk_msg.c +4 -2
@@ -108,7 +108,8 @@ u32 msgq_avail_space(const struct bcm_vk_msgq __iomem *msgq,bool bcm_vk_drv_access_ok (struct bcm_vk *vk) { -return (!!atomic_read (&vk->msgq_inited)); +/* Pair with the release store after message queue initialization. */ +return !!atomic_read_acquire (&vk->msgq_inited); }void bcm_vk_set_host_alert (struct bcm_vk *vk,u32 bit_mask)
@@ -501,7 +502,8 @@ int bcm_vk_sync_msgq(struct bcm_vk *vk, bool force_sync) msgq++; } } -atomic_set (&vk->msgq_inited,1 ); +/* Publish message queue info before allowing driver access. */ +atomic_set_release (&vk->msgq_inited,1 );return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 582/1376 misc: rtsx: add missing write register handling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gleb Markov <[email protected]>
[ Upstream commit 655faba1ccf195e22a7a83146ef6015e3271233c ]
If an error occurs at the stage of working with registers in conjunction with MCU_Block, it will not be processed.
The occurrence of errors at this stage may signal an impact on writes to the device's PCI registers and is a more global problem than a driver-level security problem, but adding a handler would be a good practice.
Add a missing error handling.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/misc/cardreader/rtsx_pcr.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/misc/cardreader/rtsx_pcr.c +2 -0
@@ -1242,6 +1242,8 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)/* Gating real mcu clock */ err =rtsx_pci_write_register (pcr,RTS5261_FW_CFG1 ,RTS5261_MCU_CLOCK_GATING ,0 ); +if (err <0 ) +return err; err =rtsx_pci_write_register (pcr,RTS5261_REG_FPDCTL ,SSC_POWER_DOWN ,0 ); }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 583/1376 misc: ad525x_dpot: use driver core groups for sysfs files
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit e3a8557e88eb26278eda60bf64f2ef33ce7de8bf ]
ad_dpot_probe() creates per-RDAC sysfs files manually and then optionally creates the command sysfs group. This leaves probe responsible for rolling back partial sysfs state and makes remove responsible for matching every file that probe created.
Move the device attributes into driver core dev_groups for the I2C and SPI drivers and use an is_visible() callback to expose only the attributes supported by the probed device. With this shape, the driver core creates the sysfs files only after probe succeeds and removes them before the remove callback frees the driver data.
--- drivers/misc/ad525x_dpot-i2c.c | 1 + drivers/misc/ad525x_dpot-spi.c | 1 + drivers/misc/ad525x_dpot.c | 177 ++++++++++++++++++++------------- drivers/misc/ad525x_dpot.h | 3 + 4 files changed, 112 insertions(+), 70 deletions(-)
drivers/misc/ad525x_dpot-i2c.c +1 -0
@@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(i2c, ad_dpot_id);static struct i2c_driver ad_dpot_i2c_driver = { .driver = { .name ="ad_dpot" , + .dev_groups = ad_dpot_groups, }, .probe = ad_dpot_i2c_probe, .remove = ad_dpot_i2c_remove,
drivers/misc/ad525x_dpot-spi.c +1 -0
@@ -131,6 +131,7 @@ MODULE_DEVICE_TABLE(spi, ad_dpot_spi_id);static struct spi_driver ad_dpot_spi_driver = { .driver = { .name ="ad_dpot" , + .dev_groups = ad_dpot_groups, }, .probe = ad_dpot_spi_probe, .remove = ad_dpot_spi_remove,
drivers/misc/ad525x_dpot.c +107 -70
224 lines not on this page · raw message
drivers/misc/ad525x_dpot.h +3 -0
@@ -10,6 +10,8 @@#include <linux/types.h> +struct attribute_group ; +#define DPOT_CONF (features, wipers, max_pos, uid) \ (((features) << 18) | (((wipers) & 0xFF) << 10) | \ ((max_pos & 0xF) << 6) | (uid & 0x3F))
@@ -210,5 +212,6 @@ struct ad_dpot_bus_data {int ad_dpot_probe (struct device *dev,struct ad_dpot_bus_data *bdata,unsigned long devid,const char *name);void ad_dpot_remove (struct device *dev); +extern const struct attribute_group *ad_dpot_groups[];#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 584/1376 cacheinfo: dont propagate DT/ACPI error when arch supplies info (arm64)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 274259391c14166fcabae74f9fc0104223ff27a1 ]
cache_setup_properties() sets use_arch_info = true when DT/ACPI provide no cache nodes and the arch can derive the topology from CPU registers (e.g. arm64 reading CLIDR_EL1), but still returns the original -ENOENT. cache_shared_cpu_map_setup() bails on that error before the new flag can take effect, so the first CPU brought online always trips a misleading warning:
cacheinfo: Unable to detect cache hierarchy for CPU 0
Subsequent CPUs skip cache_setup_properties() entirely because use_arch_info is now true, which is why only CPU0 hits it. This is reproducible on arm64 with the QEMU 'virt' machine, whose default DT has no cache nodes.
Clear ret after setting use_arch_info so the caller proceeds and populates the shared cpu map via the arch-supplied leaves.
--- drivers/base/cacheinfo.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/base/cacheinfo.c +7 -2
@@ -332,9 +332,14 @@ static int cache_setup_properties(unsigned int cpu)else if (!acpi_disabled) ret =cache_setup_acpi (cpu); -// Assume there is no cache information available in DT/ACPI from now. -if (ret &&use_arch_cache_info ()) +/* +* No DT/ACPI cache nodes; fall back to arch-derived topology (e.g. +* arm64 CLIDR_EL1) and clear the error to avoid a spurious warning. +*/ +if (ret &&use_arch_cache_info ()) { use_arch_info = true; + ret =0 ; + }return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 585/1376 ppdev: prevent overflow when setting port timeout
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 3c0cf801ea2fa40daa5e7d1e6d32adca5ff75ad9 ]
PPSETTIME64 supplies the timeval fields as s64 values, but pp_set_timeout() narrows tv_usec to int and calculates tv_sec * HZ in a signed long. Large positive values can therefore be truncated or overflow and install an unintended timeout.
Keep both fields as s64, reject a non-canonical microsecond value, and use timespec64_to_jiffies() to cap excessively large timeouts at MAX_JIFFY_OFFSET. This is a behavior change because both PPSETTIME ioctls could previously accept values with tv_usec >= USEC_PER_SEC. The validation follows the precedent set by sock_set_timeout().
--- drivers/char/ppdev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/char/ppdev.c +6 -4
@@ -340,15 +340,17 @@ static enum ieee1284_phase init_phase(int mode)return IEEE1284_PH_FWD_IDLE ; } -static int pp_set_timeout (struct pardevice *pdev,long tv_sec,int tv_usec) +static int pp_set_timeout (struct pardevice *pdev,s64 tv_sec,s64 tv_usec) { +struct timespec64 ts;long to_jiffies; -if ((tv_sec <0 ) || (tv_usec <0 )) +if (tv_sec <0 || tv_usec <0 || tv_usec >=USEC_PER_SEC )return -EINVAL ; - to_jiffies =usecs_to_jiffies (tv_usec); - to_jiffies += tv_sec *HZ ; + ts.tv_sec = tv_sec; + ts.tv_nsec = tv_usec *NSEC_PER_USEC ; + to_jiffies =timespec64_to_jiffies (&ts);if (to_jiffies <=0 )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 586/1376 ipack: ipoctal: fix UAF, null-ptr-deref, and use-after-free in cleanup on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pei Xiao <[email protected]>
[ Upstream commit b6b5d64cb161a28347d64dc3168a636c4abb68d5 ]
Three issues arise when the device is removed while a tty session is still active:
1. UAF of struct ipoctal: the remove callback frees ipoctal via kfree() while tty ops may still access it. Fix by introducing kref-based lifetime management — kref is taken in install() when a tty is opened and released in cleanup() when the tty is finally destroyed; remove() uses kref_put() instead of kfree().
2. NULL dereference in ipoctal_write_tty(): __ipoctal_remove() frees xmit_buf via tty_port_free_xmit_buf() while a userspace process may still hold the tty fd and call write(). Fix by checking for NULL xmit_buf in ipoctal_write_tty().
3. UAF in ipoctal_cleanup(): ipack_put_carrier(ipoctal->dev) dereferences ipoctal->dev after the ipack_device has been freed by ipack_device_del(). Fix by caching ipoctal->carrier_owner during probe() and calling module_put() on the cached pointer directly in cleanup(), avoiding any access to ipoctal->dev.
Also introduce a "removed" flag in struct ipoctal, set at the start of __ipoctal_remove(), and checked in every tty op that accesses hardware resources (port_activate, write_tty, set_termios, hangup, shutdown). This prevents page faults when devm_ioremap() regions are unmapped after remove() returns.
--- drivers/ipack/devices/ipoctal.c | 56 ++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-)
drivers/ipack/devices/ipoctal.c +52 -4
@@ -10,6 +10,7 @@#include <linux/device.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/kref.h> #include <linux/sched.h> #include <linux/tty.h> #include <linux/serial.h>
@@ -25,6 +26,8 @@static const struct tty_operations ipoctal_fops; +static void ipoctal_release (struct kref *kref); +struct ipoctal_channel {struct ipoctal_stats stats;unsigned int nb_bytes;
@@ -49,6 +52,9 @@ struct ipoctal {struct tty_driver *tty_drv;u8 __iomem *mem8_space;u8 __iomem *int_space; +struct kref kref; +struct module *carrier_owner; +bool removed; }; static inline struct ipoctal *chan_to_ipoctal(struct ipoctal_channel *chan,
@@ -70,8 +76,14 @@ static void ipoctal_reset_channel(struct ipoctal_channel *channel)static int ipoctal_port_activate (struct tty_port *port,struct tty_struct *tty) {struct ipoctal_channel *channel; +struct ipoctal *ipoctal; channel =dev_get_drvdata (tty->dev); + ipoctal =chan_to_ipoctal (channel, tty->index); + + +if (ipoctal->removed) +return -ENODEV ;/* * Enable RX. TX will be enabled when
@@ -95,6 +107,7 @@ static int ipoctal_install(struct tty_driver *driver, struct tty_struct *tty)if (res) goto err_put_carrier; +kref_get (&ipoctal->kref); tty->driver_data = channel;return 0 ;
@@ -460,8 +473,13 @@ static ssize_t ipoctal_write_tty(struct tty_struct *tty, const u8 *buf, size_t count) {struct ipoctal_channel *channel = tty->driver_data; +struct ipoctal *ipoctal =chan_to_ipoctal (channel, tty->index);size_t char_copied; + +if (ipoctal->removed || !channel->tty_port.xmit_buf) +return 0 ; + char_copied =ipoctal_copy_write_buffer (channel, buf, count);/* As the IP-OCTAL 485 only supports half duplex, do it manually */
@@ -501,8 +519,13 @@ static void ipoctal_set_termios(struct tty_struct *tty,unsigned char mr2 =0 ;unsigned char csr =0 ;struct ipoctal_channel *channel = tty->driver_data; +struct ipoctal *ipoctal =chan_to_ipoctal (channel, tty->index);speed_t baud; + +if (ipoctal->removed) +return ; + cflag = tty->termios.c_cflag;/* Disable and reset everything before change the setup */
@@ -631,10 +654,16 @@ static void ipoctal_hangup(struct tty_struct *tty) {unsigned long flags;struct ipoctal_channel *channel = tty->driver_data; +struct ipoctal *ipoctal;if (channel ==NULL )return ; + ipoctal =chan_to_ipoctal (channel, tty->index); + +if (ipoctal->removed) +return ; +spin_lock_irqsave (&channel->lock, flags); channel->nb_bytes =0 ; channel->pointer_read =0 ;
@@ -651,10 +680,16 @@ static void ipoctal_hangup(struct tty_struct *tty)static void ipoctal_shutdown (struct tty_struct *tty) {struct ipoctal_channel *channel = tty->driver_data; +struct ipoctal *ipoctal;if (channel ==NULL )return ; + ipoctal =chan_to_ipoctal (channel, tty->index); + +if (ipoctal->removed) +return ; +ipoctal_reset_channel (channel);tty_port_set_initialized (&channel->tty_port, false); }
@@ -664,8 +699,9 @@ static void ipoctal_cleanup(struct tty_struct *tty)struct ipoctal_channel *channel = tty->driver_data;struct ipoctal *ipoctal =chan_to_ipoctal (channel, tty->index); -/* release the carrier driver */ -ipack_put_carrier (ipoctal->dev); +/* release the carrier driver via cached owner */ +module_put (ipoctal->carrier_owner); +kref_put (&ipoctal->kref, ipoctal_release); }static const struct tty_operations ipoctal_fops = {
@@ -683,6 +719,13 @@ static const struct tty_operations ipoctal_fops = { .cleanup = ipoctal_cleanup, }; +static void ipoctal_release (struct kref *kref) +{ + struct ipoctal *ipoctal = container_of(kref, struct ipoctal, kref); + +kfree (ipoctal); +} +static int ipoctal_probe (struct ipack_device *dev) {int res;
@@ -692,7 +735,10 @@ static int ipoctal_probe(struct ipack_device *dev)if (ipoctal ==NULL )return -ENOMEM ; +kref_init (&ipoctal->kref); + ipoctal->dev = dev; + ipoctal->carrier_owner = dev->bus->owner; res =ipoctal_inst_slot (ipoctal, dev->bus->bus_nr, dev->slot);if (res) goto out_uninst;
@@ -701,7 +747,7 @@ static int ipoctal_probe(struct ipack_device *dev)return 0 ; out_uninst: -kfree (ipoctal); +kref_put (&ipoctal->kref, ipoctal_release);return res; }
@@ -709,6 +755,8 @@ static void __ipoctal_remove(struct ipoctal *ipoctal) {int i; + ipoctal->removed = true; + ipoctal->dev->bus->ops->free_irq (ipoctal->dev);for (i =0 ; i <NR_CHANNELS ; i++) {
@@ -725,7 +773,7 @@ static void __ipoctal_remove(struct ipoctal *ipoctal)tty_unregister_driver (ipoctal->tty_drv);kfree (ipoctal->tty_drv->name);tty_driver_kref_put (ipoctal->tty_drv); -kfree (ipoctal); +kref_put (&ipoctal->kref, ipoctal_release); }static void ipoctal_remove (struct ipack_device *idev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 587/1376 char: xilinx_hwicap: unregister class on init errors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e7e12b4cc0f0c3a2782aea084d4215e23f5512b3 ]
hwicap_module_init() registers icap_class before reserving the character-device region and registering the platform driver. If either of those later steps fails, the init path must undo the successful class registration before returning an error.
Route the chrdev registration failure through a class unwind label, and let the platform-driver registration failure fall through the existing chrdev unwind before unregistering the class. The normal module exit path is unchanged.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/char/xilinx_hwicap/xilinx_hwicap.c +4 -1
@@ -760,7 +760,7 @@ static int __init hwicap_module_init(void)HWICAP_DEVICES , DRIVER_NAME);if (retval <0 ) -return retval; + goto failed_class; retval =platform_driver_register (&hwicap_platform_driver);if (retval)
@@ -771,6 +771,9 @@ static int __init hwicap_module_init(void) failed:unregister_chrdev_region (devt,HWICAP_DEVICES ); + failed_class: +class_unregister (&icap_class); +return retval; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 588/1376 vfio/pci: clear vdev->msi_perm after freeing it on init failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit dc77acfeb979dded39b247b60fef0399536bfa77 ]
vfio_msi_cap_len() lazily allocates the per-device MSI permission table:
vdev->msi_perm = kmalloc_obj(struct perm_bits, GFP_KERNEL_ACCOUNT);
if (!vdev->msi_perm)
return -ENOMEM;
ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags);
if (ret) {
kfree(vdev->msi_perm);
return ret; /* vdev->msi_perm left dangling */
}When init_pci_cap_msi_perm() -> alloc_perm_bits() fails with -ENOMEM, the error path frees vdev->msi_perm but leaves the freed pointer stored in it. vdev->msi_perm is not re-zeroed later because struct vfio_pci_core_device is per-device and persists across open/close cycles, and the vfio_config_init() error path returns without calling vfio_config_free(). So the dangling pointer outlives the failed open.
That leads to two use-after-frees on the same device:
1. Reuse. The next vfio_config_init() sees the stale pointer at "if (vdev->msi_perm) return len;" and reuses the freed object. MSI config accesses in vfio_pci_config_rw_single() then dereference and call the freed perm->readfn / perm->writefn function pointers.
2. Double free. A later vfio_config_free() runs free_perm_bits() and kfree() on the already-freed object.
Fix it by NULLing vdev->msi_perm after the kfree(), matching the NULL-after-free discipline already used in free_perm_bits() and vfio_config_free().
BUG: KASAN: slab-use-after-free in vfio_pci_config_rw_single (drivers/vfio/pci/vfio_pci_config.c:1961) Read of size 8 at addr ffff88800fcc88d0 by task exploit/143 Call Trace: ... kasan_report (mm/kasan/report.c:595) vfio_pci_config_rw_single (drivers/vfio/pci/vfio_pci_config.c:1961) vfio_pci_config_rw (drivers/vfio/pci/vfio_pci_config.c:1986) vfio_pci_rw (drivers/vfio/pci/vfio_pci_core.c:1599) vfs_read (fs/read_write.c:572) __x64_sys_pread64 (fs/read_write.c:764) do_syscall_64 (arch/x86/entry/syscall_64.c:94) ...
Followed on device close by a double free of the same object:
Oops: general protection fault, probably for non-canonical address
0x1f63e0e8000008: 0000 [#1] SMP KASAN NOPTI
RIP: 0010:kfree (mm/slub.c:6711)
Call Trace:
vfio_config_free (drivers/vfio/pci/vfio_pci_config.c:1861)
vfio_pci_core_disable (drivers/vfio/pci/vfio_pci_core.c:685)
vfio_pci_core_close_device (drivers/vfio/pci/vfio_pci_core.c:777)
vfio_df_close (drivers/vfio/vfio_main.c:602)
vfio_device_fops_release (drivers/vfio/vfio_main.c:648)
__fput (fs/file_table.c:512)
__x64_sys_close (fs/open.c:1496)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
...
Kernel panic - not syncing: Fatal exception--- drivers/vfio/pci/vfio_pci_config.c | 1 + 1 file changed, 1 insertion(+)
drivers/vfio/pci/vfio_pci_config.c +1 -0
@@ -1257,6 +1257,7 @@ static int vfio_msi_cap_len(struct vfio_pci_core_device *vdev, u8 pos) ret =init_pci_cap_msi_perm (vdev->msi_perm, len, flags);if (ret) {kfree (vdev->msi_perm); + vdev->msi_perm =NULL ;return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 589/1376 soc: ti: knav_qmss_queue: Implement resource cleanup in remove()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Md Shofiqul Islam <[email protected]>
[ Upstream commit 10a1969353b20caa50c320717e054601631c0d3e ]
Implement the TODO in knav_queue_remove() by stopping PDSPs and freeing queue regions and queue ranges before disabling runtime PM, mirroring the cleanup performed in the probe error path.
Set device_ready to false before cleanup to prevent any further use of the device during teardown.
This ensures resources are released on driver unbind and avoids leaking queue/region state.
Stable-dep-of: 3c8178627599 ("soc: ti: knav_qmss: Remove debugfs file on teardown")
--- drivers/soc/ti/knav_qmss_queue.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/soc/ti/knav_qmss_queue.c +6 -1
@@ -1887,7 +1887,12 @@ static int knav_queue_probe(struct platform_device *pdev)static void knav_queue_remove (struct platform_device *pdev) { -/* TODO: Free resources */ +struct knav_device *kdev =platform_get_drvdata (pdev); + + device_ready = false; +knav_queue_stop_pdsps (kdev); +knav_queue_free_regions (kdev); +knav_free_queue_ranges (kdev);pm_runtime_put_sync (&pdev->dev);pm_runtime_disable (&pdev->dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 590/1376 soc: ti: knav_qmss: Remove debugfs file on teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 3c817862759913097f11467ed4ed2bbf974dabaf ]
knav_queue_probe() creates the global qmss debugfs file whose show callback reads the global knav_qdev state. knav_queue_remove() tears down the queue manager resources but leaves the debugfs file published.
Save the debugfs dentry in struct knav_device and remove it during teardown before the resources used by the show callback are released. While touching the debugfs_create_file() call, spell the unchanged read- only file mode as 0444.
--- drivers/soc/ti/knav_qmss.h | 1 + drivers/soc/ti/knav_qmss_queue.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-)
drivers/soc/ti/knav_qmss.h +1 -0
@@ -304,6 +304,7 @@ struct knav_device {struct list_head pools;struct list_head pdsps;struct list_head qmgrs; +struct dentry *debugfs_file;enum qmss_version version; };
drivers/soc/ti/knav_qmss_queue.c +5 -2
@@ -1871,8 +1871,9 @@ static int knav_queue_probe(struct platform_device *pdev) goto err; } -debugfs_create_file ("qmss" ,S_IFREG |S_IRUGO ,NULL ,NULL , - &knav_queue_debug_fops); + knav_qdev->debugfs_file = +debugfs_create_file ("qmss" ,0444 ,NULL ,NULL , + &knav_queue_debug_fops); device_ready = true;return 0 ;
@@ -1890,6 +1891,8 @@ static void knav_queue_remove(struct platform_device *pdev)struct knav_device *kdev =platform_get_drvdata (pdev); device_ready = false; +debugfs_remove (kdev->debugfs_file); + kdev->debugfs_file =NULL ;knav_queue_stop_pdsps (kdev);knav_queue_free_regions (kdev);knav_free_queue_ranges (kdev);
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0590/1376] soc: ti: knav_qmss: Remove debugfs file on teardown
Quoted 44 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit
3c817862759913097f11467ed4ed2bbf974dabaf]
knav_queue_probe()creates the global qmss debugfs file whose show callback reads the globalknav_qdevstate.knav_queue_remove()tears down the queue manager resources but leaves the debugfs file published.Save the debugfs dentry in struct
knav_deviceand remove it during teardown before the resources used by the show callback are released. While touching thedebugfs_create_file()call, spell the unchanged read- only file mode as 0444.Fixes 41f93af900a2 ("soc: ti: add Keystone Navigator QMSS driver")Signed-off-by Pengpeng Hou <[email protected]>Signed-off-by Nishanth Menon <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- drivers/soc/ti/knav_qmss.h | 1 + drivers/soc/ti/knav_qmss_queue.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-)drivers/soc/ti/knav_qmss.h +1
-0@@ -304,6 +304,7 @@ struct knav_device {struct list_head pools;struct list_head pdsps;struct list_head qmgrs; +struct dentry *debugfs_file;enum qmss_version version; };drivers/soc/ti/knav_qmss_queue.c +0
-0
drivers/soc/ti/knav_qmss_queue.c static int knav_queue_probe(struct platform_device *pdev) · line 1876
Quoted 8 lines
drivers/soc/ti/knav_qmss_queue.c +3
-2@@ -1871,8 +1871,9 @@ static int knav_queue_probe(struct platform_device *pdev) goto err; } -debugfs_create_file ("qmss" ,S_IFREG |S_IRUGO ,NULL ,NULL , - &knav_queue_debug_fops); + knav_qdev->debugfs_file = +debugfs_create_file ("qmss" ,0444 ,NULL ,NULL , + &knav_queue_debug_fops);
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream code after the later singleton rename:
knav_qdev->debugfs_file =
debugfs_create_file("qmss", 0444, NULL, NULL,
&knav_queue_debug_fops);Downstream 6.12.y declaration and new code:
static struct knav_device *kdev;
knav_qdev->debugfs_file =
debugfs_create_file("qmss", 0444, NULL, NULL,
&knav_queue_debug_fops);The new probe assignment uses knav_qdev->debugfs_file, but the 6.12 driver declares its singleton as static struct knav_device *kdev. The knav_qdev rename exists only in later upstream history, and no such identifier is declared on this branch. Supported Keystone configurations therefore fail to compile the affected object.
Maybe we should be changing knav_qdev to kdev at the new assignment and rebuilding a Keystone ARM configuration before retaining the backport. Thoughts?
thanks,
Harshit
Quoted 12 lines
drivers/soc/ti/knav_qmss_queue.c +2
-0device_ready = true;return 0 ;@@ -1890,6 +1891,8 @@ static void knav_queue_remove(struct platform_device *pdev)struct knav_device *kdev =platform_get_drvdata (pdev); device_ready = false; +debugfs_remove (kdev->debugfs_file); + kdev->debugfs_file =NULL ;knav_queue_stop_pdsps (kdev);knav_queue_free_regions (kdev);knav_free_queue_ranges (kdev);
Greg Kroah-Hartman
maintainerPATCH 591/1376 mtd: mtdswap: Avoid freeing registered blktrans device twice
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 779aa4c66a96bf43d2d62982ea1a9096a9128d87 ]
In mtdswap_add_mtd(), debugfs setup failure after successful blktrans registration can free mbd_dev twice.
add_mtd_blktrans_dev() initializes the blktrans device reference and publishes the disk. Once that succeeds, del_mtd_blktrans_dev() tears the disk down and drops the blktrans reference; when that reference reaches zero, blktrans_dev_release() frees the mtd_blktrans_dev.
The debugfs failure path called del_mtd_blktrans_dev(mbd_dev), then fell through the common cleanup label and called kfree(mbd_dev) again. Clear the local pointer after deregistration so the common cleanup can still release the mtdswap state without freeing the blktrans object twice.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/mtd/mtdswap.c | 1 + 1 file changed, 1 insertion(+)
drivers/mtd/mtdswap.c +1 -0
@@ -1452,6 +1452,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) debugfs_failed:del_mtd_blktrans_dev (mbd_dev); + mbd_dev =NULL ; cleanup:mtdswap_cleanup (d);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 592/1376 mtd: part: reject MTDPART_OFS_RETAIN in mtd_add_partition()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: zhouminqiang <[email protected]>
[ Upstream commit b759d5bb6265419344ee9729fd0dc07ad85719d8 ]
mtd_add_partition() does not reject the special offset value MTDPART_OFS_RETAIN (-3), which leads to a WARN_ON in add_mtd_device() when called through the BLKPG ioctl on NAND devices. The RETAIN value depends on cur_offset being the end of the previous partition, but in the dynamic partition path cur_offset equals the offset argument itself, causing undefined behavior.
Commit 5daa7b21496a ("mtd: prepare partition add and del functions for ioctl requests") introduced mtd_add_partition() and correctly rejected MTDPART_OFS_APPEND (-1) and MTDPART_OFS_NXTBLK (-2), since those special offsets rely on cur_offset tracking the previous partition's end. However, commit 1a31368bf92e ("mtd: add a flags for partitions which should just leave smth. after them") later added MTDPART_OFS_RETAIN (-3) for the static
partition table path without updating mtd_add_partition() to also reject this value.
With offset=-3 passed via BLKPG, the RETAIN size calculation in allocate_partition() underflows (parent_size - 0xFFFFFFFFFFFFFFFD = parent_size + 3). If the underflow result does not appear to leave enough space, allocate_partition() jumps to out_register via goto, skipping erasesize initialization. This results in erasesize=0, which triggers:
WARN_ON((!mtd->erasesize || !master->_erase) &&
!(mtd->flags & MTD_NO_ERASE))
in add_mtd_device(). If the underflow result appears to leave enough space, a bogus partition size is calculated, but the "out of reach" sanity check catches the invalid offset and creates a disabled empty partition (offset=0, size=0) instead of returning an error.
Fix this by adding MTDPART_OFS_RETAIN to the rejection list in mtd_add_partition(), consistent with the existing handling of APPEND and NXTBLK.
--- drivers/mtd/mtdpart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/mtd/mtdpart.c +2 -1
@@ -254,7 +254,8 @@ int mtd_add_partition(struct mtd_info *parent, const char *name,/* the direct offset is expected */ if (offset ==MTDPART_OFS_APPEND || - offset ==MTDPART_OFS_NXTBLK ) + offset ==MTDPART_OFS_NXTBLK || + offset ==MTDPART_OFS_RETAIN )return -EINVAL ;if (length ==MTDPART_SIZ_FULL )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 593/1376 perf ui hists: Fix uninitialized stack memory free on pstack allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit d5fdde1c426922efabe86a515f0782b3eba40577 ]
Fixes heap corruption by initializing the options and actions arrays before the pstack allocation check, preventing an uninitialized stack pointer from being passed to free_popup_options() if the allocation fails.
--- tools/perf/ui/browsers/hists.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/ui/browsers/hists.c +3 -3
@@ -3033,15 +3033,15 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h browser->min_pcnt = min_pcnt;hist_browser__update_nr_entries (browser); +memset (options,0 ,sizeof (options)); +memset (actions,0 ,sizeof (actions)); + browser->pstack =pstack__new (3 );if (browser->pstack ==NULL ) goto out;ui_helpline__push (helpline); -memset (options,0 ,sizeof (options)); -memset (actions,0 ,sizeof (actions)); -if (symbol_conf.col_width_list_str)perf_hpp__set_user_width (symbol_conf.col_width_list_str);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 594/1376 software node: Fix software_node_get_reference_args() with index -1
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alban Bedel <[email protected]>
[ Upstream commit ba3dedcf3bd47017307595a7e54924198f018246 ]
The bounds check for the index passed to software_node_get_reference_args() was failing when passed UINT_MAX, this in turn would lead to an out of bound access in the property array. Fix the bound check to also cover the UINT_MAX case.
--- drivers/base/swnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/base/swnode.c +1 -1
@@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,if (prop->is_inline)return -EINVAL ; -if ((index +1 ) *sizeof (*ref) > prop->length) +if (index >= prop->length /sizeof (*ref))return -ENOENT ; ref_array = prop->pointer;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 595/1376 driver core: soc: Unregister bus on early device registration failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 45dfa004893dfeae182ec27eddbd153c6d4ddbf9 ]
soc_bus_register() registers the SoC bus before registering a deferred early SoC device. If soc_device_register() fails in that path, the function returns the error directly and leaves the bus registered.
Store the returned SoC device pointer explicitly so the success and error cases are handled separately. On failure, clear soc_bus_registered and unregister the bus before returning the error.
--- drivers/base/soc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/base/soc.c +13 -2
@@ -194,6 +194,7 @@ EXPORT_SYMBOL_GPL(soc_device_unregister);static int __init soc_bus_register (void ) { +struct soc_device *soc_dev;int ret; ret =bus_register (&soc_bus_type);
@@ -201,10 +202,20 @@ static int __init soc_bus_register(void)return ret; soc_bus_registered = true; -if (early_soc_dev_attr) -return PTR_ERR (soc_device_register (early_soc_dev_attr)); +if (early_soc_dev_attr) { + soc_dev =soc_device_register (early_soc_dev_attr); +if (IS_ERR (soc_dev)) { + ret =PTR_ERR (soc_dev); + goto err_unregister_bus; + } + }return 0 ; + +err_unregister_bus: + soc_bus_registered = false; +bus_unregister (&soc_bus_type); +return ret; }core_initcall (soc_bus_register);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 596/1376 drm/msm/a6xx: Fix RBBM_CLOCK_CNTL3_TP0 value in a730_hwcg
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Puranam V G Tejaswi <[email protected]>
[ Upstream commit 01bcc0398f43099acb407a6067481e635c3e1b84 ]
The RBBM_CLOCK_CNTL3_TP0 entry in a730_hwcg has bits[19:16] set to 2 (clock gating enabled for that TP0 stage). As per the latest recommendation, clear this nibble to disable clock gating for this particular stage.
Patchwork: https://patchwork.freedesktop.org/patch/740955/
Message-ID: <[email protected]>
--- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/msm/adreno/a6xx_catalog.c +1 -1
@@ -1117,7 +1117,7 @@ static const struct adreno_reglist a730_hwcg[] = { { REG_A6XX_RBBM_CLOCK_DELAY_SP0, 0x00000080 }, { REG_A6XX_RBBM_CLOCK_CNTL_TP0, 0x22222220 }, { REG_A6XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222 }, - { REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22222222 }, + { REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22220222 }, { REG_A6XX_RBBM_CLOCK_CNTL4_TP0, 0x00222222 }, { REG_A6XX_RBBM_CLOCK_HYST_TP0, 0x77777777 }, { REG_A6XX_RBBM_CLOCK_HYST2_TP0, 0x77777777 },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 597/1376 bpf: Reject arena frees below the arena base
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <[email protected]>
[ Upstream commit b5a71cb2db6d84ac0042549dcec266b18429d41e ]
bpf_arena_free_pages() accepts scalar arena addresses. The runtime masks the address to the low 32 bits and reconstructs a full user address from the arena base before returning the range to the arena free tree.
When the scalar value is below the low 32 bits of the arena base, full_uaddr falls below user_vm_start. The existing upper-end clipping then turns this into an out-of-range free-tree offset. A later allocation can reuse that offset and return an address below the arena mapping.
Reject such frees before computing the clipped range.
--- kernel/bpf/arena.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/bpf/arena.c +2 -0
@@ -523,6 +523,8 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt) uaddr = (u32 )uaddr; uaddr &=PAGE_MASK ; full_uaddr =clear_lo32 (arena->user_vm_start) + uaddr; +if (full_uaddr < arena->user_vm_start) +return ; uaddr_end =min (arena->user_vm_end, full_uaddr + (page_cnt <<PAGE_SHIFT ));if (full_uaddr >= uaddr_end)return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 598/1376 dmaengine: dw-edma: Terminate all descriptors without callbacks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 99109a51efd28c9a661fbfb9469b023c517b31d1 ]
The DMA Engine client documentation says in the "Terminate APIs" section of Documentation/driver-api/dmaengine/client.rst:
"No callback functions will be called for any incomplete transfers."
dw-edma instead calls vchan_cookie_complete() when a deferred STOP reaches the interrupt handler. This schedules a callback for the active descriptor and leaves other issued or submitted descriptors queued. A late callback after dmaengine_terminate_sync() can dereference client state that has already been freed, while leftover descriptors may later restart into reused buffers or leak.
Move all issued and submitted descriptors to the terminated list whenever termination completes. For a pending STOP, do this from both the DONE and ABORT paths. Complete their cookies in order without scheduling callbacks.
A STOP can remain pending until the running transfer raises an interrupt. Make device_synchronize() wait for such a pending STOP to complete before releasing terminated descriptors. Reuse it from free_chan_resources(), then release the remaining virt-dma resources. Sleep instead of busy-polling while waiting, and warn if the existing timeout expires.
--- drivers/dma/dw-edma/dw-edma-core.c | 90 +++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 14 deletions(-)
drivers/dma/dw-edma/dw-edma-core.c +76 -14
@@ -7,6 +7,7 @@*/ #include <linux/module.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/dmaengine.h>
@@ -212,6 +213,35 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)return 1 ; } +static void dw_edma_terminate_vdesc (struct virt_dma_desc *vd) +{ +list_del (&vd->node); +dma_cookie_complete (&vd->tx); +vchan_terminate_vdesc (vd); +} + +static void dw_edma_terminate_vdesc_list (struct list_head *head) +{ +struct virt_dma_desc *vd, *_vd; + +list_for_each_entry_safe (vd, _vd, head, node) +dw_edma_terminate_vdesc (vd); +} + +/* Must be called with vc.lock held. */ +static void dw_edma_terminate_all_descs (struct dw_edma_chan *chan) +{ +/* +* This order must not be reversed. Cookies are assigned when +* descriptors are submitted, so desc_issued contains older cookies +* than desc_submitted. Completing desc_submitted first could move +* chan->vc.chan.completed_cookie backwards when desc_issued is +* terminated afterwards. +*/ +dw_edma_terminate_vdesc_list (&chan->vc.desc_issued); +dw_edma_terminate_vdesc_list (&chan->vc.desc_submitted); +} +static void dw_edma_device_caps (struct dma_chan *dchan,struct dma_slave_caps *caps) {
@@ -283,20 +313,22 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan);int err =0 ; +guard (spinlock_irqsave)(&chan->vc.lock); +if (!chan->configured) { -/* Do nothing */ +dw_edma_terminate_all_descs (chan); }else if (chan->status ==EDMA_ST_PAUSE ) { +dw_edma_terminate_all_descs (chan); chan->status =EDMA_ST_IDLE ; - chan->configured = false; }else if (chan->status ==EDMA_ST_IDLE ) { - chan->configured = false; +dw_edma_terminate_all_descs (chan); }else if (dw_edma_core_ch_status (chan) ==DMA_COMPLETE ) {/* * The channel is in a false BUSY state, probably didn't * receive or lost an interrupt */ +dw_edma_terminate_all_descs (chan); chan->status =EDMA_ST_IDLE ; - chan->configured = false; }else if (chan->request >EDMA_REQ_PAUSE ) { err = -EPERM ; }else {
@@ -652,8 +684,7 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)break ;case EDMA_REQ_STOP : -list_del (&vd->node); -vchan_cookie_complete (vd); +dw_edma_terminate_all_descs (chan); chan->request =EDMA_REQ_NONE ; chan->status =EDMA_ST_IDLE ;break ;
@@ -672,7 +703,9 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)spin_lock_irqsave (&chan->vc.lock, flags); vd =vchan_next_desc (&chan->vc); -if (vd) { +if (vd && chan->request ==EDMA_REQ_STOP ) { +dw_edma_terminate_all_descs (chan); + }else if (vd) {dw_hdma_set_callback_result (vd,DMA_TRANS_ABORTED );list_del (&vd->node);vchan_cookie_complete (vd);
@@ -720,21 +753,49 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)return 0 ; } -static void dw_edma_free_chan_resources (struct dma_chan *dchan) +static void dw_edma_wait_termination (struct dma_chan *dchan) { +struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan);unsigned long timeout = jiffies +msecs_to_jiffies (5000 ); -int ret; +bool stopping; +/* +* A STOP may be deferred to a later interrupt while the channel is still +* running. Wait until that handler completes the termination. +*/ while (time_before (jiffies, timeout)) { - ret =dw_edma_device_terminate_all (dchan); -if (!ret) -break ; +scoped_guard (spinlock_irqsave, &chan->vc.lock) + stopping = chan->request == EDMA_REQ_STOP; -if (time_after_eq (jiffies, timeout)) +if (!stopping)return ; -cpu_relax (); +fsleep (1000 ); } + +dev_warn (chan->dw->chip->dev, +"timeout waiting for channel termination\n" ); +} + +static void dw_edma_device_synchronize (struct dma_chan *dchan) +{ +struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); + +dw_edma_wait_termination (dchan); +vchan_synchronize (&chan->vc); +} + +static void dw_edma_free_chan_resources (struct dma_chan *dchan) +{ +struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); + +dw_edma_device_terminate_all (dchan); +dw_edma_device_synchronize (dchan); + +scoped_guard (spinlock_irqsave, &chan->vc.lock) + chan->configured = false; + +vchan_free_chan_resources (&chan->vc); }static int dw_edma_channel_setup (struct dw_edma *dw,u32 wr_alloc,u32 rd_alloc)
@@ -830,6 +891,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc) dma->device_pause = dw_edma_device_pause; dma->device_resume = dw_edma_device_resume; dma->device_terminate_all = dw_edma_device_terminate_all; + dma->device_synchronize = dw_edma_device_synchronize; dma->device_issue_pending = dw_edma_device_issue_pending; dma->device_tx_status = dw_edma_device_tx_status; dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 599/1376 dmaengine: dw-edma: Serialize abort state updates
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit dd80e259f65d932634e26d366570d71669ef6654 ]
dw_edma_abort_interrupt() drops vc.lock before changing request and status. issue_pending() can acquire the lock in that small window, observe the old busy state, and skip starting queued descriptors. Then the abort handler overwrites the channel status as idle, leaving the new descriptors stranded for good.
Keep descriptor completion and the state transition in the same critical section.
--- drivers/dma/dw-edma/dw-edma-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/dw-edma/dw-edma-core.c +1 -1
@@ -710,9 +710,9 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)list_del (&vd->node);vchan_cookie_complete (vd); } -spin_unlock_irqrestore (&chan->vc.lock, flags); chan->request =EDMA_REQ_NONE ; chan->status =EDMA_ST_IDLE ; +spin_unlock_irqrestore (&chan->vc.lock, flags); }static inline irqreturn_t dw_edma_interrupt_write (int irq,void *data)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 600/1376 dmaengine: dw-edma: Serialize channel state checks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit f7d1619f3e10c619b62c6cd6d95371b5c526c85a ]
pause() and resume() read and update channel state without holding vc.lock, while the interrupt handlers update the same state under it. Take the same lock around those state checks so that request, status, and configured stay consistent.
For example, pause() can observe EDMA_ST_BUSY right before the interrupt handler completes the final descriptor and moves the channel to EDMA_ST_IDLE, and then record EDMA_REQ_PAUSE on an already idle channel. No further interrupt will acknowledge the request, and since issue_pending() requires EDMA_REQ_NONE, the channel is wedged for good: terminate_all() leaves the stale request behind, so even reconfiguring the channel does not recover it.
issue_pending() already runs under vc.lock, but it tests configured before taking it. Move that test under the lock as well, so configured, request, and status are evaluated as one channel-state snapshot.
--- drivers/dma/dw-edma/dw-edma-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/dma/dw-edma/dw-edma-core.c +6 -4
@@ -276,6 +276,8 @@ static int dw_edma_device_pause(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan);int err =0 ; +guard (spinlock_irqsave)(&chan->vc.lock); +if (!chan->configured) err = -EPERM ;else if (chan->status !=EDMA_ST_BUSY )
@@ -293,6 +295,8 @@ static int dw_edma_device_resume(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan);int err =0 ; +guard (spinlock_irqsave)(&chan->vc.lock); +if (!chan->configured) { err = -EPERM ; }else if (chan->status !=EDMA_ST_PAUSE ) {
@@ -343,11 +347,9 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan);unsigned long flags; -if (!chan->configured) -return ; -spin_lock_irqsave (&chan->vc.lock, flags); -if (vchan_issue_pending (&chan->vc) && chan->request ==EDMA_REQ_NONE && +if (chan->configured &&vchan_issue_pending (&chan->vc) && + chan->request ==EDMA_REQ_NONE && chan->status ==EDMA_ST_IDLE ) { chan->status =EDMA_ST_BUSY ;dw_edma_start_transfer (chan);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 601/1376 dmaengine: dw-edma: Clear stale requests on termination
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit c0d9c6275adcca7c0ca5f4270bf88026f9864bd1 ]
terminate_all() can finish immediately when the channel is unconfigured, paused, idle, or already stopped in hardware. A pending PAUSE request can survive these paths and block issue_pending() even after termination.
Clear the request whenever termination leaves the channel idle. A running channel keeps its STOP request until the interrupt handler consumes it.
--- drivers/dma/dw-edma/dw-edma-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/dma/dw-edma/dw-edma-core.c +2 -0
@@ -338,6 +338,8 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan) }else { chan->request =EDMA_REQ_STOP ; } +if (chan->status ==EDMA_ST_IDLE ) + chan->request =EDMA_REQ_NONE ;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 602/1376 ASoC: meson: Keep link pointers valid on realloc failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 2aaa41cf974f83a6fb105422bac4e2f107150774 ]
meson_card_reallocate_links() grows the DAI link and private data arrays with two consecutive krealloc() calls and updates the owner pointers only after both calls have succeeded.
A successful krealloc() may move the data: it frees the old block and returns a new one. When that happens for the link array and the second krealloc() then fails, card->dai_link still points to the block that krealloc() already freed, and the error path frees the new block too. The probe error path then calls meson_card_clean_references(), which dereferences card->dai_link and kfree()s it again, resulting in a use-after-free and a double free.
Commit card->dai_link and card->num_links right after the first krealloc() succeeds, so the pointer always refers to a valid allocation that meson_card_clean_references() can walk and free. krealloc() with __GFP_ZERO zero-initializes the added entries, so walking them on the error path is safe. With both failure paths reduced to a plain return, drop the goto labels and the error message.
--- sound/soc/meson/meson-card-utils.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
sound/soc/meson/meson-card-utils.c +6 -11
@@ -50,25 +50,20 @@ int meson_card_reallocate_links(struct snd_soc_card *card, num_links *sizeof (*priv->card.dai_link), GFP_KERNEL | __GFP_ZERO);if (!links) - goto err_links; +return -ENOMEM ; + + priv->card.dai_link = links; + priv->card.num_links = num_links; ldata =krealloc (priv->link_data, num_links *sizeof (*priv->link_data),GFP_KERNEL | __GFP_ZERO); +/* meson_card_clean_references() will free the links on this error path */ if (!ldata) - goto err_ldata; +return -ENOMEM ; - priv->card.dai_link = links; priv->link_data = ldata; - priv->card.num_links = num_links;return 0 ; - -err_ldata: -kfree (links); -err_links: -dev_err (priv->card.dev,"failed to allocate links\n" ); -return -ENOMEM ; - }EXPORT_SYMBOL_GPL (meson_card_reallocate_links);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 603/1376 phy: starfive: Fix runtime PM cleanup in JH7110 DPHY TX probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
[ Upstream commit f40b0241f3a382e99c14de2f28f14a44973407c1 ]
stf_dphy_probe() enables runtime PM before getting the clock and reset controls, creating the PHY and registering the PHY provider. If any of those steps fails, probe returns with runtime PM still enabled.
The driver also has no remove callback, so runtime PM is left enabled on driver unbind after a successful probe.
Use devm_pm_runtime_enable() so runtime PM is disabled automatically on later probe failures and on driver unbind.
--- drivers/phy/starfive/phy-jh7110-dphy-tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/phy/starfive/phy-jh7110-dphy-tx.c +4 -1
@@ -392,6 +392,7 @@ static int stf_dphy_probe(struct platform_device *pdev) {struct phy_provider *phy_provider;struct stf_dphy *dphy; +int ret; dphy =devm_kzalloc (&pdev->dev,sizeof (*dphy),GFP_KERNEL );if (!dphy)
@@ -406,7 +407,9 @@ static int stf_dphy_probe(struct platform_device *pdev)if (IS_ERR (dphy->topsys))return PTR_ERR (dphy->topsys); -pm_runtime_enable (&pdev->dev); + ret =devm_pm_runtime_enable (&pdev->dev); +if (ret) +return ret; dphy->txesc_clk =devm_clk_get (&pdev->dev,"txesc" );if (IS_ERR (dphy->txesc_clk))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 604/1376 phy: starfive: Fix runtime PM cleanup in JH7110 DPHY RX probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
[ Upstream commit 97bed336f6a25c9d1115ca95e3aa00e05c3bc271 ]
stf_dphy_probe() enables runtime PM before registering the PHY provider. If devm_of_phy_provider_register() fails, probe returns with runtime PM still enabled.
The driver also has no remove callback, so runtime PM is left enabled on driver unbind after a successful probe.
Use devm_pm_runtime_enable() so runtime PM is disabled automatically on later probe failures and on driver unbind.
--- drivers/phy/starfive/phy-jh7110-dphy-rx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/phy/starfive/phy-jh7110-dphy-rx.c +4 -1
@@ -150,6 +150,7 @@ static int stf_dphy_probe(struct platform_device *pdev) {struct phy_provider *phy_provider;struct stf_dphy *dphy; +int ret; dphy =devm_kzalloc (&pdev->dev,sizeof (*dphy),GFP_KERNEL );if (!dphy)
@@ -190,7 +191,9 @@ static int stf_dphy_probe(struct platform_device *pdev)return PTR_ERR (dphy->phy); } -pm_runtime_enable (&pdev->dev); + ret =devm_pm_runtime_enable (&pdev->dev); +if (ret) +return ret;phy_set_drvdata (dphy->phy, dphy); phy_provider = devm_of_phy_provider_register(&pdev->dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 605/1376 arm64: dts: amlogic: meson-axg: Add missing nand_rb0 pin to nand_all_pins
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yan <[email protected]>
[ Upstream commit 45eb76f9ab6854f79690d56d04df227429a536b8 ]
The nand_all_pins pinctrl node was missing the nand_rb0 (ready/busy) pin description, which is required for NAND controller operation.
Add it to the pinmux list.
--- arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/amlogic/meson-axg.dtsi +2 -1
@@ -454,7 +454,8 @@ mux { "nand_ale", "nand_cle", "nand_wen_clk", - "nand_ren_wr"; + "nand_ren_wr", + "nand_rb0"; function = "nand"; input-enable; bias-pull-up;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 606/1376 arm64: dts: amlogic: meson-axg-s400: enable mipi_pcie_analog_dphy for PCIe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yan <[email protected]>
[ Upstream commit 7f1d0cc86cb70fa550163b6f70fd1d484c03218e ]
The PCIe PHY node references mipi_pcie_analog_dphy via its phys property. Enable this analog PHY node to make PCIe functionally viable.
--- arch/arm64/boot/dts/amlogic/meson-axg-s400.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/boot/dts/amlogic/meson-axg-s400.dts +4 -0
@@ -432,6 +432,10 @@ gpio_speaker: gpio-controller@1f { }; }; +&mipi_pcie_analog_dphy { + status = "okay"; +}; + &pdm { pinctrl-0 = <&pdm_dclk_a14_pins>, <&pdm_din0_pins>, <&pdm_din1_pins>, <&pdm_din2_pins>, <&pdm_din3_pins>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 607/1376 RDMA/hfi1: Propagate sdma_txinit_ahg() errors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danila Chernetsov <[email protected]>
[ Upstream commit 091c6162c022cbdfb64219708a71728cfd1d4600 ]
set_txreq_header_ahg() ignores the return value of sdma_txinit_ahg().
If sdma_txinit_ahg() fails, it returns before initializing tx->txreq. However, set_txreq_header_ahg() ignores the error and returns the AHG change count, causing the caller to continue processing the request as though initialization had succeeded.
Propagate sdma_txinit_ahg() failures to the caller and abort request processing when initialization fails.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/infiniband/hw/hfi1/user_sdma.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/infiniband/hw/hfi1/user_sdma.c +8 -5
@@ -1028,6 +1028,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req, struct user_sdma_txreq *tx, u32 datalen) {u32 ahg[AHG_KDETH_ARRAY_SIZE ]; +int ret;int idx =0 ;u8 omfactor;/* KDETH.OM */ struct hfi1_user_sdma_pkt_q *pq = req->pq;
@@ -1132,11 +1133,13 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,trace_hfi1_sdma_user_header_ahg (pq->dd, pq->ctxt, pq->subctxt, req->info.comp_idx, req->sde->this_idx, req->ahg_idx, ahg, idx, tidval); -sdma_txinit_ahg (&tx->txreq, -SDMA_TXREQ_F_USE_AHG , - datalen, req->ahg_idx, idx, - ahg,sizeof (req->hdr), - user_sdma_txreq_cb); + ret =sdma_txinit_ahg (&tx->txreq, +SDMA_TXREQ_F_USE_AHG , + datalen, req->ahg_idx, idx, + ahg,sizeof (req->hdr), + user_sdma_txreq_cb); +if (ret) +return ret;return idx; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 608/1376 RDMA/rxe: Validate num_sge/cur_sge before indexing wqe->dma.sge[]
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
[ Upstream commit 126c757e4cd46f866ddc283143b58eb4d9bf52cd ]
For a user QP, qp->sq.queue is a ring the application writes directly, so rxe_post_send() takes the is_user branch and only schedules send_task without validating the WQE. rxe_requester() consumes it in place via req_next_wqe() and calls copy_data(), which indexes &wqe->dma.sge[cur_sge] with the attacker-controlled num_sge/cur_sge. Only the kernel path bounds num_sge (validate_send_wr()); the user WQE is never checked, so a local unprivileged user can post a WQE with an out-of-range cur_sge or oversized num_sge and force an out-of-bounds read of the per-WQE sge array in copy_data() (vmalloc OOB read, local DoS).
Bound num_sge to qp->sq.max_sge in rxe_requester() before use, the way get_srq_wqe() already guards SRQ entries, and bound cur_sge only when the WQE carries payload (dma.resid): copy_data() returns early on a zero-length copy before touching dma->sge[], so a zero-payload WQE -- the only kind a max_sge == 0 QP can post -- stays valid.
Reproduced under KASAN; the vmalloc-out-of-bounds in copy_data() is gone.
--- drivers/infiniband/sw/rxe/rxe_req.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/infiniband/sw/rxe/rxe_req.c +15 -0
@@ -702,6 +702,21 @@ int rxe_requester(struct rxe_qp *qp)if (unlikely (!wqe)) goto exit; +/* +* Don't trust user space data: a user QP's WQE comes from an mmap'd +* ring, so num_sge/cur_sge are attacker-controlled. Bound num_sge like +* get_srq_wqe(); bound cur_sge only when payload exists (dma.resid), +* since copy_data() skips dma->sge[] on a zero-length copy (all a +* max_sge == 0 QP can post). +*/ +if (unlikely (wqe->dma.num_sge > qp->sq.max_sge || + (wqe->dma.resid && + wqe->dma.cur_sge >= qp->sq.max_sge))) { +rxe_dbg_qp (qp,"invalid num_sge/cur_sge in send wqe\n" ); + wqe->status =IB_WC_LOC_QP_OP_ERR ; + goto err; + } +if (rxe_wqe_is_fenced (qp, wqe)) { qp->req.wait_fence =1 ; goto exit;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 609/1376 RDMA/srpt: Fix srpt_alloc_rw_ctxs() unwind counters
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: TanZheng <[email protected]>
[ Upstream commit b38f98e176050850f41bb6415f3a71400056623e ]
When srpt_alloc_rw_ctxs() fails partway through a multi-buffer indirect descriptor, the unwind path destroys RDMA contexts but leaves stale n_rw_ctx and n_rdma values (and a dangling rw_ctxs pointer). Later sq_wr_avail accounting in srpt_queue_response() or srpt_write_pending() can then subtract the wrong number of send queue credits.
Reset the counters and clear rw_ctxs after freeing the heap allocation before returning an error.
--- drivers/infiniband/ulp/srpt/ib_srpt.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/infiniband/ulp/srpt/ib_srpt.c +7 -0
@@ -959,6 +959,7 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx,struct srpt_rdma_ch *ch = ioctx->ch;struct scatterlist *prev =NULL ;unsigned prev_nents; +u8 n_rdma, n_rw_ctx;int ret, i;if (nbufs ==1 ) {
@@ -970,6 +971,9 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx,return -ENOMEM ; } + n_rw_ctx = ioctx->n_rw_ctx; + n_rdma = ioctx->n_rdma; +for (i = ioctx->n_rw_ctx; i < nbufs; i++, db++) {struct srpt_rw_ctx *ctx = &ioctx->rw_ctxs[i];u64 remote_addr =be64_to_cpu (db->va);
@@ -1016,6 +1020,9 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx, }if (ioctx->rw_ctxs != &ioctx->s_rw_ctx)kfree (ioctx->rw_ctxs); + ioctx->rw_ctxs =NULL ; + ioctx->n_rw_ctx = n_rw_ctx; + ioctx->n_rdma = n_rdma;return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 610/1376 kcsan: avoid unintended access checking in NMIs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Elver <[email protected]>
[ Upstream commit a8488ecbd7ba44d65b912dfe88a73f438eba2447 ]
If a watcher deliberately disables interrupts (either by user choice, or because we're dealing with a scoped reordered access) to avoid detecting any data races in interrupts, NMIs are still able to fire.
When we set up a watchpoint on a scoped reordered access, we disabled interrupts because the same CPU cannot observe reordering of its own accesses. To ensure we observe no false positives from NMIs, disable access checking for interrupt contexts as well.
--- kernel/kcsan/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/kcsan/core.c +10 -2
@@ -585,8 +585,14 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned* information is lost if dirtied by KCSAN. */ kcsan_save_irqtrace (current); -if (!interrupt_watcher) +if (!interrupt_watcher) {local_irq_save (irq_flags); +/* +* NMIs can still fire, disable checking for all interrupt +* contexts. +*/ +raw_cpu_ptr (&kcsan_cpu_ctx)->disable_count++; + } watchpoint =insert_watchpoint ((unsigned long )ptr, size, is_write);if (watchpoint ==NULL ) {
@@ -699,8 +705,10 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsignedatomic_long_dec (&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS ]); out_unlock: -if (!interrupt_watcher) +if (!interrupt_watcher) { +raw_cpu_ptr (&kcsan_cpu_ctx)->disable_count--;local_irq_restore (irq_flags); + }kcsan_restore_irqtrace (current); ctx->disable_scoped--;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 611/1376 arm64: dts: imx8-ss-audio: Fix LPCG clock indices for ASRC0
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Li <[email protected]>
[ Upstream commit 8563591f76ca02c1a6fd70ce986df1d0dde8d249 ]
The LPCG clock indices for ASRC0 and AUD_PLL_DIV0 are swapped. The ASRC0 LPCG provides only IMX_LPCG_CLK_4, so update the ASRC0 clock consumer to use IMX_LPCG_CLK_4 instead of the non-existent IMX_LPCG_CLK_0.
Likewise, the AUD_PLL_DIV0 LPCG provides only IMX_LPCG_CLK_0, so update its clock consumer to use IMX_LPCG_CLK_0 instead of the non-existent IMX_LPCG_CLK_4.
--- arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +4 -4
@@ -124,10 +124,10 @@ asrc0: asrc@59000000 { compatible = "fsl,imx8qm-asrc"; reg = <0x59000000 0x10000>; interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&asrc0_lpcg IMX_LPCG_CLK_0>, - <&asrc0_lpcg IMX_LPCG_CLK_0>, - <&aud_pll_div0_lpcg IMX_LPCG_CLK_4>, - <&aud_pll_div1_lpcg IMX_LPCG_CLK_4>, + clocks = <&asrc0_lpcg IMX_LPCG_CLK_4>, + <&asrc0_lpcg IMX_LPCG_CLK_4>, + <&aud_pll_div0_lpcg IMX_LPCG_CLK_0>, + <&aud_pll_div1_lpcg IMX_LPCG_CLK_0>, <&acm IMX_ADMA_ACM_AUD_CLK0_SEL>, <&acm IMX_ADMA_ACM_AUD_CLK1_SEL>, <&clk_dummy>,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 612/1376 selftests/bpf: Silence array bounds warning in global_map_resize
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viktor Malik <[email protected]>
[ Upstream commit dcd164ec67f89e0db5ee025ee9e91280052eb737 ]
When compiling BPF selftests with -O2, GCC reports an array bounds violation warning in global_map_resize test:
In function ‘global_map_resize_bss_subtest’,
inlined from ‘test_global_map_resize’ at /bpf-next/tools/testing/selftests/bpf/prog_tests/global_map_resize.c:228:3:
/bpf-next/tools/testing/selftests/bpf/prog_tests/global_map_resize.c:64:33: error: array subscript 1 is above array bounds of ‘int[1]’ [-Werror=array-bounds=]
64 | skel->bss->array[i] = 1;
| ~~~~~~~~~~~~~~~~^~~
In file included from /bpf-next/tools/testing/selftests/bpf/prog_tests/global_map_resize.c:6:
./test_global_map_resize.skel.h: In function ‘test_global_map_resize’:
./test_global_map_resize.skel.h:44:21: note: while referencing ‘array’
44 | int array[1];
| ^~~~~
This is a false positive because array (a BPF map) has been resized from within the BPF program. GCC doesn't know that so let us silence the warning by accessing the array via a plain pointer.
--- .../testing/selftests/bpf/prog_tests/global_map_resize.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/testing/selftests/bpf/prog_tests/global_map_resize.c +6 -2
@@ -23,6 +23,7 @@ static void global_map_resize_bss_subtest(void)struct bpf_map *map;const __u32 desired_sz =sizeof (skel->bss->sum) +sysconf (_SC_PAGE_SIZE) *2 ;size_t array_len, actual_sz, new_sz; +int *array; skel =test_global_map_resize__open ();if (!ASSERT_OK_PTR (skel,"test_global_map_resize__open" ))
@@ -58,10 +59,13 @@ static void global_map_resize_bss_subtest(void) goto teardown;/* fill the newly resized array with ones, -* skipping the first element which was previously set +* skipping the first element which was previously set; +* access through a plain pointer to avoid -Warray-bounds +* since the array was resized beyond its declared length. */ + array = skel->bss->array;for (int i =1 ; i < array_len; i++) - skel->bss->array[i] =1 ; + array[i] =1 ;/* set global const values before loading */ skel->rodata->pid =getpid ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 613/1376 irqchip/gic-v3-its: Prevent leak in its_vpe_irq_domain_alloc()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kemeng Shi <[email protected]>
[ Upstream commit 325ff3e78c64cd619d52b99f7c8b09a3f31e1495 ]
When its_irq_gic_domain_alloc() fails, the following its_vpe_irq_domain_free() fails to invoke its_vep_teardown() for the corresponding interrupt, which leaks the resource.
Invoke its_vpe_teardown() in the error handling path to avoid the leak.
[ tglx: Massaged change log ]
--- drivers/irqchip/irq-gic-v3-its.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +10 -1
@@ -4503,6 +4503,13 @@ static int its_vpe_init(struct its_vpe *vpe)static void its_vpe_teardown (struct its_vpe *vpe) { +/* +* If vpt_page is NULL, then its_vpe_init() has failed, and +* there is nothing to do as no resource has been allocated. +*/ +if (vpe->vpt_page ==NULL ) +return ; +its_vpe_db_proxy_unmap (vpe);its_vpe_id_free (vpe->vpe_id);its_free_pending_table (vpe->vpt_page);
@@ -4583,8 +4590,10 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virqirqd_set_resend_when_in_progress (irq_get_irq_data (virq + i)); } -if (err) +if (err) { +its_vpe_teardown (vm->vpes[i]);its_vpe_irq_domain_free (domain, virq, i); + }return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 614/1376 RDMA/nldev: validate dynamic counter attribute length
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 74f49255492a62658f36bf2578d7916f1c6ffad1 ]
RDMA_NLDEV_ATTR_STAT_HWCOUNTERS is a nested attribute whose children are consumed directly with nla_get_u32(). The top-level policy validates only the container, so it does not establish the fixed shape of each child.
Require every child payload to be exactly one u32 before reading it.
--- drivers/infiniband/core/nldev.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/infiniband/core/nldev.c +5 -0
@@ -2093,6 +2093,11 @@ static int nldev_stat_set_counter_dynamic_doit(struct nlattr *tb[],nla_for_each_nested (entry_attr, tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS ], rem) { +if (nla_len (entry_attr) !=sizeof (u32)) { + ret = -EINVAL ; + goto out; + } + index =nla_get_u32 (entry_attr);if ((index >= stats->num_counters) || !(stats->descs[index].flags &IB_STAT_FLAG_OPTIONAL )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 615/1376 ACPI: EC: Avoid _REG disconnect on GPIO IRQ defer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhu Ling <[email protected]>
[ Upstream commit e71bdbce27dcaa7f467a3a198cbe723924f05569 ]
EC event delivery uses either a GPE or, on ACPI reduced hardware platforms, a GpioInt resource. The GPE path does not have a provider lookup that can defer, but acpi_dev_gpio_irq_get() can return -EPROBE_DEFER for the GpioInt path.
ec_install_handlers() currently installs the EC address space handler and executes _REG before looking up the GPIO IRQ. If the GPIO lookup then defers, acpi_ec_setup() tears the handlers down again. Removing the EC address space handler causes ACPICA to execute _REG for disconnect, so firmware may observe an EC OpRegion connected -> disconnected transition during one failed probe attempt.
This is observable when the namespace EC reuses a boot EC that has already installed the EC address space handler. A deferred namespace EC probe can disconnect the already usable boot EC OpRegion until a later reprobe connects it again. AML that gates EC field accesses on _REG state can then return fallback values to other drivers during that window.
Prepare the GPIOInt IRQ before publishing EC OpRegion availability to AML. This leaves the GPE path unchanged, keeps non-deferred GPIO lookup errors non-fatal as before, and still lets the existing acpi_ec_setup() error path clean up real handler installation failures.
--- drivers/acpi/ec.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-)
drivers/acpi/ec.c +26 -14
@@ -1510,6 +1510,24 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec) IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0; } +static int ec_prepare_gpio_irq (struct acpi_ec *ec,struct acpi_device *device) +{ +int irq; + +if (!device || ec->gpe >=0 || ec->irq >=0 ) +return 0 ; + +/* ACPI reduced hardware platforms use a GpioInt from _CRS. */ + irq =acpi_dev_gpio_irq_get (device,0 ); +if (irq == -EPROBE_DEFER ) +return irq; + +if (irq >=0 ) + ec->irq = irq; + +return 0 ; +} +/** * ec_install_handlers - Install service callbacks and register query methods. * @ec: Target EC.
@@ -1524,7 +1542,6 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)* Return: * -ENODEV if the address space handler cannot be installed, which means * "unable to handle transactions", -* -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred, * or 0 (success) otherwise. */ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
@@ -1557,19 +1574,6 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,if (!device)return 0 ; -if (ec->gpe <0 ) { -/* ACPI reduced hardware platforms use a GpioInt from _CRS. */ -int irq =acpi_dev_gpio_irq_get (device,0 ); -/* -* Bail out right away for deferred probing or complete the -* initialization regardless of any other errors. -*/ -if (irq == -EPROBE_DEFER ) -return -EPROBE_DEFER ; -else if (irq >=0 ) - ec->irq = irq; - } -if (!test_bit (EC_FLAGS_QUERY_METHODS_INSTALLED , &ec->flags)) {/* Find and register all query methods */ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
@@ -1647,6 +1651,14 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca {int ret; +/* +* GPIO IRQ lookup can defer. Do it before publishing the EC +* OpRegion to AML to avoid a spurious _REG(disconnect). +*/ + ret =ec_prepare_gpio_irq (ec, device); +if (ret) +return ret; +/* First EC capable of handling transactions */ if (!first_ec) first_ec = ec;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 616/1376 ACPI: processor: validate MADT IOAPIC entry bounds
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 2c50ffdc73f3a70d745d249f509fc290754121e6 ]
The IOAPIC hotplug lookup parses both MADT and _MAT records directly. The MADT walk previously used a subtable's declared length to advance the cursor after only locating a generic header. The _MAT path likewise passed a generic header to the IOAPIC helper.
Validate that a current record has a complete generic header, that its declared length is contained in the available record range, and that a typed IOAPIC record contains the full fixed IOAPIC body before reading its fields. Use the same relation for both MADT and _MAT provider paths.
--- drivers/acpi/processor_core.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
drivers/acpi/processor_core.c +25 -6
@@ -336,11 +336,26 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)EXPORT_SYMBOL_GPL (acpi_get_cpuid);#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC -static int get_ioapic_id (struct acpi_subtable_header *entry,u32 gsi_base, +static bool madt_entry_is_valid (struct acpi_subtable_header *entry, +unsigned long end) +{ +unsigned long start = (unsigned long )entry; + +if (start >= end || end - start <sizeof (*entry)) +return false; + +return entry->length >=sizeof (*entry) && entry->length <= end - start; +} + +static int get_ioapic_id (struct acpi_subtable_header *entry, +const unsigned long end,u32 gsi_base,u64 *phys_addr,int *ioapic_id) {struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; +if (!madt_entry_is_valid (entry, end) ||BAD_MADT_ENTRY (ioapic, end)) +return 0 ; +if (ioapic->global_irq_base != gsi_base)return 0 ;
@@ -361,17 +376,19 @@ static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)return apic_id; entry = (unsigned long )madt; +if (madt->header.length <sizeof (*madt)) +return apic_id; madt_end = entry + madt->header.length;/* Parse all entries looking for a match. */ entry +=sizeof (struct acpi_table_madt ); -while (entry +sizeof (struct acpi_subtable_header ) < madt_end) { +while (madt_entry_is_valid ((struct acpi_subtable_header *)entry, + madt_end)) { hdr = (struct acpi_subtable_header *)entry;if (hdr->type ==ACPI_MADT_TYPE_IO_APIC && -get_ioapic_id (hdr, gsi_base, phys_addr, &apic_id)) +get_ioapic_id (hdr, madt_end, gsi_base, phys_addr, &apic_id))break ; -else - entry += hdr->length; + entry += hdr->length; }return apic_id;
@@ -398,7 +415,9 @@ static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, header = (struct acpi_subtable_header *)obj->buffer.pointer;if (header->type ==ACPI_MADT_TYPE_IO_APIC ) -get_ioapic_id (header, gsi_base, phys_addr, &apic_id); +get_ioapic_id (header, + (unsigned long )header + obj->buffer.length, + gsi_base, phys_addr, &apic_id); exit:kfree (buffer.pointer);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 617/1376 ACPI: PCI: Clear driver_data on all paths that free the acpi_pci_root
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Pei <[email protected]>
[ Upstream commit 8a742141f7ab84975aa758b775567ef4740ef0cf ]
acpi_pci_root_add() assigns the freshly allocated root to device->driver_data before dmar_device_add() and pci_acpi_scan_root(). Both failure paths reach the end: label where root is kfree()'d, but only the pci_acpi_scan_root() path clears driver_data first.
When dmar_device_add() fails during a hot-add, root is freed while device->driver_data still points at it. The ACPI core does not clear driver_data on attach failure, so a later acpi_pci_find_root() call may dereference this dangling pointer.
acpi_pci_root_remove() has the same problem: it frees root without clearing device->driver_data, leaving a dangling pointer behind after the root bridge is removed.
Move the NULL assignment to the shared end: label so every error path in acpi_pci_root_add() clears driver_data before freeing root, and clear it in acpi_pci_root_remove() as well, so the object is never left reachable through driver_data after being freed.
--- drivers/acpi/pci_root.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/acpi/pci_root.c +2 -1
@@ -730,7 +730,6 @@ static int acpi_pci_root_add(struct acpi_device *device,dev_err (&device->dev,"Bus %04x:%02x not present in PCI namespace\n" , root->segment, (unsigned int )root->secondary.start); - device->driver_data =NULL ; result = -ENODEV ; goto remove_dmar; }
@@ -766,6 +765,7 @@ static int acpi_pci_root_add(struct acpi_device *device,if (hotadd)dmar_device_remove (handle); end: + device->driver_data =NULL ;kfree (root);return result; }
@@ -789,6 +789,7 @@ static void acpi_pci_root_remove(struct acpi_device *device)pci_unlock_rescan_remove (); + device->driver_data =NULL ;kfree (root); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 618/1376 ext4: fix circular lock dependency in ext4_ext_migrate
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit a897682793eba5de51ee6f3152760374afa629cf ]
Move iput(tmp_inode) after ext4_writepages_up_write() to avoid a circular lock dependency between s_writepages_rwsem and sb_internal (freeze protection).
The deadlock scenario:
CPU0 (EXT4_IOC_MIGRATE) CPU1 (orphan cleanup during mount)
---- ----
ext4_ext_migrate()
ext4_writepages_down_write()
s_writepages_rwsem (write)
ext4_evict_inode()
sb_start_intwrite() [sb_internal]
...
ext4_writepages()
s_writepages_rwsem (read) [BLOCKED]
iput(tmp_inode)
ext4_evict_inode()
sb_start_intwrite() [BLOCKED]The tmp_inode is a temporary inode with nlink=0 created solely for building the extent tree. Its eviction does not require s_writepages_rwsem protection, so deferring iput() until after releasing the rwsem is safe.
--- fs/ext4/migrate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/migrate.c +2 -1
@@ -458,6 +458,7 @@ int ext4_ext_migrate(struct inode *inode)if (IS_ERR (tmp_inode)) { retval =PTR_ERR (tmp_inode);ext4_journal_stop (handle); + tmp_inode =NULL ; goto out_unlock; }/*
@@ -585,9 +586,9 @@ int ext4_ext_migrate(struct inode *inode)ext4_journal_stop (handle); out_tmp_inode:unlock_new_inode (tmp_inode); -iput (tmp_inode); out_unlock:ext4_writepages_up_write (inode->i_sb, alloc_ctx); +iput (tmp_inode);return retval; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 619/1376 ext4: fix out-of-bounds read in ext4_read_inline_dir()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 9333cc809f0a89e001b814155a6cb8903a6274df ]
ext4_read_inline_dir() can read a dirent header past the end of its inline buffer, triggering a slab-out-of-bounds read during getdents64():
BUG: KASAN: slab-out-of-bounds in __ext4_check_dir_entry Read of size 2 at addr ffff88800f3dd23c by task exploit/148 ... __ext4_check_dir_entry ext4_read_inline_dir iterate_dir
The dirent payload lives in a buffer of exactly inline_size bytes:
dir_buf = kmalloc(inline_size, GFP_NOFS);
but iteration runs in a position space extra_offset bytes larger (extra_size = extra_offset + inline_size) so the synthetic "." and ".." land at their block-dir offsets. A dirent is formed at "dir_buf + pos - extra_offset", yet the ext4_check_dir_entry() length argument uses the larger extra_size. A position whose dirent header would extend past extra_size is therefore accepted, and the rescan loop's rec_len probe and ext4_check_dir_entry() dereference de->rec_len before the entry is rejected.
Reject a position whose minimum-size dirent header would not fit within extra_size before forming de, in both the rescan and main loops, and pass inline_size rather than extra_size to ext4_check_dir_entry() so the length check matches the physical buffer.
--- fs/ext4/inline.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
fs/ext4/inline.c +10 -1
@@ -1554,6 +1554,8 @@ int ext4_read_inline_dir(struct file *file,/* for other entry, the real offset in * the buf has to be tuned accordingly. */ +if (i +ext4_dir_rec_len (1 ,NULL ) > extra_size) +break ; de = (struct ext4_dir_entry_2 *) (dir_buf + i - extra_offset);/* It's too expensive to do a full
@@ -1588,10 +1590,17 @@ int ext4_read_inline_dir(struct file *file,continue ; } +/* +* de lives at dir_buf + ctx->pos - extra_offset, within the +* kmalloc(inline_size) buffer. Make sure its header fits before +* ext4_check_dir_entry() dereferences de->rec_len. +*/ +if (ctx->pos +ext4_dir_rec_len (1 ,NULL ) > extra_size) + goto out; de = (struct ext4_dir_entry_2 *) (dir_buf + ctx->pos - extra_offset);if (ext4_check_dir_entry (inode, file, de, iloc.bh, dir_buf, - extra_size, ctx->pos)) + inline_size, ctx->pos)) goto out; if (le32_to_cpu(de->inode)) { if (!dir_emit(ctx, de->name, de->name_len,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 620/1376 ext4: skip extra isize expansion during mount to prevent deadlock
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit 7461c60b9c6a839b13ad4c3490681a0cf5aa0637 ]
ext4_try_to_expand_extra_isize() is called from __ext4_mark_inode_dirty() while holding an active jbd2 handle. During mount (!SB_ACTIVE), the expand path may move xattrs to external blocks and release ea_inodes via iput(). When !SB_ACTIVE, iput() calls write_inode_now() which acquires s_writepages_rwsem, creating a circular lock dependency:
s_writepages_rwsem --> jbd2_handle --> xattr_sem --> s_writepages_rwsem
This can be triggered via:
ext4_process_orphan() -> ext4_truncate() -> ext4_mark_inode_dirty()
-> ext4_try_to_expand_extra_isize()
or:
ext4_evict_inode() -> ext4_mark_inode_dirty()
-> ext4_try_to_expand_extra_isize()
Skip expansion when !SB_ACTIVE. This is a minor loss of functionality (extra isize won't grow for these inodes during mount), which e2fsck can resolve later if needed.
--- fs/ext4/inode.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/ext4/inode.c +10 -0
@@ -5975,6 +5975,16 @@ static int ext4_try_to_expand_extra_isize(struct inode *inode,if (ext4_test_inode_state (inode,EXT4_STATE_NO_EXPAND ))return -EOVERFLOW ; +/* +* Skip expansion during mount (!SB_ACTIVE). Expanding extra isize +* may move xattrs to external blocks and release ea_inodes via iput. +* When !SB_ACTIVE, iput triggers write_inode_now() which acquires +* s_writepages_rwsem, causing a deadlock with the caller's active +* jbd2 handle (lock order: s_writepages_rwsem -> jbd2_handle). +*/ +if (unlikely (!(inode->i_sb->s_flags &SB_ACTIVE ))) +return -EBUSY ; +/* * In nojournal mode, we can immediately attempt to expand * the inode. When journaled, we first need to obtain extra
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 621/1376 libbpf: Search /lib64 and /lib in resolve_full_path()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo B. Marlière <[email protected]>
[ Upstream commit 7b5ae0481efdac040cea72b4fabd1398109f975b ]
attach_probe/uprobe-lib and uprobe_autoattach selftests fail with "failed to resolve full path for libc.so.6" on older non-usrmerged distros, where libc.so.6 lives under a top-level /lib64 or /lib rather than /usr/lib64 or /usr/lib. Add /lib64:/lib to the search paths, alongside the existing /usr/lib64:/usr/lib and Debian multiarch entries.
--- tools/lib/bpf/libbpf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/lib/bpf/libbpf.c +2 -1
@@ -11946,13 +11946,14 @@ static const char *arch_specific_lib_paths(void)/* Get full path to program/shared library. */ static int resolve_full_path (const char *file,char *result,size_t result_sz) { -const char *search_paths[3 ] = {}; +const char *search_paths[4 ] = {};int i, perm;if (str_has_sfx (file,".so" ) ||strstr (file,".so." )) { search_paths[0 ] =getenv ("LD_LIBRARY_PATH" ); search_paths[1 ] ="/usr/lib64:/usr/lib" ; search_paths[2 ] =arch_specific_lib_paths (); + search_paths[3 ] ="/lib64:/lib" ; perm =R_OK ; }else { search_paths[0 ] =getenv ("PATH" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 622/1376 riscv, bpf: Fix memory leak in bpf_jit_free
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 369e4635d04801f394d5bd42556f21029e95ff93 ]
When bpf_int_jit_compile() is called for subprograms, it returns early during the first pass (!prog->is_func || extra_pass is false), keeping ctx->offset alive for the subsequent extra pass.
If JIT compilation fails for a later subprogram, the BPF core aborts and calls bpf_jit_free() to clean up the first subprogram. However, bpf_jit_free() fails to free jit_data->ctx.offset, which causes a memory leak of the JIT context offsets array.
Fix this by adding the missing kfree(jit_data->ctx.offset) in bpf_jit_free().
--- arch/riscv/net/bpf_jit_core.c | 1 + 1 file changed, 1 insertion(+)
arch/riscv/net/bpf_jit_core.c +1 -0
@@ -259,6 +259,7 @@ void bpf_jit_free(struct bpf_prog *prog)*/ if (jit_data) {bpf_jit_binary_pack_finalize (jit_data->ro_header, jit_data->header); +kfree (jit_data->ctx.offset);kfree (jit_data); } hdr =bpf_jit_binary_pack_hdr (prog);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 623/1376 ACPI: battery: Adjust charging status validation check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit 77ce4be0d8d53c528d1663ab62a14d93d5853f11 ]
Commit bb1256e0ddc7 ("ACPI: battery: fix incorrect charging status when current is zero") added a charge rate check to validate the "charging" status of the battery, but that check is reported to cause some systems to misbehave [1]. Namely, it causes the "not charging" status to be reported on them while the battery is in fact charging (and they were correctly reporting the "charging" status in that case previously).
To address that, check if the battery is full in addition to checking the charge rate when the "charging" status is reported by the platform firmware and only change it to "not charging" if the battery is full and its charge rate is zero or it is unknown.
--- drivers/acpi/battery.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-)
drivers/acpi/battery.c +19 -17
@@ -151,27 +151,28 @@ static int acpi_battery_technology(struct acpi_battery *battery)static int acpi_battery_get_state (struct acpi_battery *battery); -static int acpi_battery_is_charged (struct acpi_battery *battery) +static bool acpi_battery_is_full (struct acpi_battery *battery) { -/* charging, discharging, critical low or charge limited */ -if (battery->state !=0 ) -return 0 ; -/* battery not reporting charge */ if (battery->capacity_now ==ACPI_BATTERY_VALUE_UNKNOWN || battery->capacity_now ==0 ) -return 0 ; +return false;/* good batteries update full_charge as the batteries degrade */ if (battery->full_charge_capacity == battery->capacity_now) -return 1 ; +return true;/* fallback to using design values for broken batteries */ -if (battery->design_capacity <= battery->capacity_now) -return 1 ; +return battery->design_capacity <= battery->capacity_now; +} -/* we don't do any sort of metric based on percentages */ -return 0 ; +static int acpi_battery_is_charged (struct acpi_battery *battery) +{ +/* charging, discharging, critical low or charge limited */ +if (battery->state !=0 ) +return 0 ; + +return acpi_battery_is_full (battery); }static bool acpi_battery_is_degraded (struct acpi_battery *battery)
@@ -212,13 +213,14 @@ static int acpi_battery_get_property(struct power_supply *psy,if (battery->state &ACPI_BATTERY_STATE_DISCHARGING ) val->intval =acpi_battery_handle_discharging (battery);else if (battery->state &ACPI_BATTERY_STATE_CHARGING ) -/* Validate the status by checking the current. */ -if (battery->rate_now !=ACPI_BATTERY_VALUE_UNKNOWN && - battery->rate_now ==0 ) { -/* On charge but no current (0W/0mA). */ - val->intval =POWER_SUPPLY_STATUS_NOT_CHARGING ; - }else { +/* Check the rate and capacity to validate the status. */ +if (!acpi_battery_is_full (battery) || + (battery->rate_now !=ACPI_BATTERY_VALUE_UNKNOWN && + battery->rate_now >0 )) { val->intval =POWER_SUPPLY_STATUS_CHARGING ; + }else { +/* Full and zero rate. */ + val->intval =POWER_SUPPLY_STATUS_NOT_CHARGING ; }else if (battery->state &ACPI_BATTERY_STATE_CHARGE_LIMITING ) val->intval =POWER_SUPPLY_STATUS_NOT_CHARGING ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 624/1376 bpf: Preserve unique-field state across nested structs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit f08619f060468076e4acbdc10e0713af20d60e65 ]
btf_find_struct_field() initializes a fresh seen mask for every recursive descent. Unique special fields in different levels of the same aggregate therefore do not see one another. The duplicate fields can reach btf_parse_fields(), where they trigger an invariant WARN_ON_ONCE(). A crafted user BTF can consequently trigger the warning before map creation checks capabilities.
Initialize the seen mask once in btf_find_field() and pass the same pointer through struct, datasec, and nested-struct walks. This gives the entire field traversal one shared uniqueness state.
--- kernel/bpf/btf.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
kernel/bpf/btf.c +14 -12
@@ -3565,7 +3565,7 @@ static int btf_repeat_fields(struct btf_field_info *info, int info_cnt,static int btf_find_struct_field (const struct btf *btf,const struct btf_type *t,u32 field_mask,struct btf_field_info *info,int info_cnt, -u32 level); +u32 level,u32 *seen_mask);/* Find special fields in the struct type of a field. *
@@ -3576,7 +3576,7 @@ static int btf_find_struct_field(const struct btf *btf,static int btf_find_nested_struct (const struct btf *btf,const struct btf_type *t,u32 off,u32 nelems,u32 field_mask,struct btf_field_info *info, -int info_cnt,u32 level) +int info_cnt,u32 level,u32 *seen_mask) {int ret, err, i;
@@ -3584,7 +3584,7 @@ static int btf_find_nested_struct(const struct btf *btf, const struct btf_type *if (level >=MAX_RESOLVE_DEPTH )return -E2BIG ; - ret =btf_find_struct_field (btf, t, field_mask, info, info_cnt, level); + ret =btf_find_struct_field (btf, t, field_mask, info, info_cnt, level, seen_mask);if (ret <=0 )return ret;
@@ -3641,7 +3641,7 @@ static int btf_find_field_one(const struct btf *btf,if (expected_size && expected_size != sz * nelems)return 0 ; ret =btf_find_nested_struct (btf, var_type, off, nelems, field_mask, - &info[0 ], info_cnt, level); + &info[0 ], info_cnt, level, seen_mask);return ret; }
@@ -3703,11 +3703,11 @@ static int btf_find_field_one(const struct btf *btf,static int btf_find_struct_field (const struct btf *btf,const struct btf_type *t,u32 field_mask,struct btf_field_info *info,int info_cnt, -u32 level) +u32 level,u32 *seen_mask) {int ret, idx =0 ;const struct btf_member *member; -u32 i, off, seen_mask =0 ; +u32 i, off;for_each_member (i, t, member) { const struct btf_type *member_type = btf_type_by_id(btf,
@@ -3721,7 +3721,7 @@ static int btf_find_struct_field(const struct btf *btf, ret =btf_find_field_one (btf, t, member_type, i, off,0 , - field_mask, &seen_mask, + field_mask, seen_mask, &info[idx], info_cnt - idx, level);if (ret <0 )return ret;
@@ -3732,11 +3732,11 @@ static int btf_find_struct_field(const struct btf *btf,static int btf_find_datasec_var (const struct btf *btf,const struct btf_type *t,u32 field_mask,struct btf_field_info *info, -int info_cnt,u32 level) +int info_cnt,u32 level,u32 *seen_mask) {int ret, idx =0 ;const struct btf_var_secinfo *vsi; -u32 i, off, seen_mask =0 ; +u32 i, off;for_each_vsi (i, t, vsi) {const struct btf_type *var =btf_type_by_id (btf, vsi->type);
@@ -3744,7 +3744,7 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t, off = vsi->offset; ret =btf_find_field_one (btf, var, var_type,-1 , off, vsi->size, - field_mask, &seen_mask, + field_mask, seen_mask, &info[idx], info_cnt - idx, level);if (ret <0 )
@@ -3758,10 +3758,12 @@ static int btf_find_field(const struct btf *btf, const struct btf_type *t, u32 field_mask, struct btf_field_info *info, int info_cnt) { + u32 seen_mask = 0; +if (__btf_type_is_struct (t)) - return btf_find_struct_field(btf, t, field_mask, info, info_cnt, 0); +return btf_find_struct_field (btf, t, field_mask, info, info_cnt,0 , &seen_mask);else if (btf_type_is_datasec (t)) - return btf_find_datasec_var(btf, t, field_mask, info, info_cnt, 0); +return btf_find_datasec_var (btf, t, field_mask, info, info_cnt,0 , &seen_mask);return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 625/1376 RDMA/srpt: Pass the mapped task attribute to target_init_cmd()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit ef63cc441703412628a517dda354f3e51fe2dc92 ]
srpt_handle_cmd() maps the initiator-supplied srp_cmd->task_attr into cmd->sam_task_attr, but then hands a hardcoded TCM_SIMPLE_TAG to target_init_cmd().
Pass the already mapped cmd->sam_task_attr instead, so target core sees the attribute the initiator requested.
--- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/ulp/srpt/ib_srpt.c +1 -1
@@ -1603,7 +1603,7 @@ static void srpt_handle_cmd(struct srpt_rdma_ch *ch, rc =target_init_cmd (cmd, ch->sess, &send_ioctx->sense_data[0 ],scsilun_to_int (&srp_cmd->lun), data_len, -TCM_SIMPLE_TAG , dir,TARGET_SCF_ACK_KREF ); + cmd->sam_task_attr, dir,TARGET_SCF_ACK_KREF );if (rc !=0 ) {pr_debug ("target_submit_cmd() returned %d for tag %#llx\n" , rc, srp_cmd->tag);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 626/1376 PCI: j721e: Fix incorrect max_lanes for J7200
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takuma Fujiwara <[email protected]>
[ Upstream commit 7147a7bfce47acd48c3738130bf0bd692bfd80de ]
The PCIe Controller in the J7200 SoC supports a 4-lane configuration. However, j7200_pcie_rc_data and j7200_pcie_ep_data incorrectly set .max_lanes = 2, limiting operation to fewer lanes than the hardware supports.
Set .max_lanes = 4 for both j7200_pcie_rc_data and j7200_pcie_ep_data to match the hardware capability.
See J7200 Technical Reference Manual (SPRUIU1D), section 12.2.3.1.1 for further details: https://www.ti.com/lit/pdf/spruiu1d
--- drivers/pci/controller/cadence/pci-j721e.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pci/controller/cadence/pci-j721e.c +2 -2
@@ -374,7 +374,7 @@ static const struct j721e_pcie_data j7200_pcie_rc_data = { .quirk_detect_quiet_flag = true, .linkdown_irq_regfield = J7200_LINK_DOWN, .byte_access_allowed = true, - .max_lanes = 2, + .max_lanes = 4, };static const struct j721e_pcie_data j7200_pcie_ep_data = {
@@ -382,7 +382,7 @@ static const struct j721e_pcie_data j7200_pcie_ep_data = { .quirk_detect_quiet_flag = true, .linkdown_irq_regfield = J7200_LINK_DOWN, .quirk_disable_flr = true, - .max_lanes = 2, + .max_lanes = 4, };static const struct j721e_pcie_data am64_pcie_rc_data = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 627/1376 RDMA/erdma: Fix CEQ tasklet use-after-free on removal
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit 0ca79979384f031d710c4b3bae065dcb5d95aca3 ]
Each CEQ interrupt handler only schedules eqc->tasklet. The tasklet calls erdma_ceq_completion_handler(), which reads the DMA-coherent EQ ring through get_next_valid_eqe() and updates eq->dbrec through notify_eq().
erdma_ceqs_uninit() frees each CEQ IRQ and then destroys its EQ. free_irq() prevents another hard IRQ and waits for an in-flight handler, but it does not drain a tasklet that the handler already scheduled. The tasklet can therefore access eq->qbuf or eq->dbrec after erdma_eq_destroy() frees them.
Clearing ceq_cb->ready does not synchronize with a tasklet that already passed the check at the start of erdma_ceq_completion_handler().
Kill the tasklet after free_irq(), when no handler can schedule it again, and before erdma_ceq_uninit_one() releases the EQ buffers.
--- drivers/infiniband/hw/erdma/erdma_eq.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/hw/erdma/erdma_eq.c +1 -0
@@ -219,6 +219,7 @@ static void erdma_free_ceq_irq(struct erdma_dev *dev, u16 ceqn)irq_set_affinity_hint (eqc->irq.msix_vector,NULL );free_irq (eqc->irq.msix_vector, eqc); +tasklet_kill (&eqc->tasklet); }static int create_eq_cmd (struct erdma_dev *dev,u32 eqn,struct erdma_eq *eq)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 628/1376 RDMA/restrack: Fix typos in the comments
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalesh AP <[email protected]>
[ Upstream commit d43358cda7c4696e08880aaa58a7df82e471fa7c ]
Fix couple of occurrences of the misspelled word "reource" in the comments with the correct spelling "resource".
Stable-dep-of: 709ba0e5311b ("RDMA/core: Fix use after free in ib_query_qp()")
--- drivers/infiniband/core/restrack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/infiniband/core/restrack.c +2 -2
@@ -173,7 +173,7 @@ void rdma_restrack_new(struct rdma_restrack_entry *res,EXPORT_SYMBOL (rdma_restrack_new);/** -* rdma_restrack_add() - add object to the reource tracking database +* rdma_restrack_add() - add object to the resource tracking database * @res: resource entry */ void rdma_restrack_add (struct rdma_restrack_entry *res)
@@ -275,7 +275,7 @@ int rdma_restrack_put(struct rdma_restrack_entry *res)EXPORT_SYMBOL (rdma_restrack_put);/** -* rdma_restrack_del() - delete object from the reource tracking database +* rdma_restrack_del() - delete object from the resource tracking database * @res: resource entry */ void rdma_restrack_del (struct rdma_restrack_entry *res)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 629/1376 RDMA/nldev: Fix locking when accessing mr->pd
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Gunthorpe <[email protected]>
[ Upstream commit 50d5c02ab8e62325548bd3a6e6b758a9dcd6e7c3 ]
Sashiko points out that, due to rereg_mr, the PD is actually variable and all the touches in nldev are racy.
Use mr->device instead of mr->pd->device.
Getting the PD restrack ID is more tricky. To avoid disturbing all the happy paths, add an rdma_restrack_sync() operation which is sort of like flush_workqueue() or synchronize_irq(): after it returns, all the old nldev touches to the mr are gone and everything sees the new PD. This makes it safe to reach into the PD pointer.
Stable-dep-of: 709ba0e5311b ("RDMA/core: Fix use after free in ib_query_qp()")
--- drivers/infiniband/core/nldev.c | 15 +++++---- drivers/infiniband/core/restrack.c | 49 ++++++++++++++++++++++++++++ drivers/infiniband/core/restrack.h | 1 + drivers/infiniband/core/uverbs_cmd.c | 10 ++++-- include/rdma/ib_verbs.h | 5 +++ 5 files changed, 72 insertions(+), 8 deletions(-)
drivers/infiniband/core/nldev.c +9 -6
@@ -678,7 +678,7 @@ static int fill_res_mr_entry(struct sk_buff *msg, bool has_cap_net_admin, struct rdma_restrack_entry *res, uint32_t port) { struct ib_mr *mr = container_of(res, struct ib_mr, res); -struct ib_device *dev = mr->pd->device; +struct ib_device *dev = mr->device;if (has_cap_net_admin) {if (nla_put_u32 (msg,RDMA_NLDEV_ATTR_RES_RKEY , mr->rkey))
@@ -694,9 +694,12 @@ static int fill_res_mr_entry(struct sk_buff *msg, bool has_cap_net_admin,if (nla_put_u32 (msg,RDMA_NLDEV_ATTR_RES_MRN , res->id))return -EMSGSIZE ; -if (!rdma_is_kernel_res (res) && -nla_put_u32 (msg,RDMA_NLDEV_ATTR_RES_PDN , mr->pd->res.id)) -return -EMSGSIZE ; +if (!rdma_is_kernel_res (res)) { +struct ib_pd *pd =READ_ONCE (mr->pd); + +if (nla_put_u32 (msg,RDMA_NLDEV_ATTR_RES_PDN , pd->res.id)) +return -EMSGSIZE ; + }if (fill_res_name_pid (msg, res))return -EMSGSIZE ;
@@ -710,7 +713,7 @@ static int fill_res_mr_raw_entry(struct sk_buff *msg, bool has_cap_net_admin, struct rdma_restrack_entry *res, uint32_t port) { struct ib_mr *mr = container_of(res, struct ib_mr, res); -struct ib_device *dev = mr->pd->device; +struct ib_device *dev = mr->device;if (!dev->ops.fill_res_mr_entry_raw)return -EINVAL ;
@@ -1000,7 +1003,7 @@ static int fill_stat_mr_entry(struct sk_buff *msg, bool has_cap_net_admin, struct rdma_restrack_entry *res, uint32_t port) { struct ib_mr *mr = container_of(res, struct ib_mr, res); -struct ib_device *dev = mr->pd->device; +struct ib_device *dev = mr->device;if (nla_put_u32 (msg,RDMA_NLDEV_ATTR_RES_MRN , res->id)) goto err;
drivers/infiniband/core/restrack.c +49 -0
61 lines not on this page · raw message
drivers/infiniband/core/restrack.h +1 -0
@@ -27,6 +27,7 @@ int rdma_restrack_init(struct ib_device *dev);void rdma_restrack_clean (struct ib_device *dev);void rdma_restrack_add (struct rdma_restrack_entry *res);void rdma_restrack_del (struct rdma_restrack_entry *res); +void rdma_restrack_sync (struct rdma_restrack_entry *res);void rdma_restrack_new (struct rdma_restrack_entry *res,enum rdma_restrack_type type); void rdma_restrack_set_name(struct rdma_restrack_entry *res,
drivers/infiniband/core/uverbs_cmd.c +8 -2
@@ -46,6 +46,7 @@#include "uverbs.h" #include "core_priv.h" +#include "restrack.h" /* * Copy a response to userspace. If the provided 'resp' is larger than the
@@ -813,6 +814,10 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs) ret =PTR_ERR (new_pd); goto put_uobjs; } +if (new_pd == orig_pd) { +uobj_put_obj_read (new_pd); + cmd.flags &= ~IB_MR_REREG_PD ; + } }else { new_pd = mr->pd; }
@@ -858,9 +863,10 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs) mr = new_mr; }else {if (cmd.flags &IB_MR_REREG_PD ) { -atomic_dec (&orig_pd->usecnt); - mr->pd = new_pd;atomic_inc (&new_pd->usecnt); +WRITE_ONCE (mr->pd, new_pd); +rdma_restrack_sync (&mr->res); +atomic_dec (&orig_pd->usecnt); }if (cmd.flags &IB_MR_REREG_TRANS ) { mr->iova = cmd.hca_va;
include/rdma/ib_verbs.h +5 -0
@@ -1831,6 +1831,11 @@ struct ib_dm {struct ib_mr {struct ib_device *device; +/* +* Due to IB_MR_REREG_PD pd is not a fixed pointer and can change. For a +* user MR, this value should only be read from a system call that holds +* the uobject lock, or the driver should disable in-place REREG_PD. +*/ struct ib_pd *pd;u32 lkey;u32 rkey;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 630/1376 RDMA/core: Add rdma_restrack_begin/abort/commit_del() operations
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 8d186210677c0322db886973bcec9aa4d21b51cd ]
Add rdma_restrack_abort_del(), rdma_restrack_begin_del() and rdma_restrack_commit_del() functions to allow deleting a resource from the xarray to effectively prevent future access to it and wait for all current users to finish while preserving its index in the xarray to allow to re-insert it if needed with guaranteed success.
This is a preparatory change for subsequent patches in the series which will use these functions to fix the cleanup flow.
Stable-dep-of: 709ba0e5311b ("RDMA/core: Fix use after free in ib_query_qp()")
--- drivers/infiniband/core/restrack.c | 165 +++++++++++++++++++++++------ drivers/infiniband/core/restrack.h | 3 + 2 files changed, 135 insertions(+), 33 deletions(-)
drivers/infiniband/core/restrack.c +132 -33
@@ -127,6 +127,46 @@ static void rdma_restrack_attach_task(struct rdma_restrack_entry *res, res->user = true; } +static struct rdma_restrack_root *res_to_rt (struct rdma_restrack_entry *res) +{ +struct ib_device *dev =res_to_dev (res); + +if (WARN_ON (!dev)) +return NULL ; + +return &dev->res[res->type]; +} + +static void restrack_drain_res (struct rdma_restrack_root *rt, +struct rdma_restrack_entry *res) +{ +if (rt) { +struct rdma_restrack_entry *old; + + old =xa_cmpxchg (&rt->xa, res->id, res,XA_ZERO_ENTRY , +GFP_KERNEL ); +WARN_ON (old != res); + } + +rdma_restrack_put (res); +wait_for_completion (&res->comp); +} + +static void restrack_restore_res (struct rdma_restrack_root *rt, +struct rdma_restrack_entry *res) +{ +reinit_completion (&res->comp); +kref_init (&res->kref); + +if (rt) { +struct rdma_restrack_entry *old; + + old =xa_cmpxchg (&rt->xa, res->id,XA_ZERO_ENTRY , res, +GFP_KERNEL ); +WARN_ON (old); + } +} +/** * rdma_restrack_set_name() - set the task for this resource * @res: resource entry
@@ -175,22 +215,23 @@ void rdma_restrack_new(struct rdma_restrack_entry *res,EXPORT_SYMBOL (rdma_restrack_new);/** -* rdma_restrack_add() - add object to the resource tracking database +* rdma_restrack_add() - add object to the resource tracking database. +* If this resource reuses an ID of a resource that was already destroyed +* after calling rdma_restrack_begin() but didn't yet call +* rdma_restrack_commit_del() it can result in an untracked QP. * @res: resource entry */ void rdma_restrack_add (struct rdma_restrack_entry *res) { -struct ib_device *dev =res_to_dev (res);struct rdma_restrack_root *rt;int ret =0 ; -if (!dev) -return ; -if (res->no_track) goto out; - rt = &dev->res[res->type]; + rt =res_to_rt (res); +if (!rt) +return ;if (res->type ==RDMA_RESTRACK_QP ) {/* Special case to ensure that LQPN points to right QP */
@@ -227,6 +268,28 @@ void rdma_restrack_add(struct rdma_restrack_entry *res) }EXPORT_SYMBOL (rdma_restrack_add); +/** +* rdma_restrack_abort_del() - re-add object to the resource tracking database +* it can only be used after rdma_restrack_begin_del(). +* @res: resource entry +*/ +void rdma_restrack_abort_del (struct rdma_restrack_entry *res) +{ +struct rdma_restrack_root *rt =NULL ; + +if (!res->valid) +return ; + +if (!res->no_track) { + rt =res_to_rt (res); +if (!rt) +return ; + } + +restrack_restore_res (rt, res); +} +EXPORT_SYMBOL (rdma_restrack_abort_del); +int __must_check rdma_restrack_get (struct rdma_restrack_entry *res) {return kref_get_unless_zero (&res->kref);
@@ -263,7 +326,7 @@ static void restrack_release(struct kref *kref)struct rdma_restrack_entry *res; res = container_of(kref, struct rdma_restrack_entry, kref); -if (res->task) { +if (res->task && !res->valid) {put_task_struct (res->task); res->task =NULL ; }
@@ -289,37 +352,20 @@ EXPORT_SYMBOL(rdma_restrack_put);*/ void rdma_restrack_sync (struct rdma_restrack_entry *res) { -struct rdma_restrack_entry *old;struct rdma_restrack_root *rt; -struct task_struct *task; -struct ib_device *dev;if (!res->valid || res->no_track)return ; - dev =res_to_dev (res); -if (WARN_ON (!dev)) + rt =res_to_rt (res); +if (!rt)return ; - rt = &dev->res[res->type];if (WARN_ON (xa_get_mark (&rt->xa, res->id,RESTRACK_DD )))return ; - old =xa_cmpxchg (&rt->xa, res->id, res,XA_ZERO_ENTRY ,GFP_KERNEL ); -if (WARN_ON (old != res)) -return ; - - task = res->task; -if (task) -get_task_struct (task); -rdma_restrack_put (res); -wait_for_completion (&res->comp); -reinit_completion (&res->comp); -if (task) - res->task = task; -kref_init (&res->kref); - -xa_cmpxchg (&rt->xa, res->id,XA_ZERO_ENTRY , res,GFP_KERNEL ); +restrack_drain_res (rt, res); +restrack_restore_res (rt, res); }EXPORT_SYMBOL (rdma_restrack_sync);
@@ -331,7 +377,6 @@ void rdma_restrack_del(struct rdma_restrack_entry *res) {struct rdma_restrack_entry *old;struct rdma_restrack_root *rt; -struct ib_device *dev;if (!res->valid) {if (res->task) {
@@ -344,12 +389,10 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)if (res->no_track) goto out; - dev =res_to_dev (res); -if (WARN_ON (!dev)) + rt =res_to_rt (res); +if (!rt)return ; - rt = &dev->res[res->type]; - old =xa_erase (&rt->xa, res->id);WARN_ON (old != res);
@@ -357,5 +400,61 @@ void rdma_restrack_del(struct rdma_restrack_entry *res) res->valid = false;rdma_restrack_put (res);wait_for_completion (&res->comp); +if (res->task) { +put_task_struct (res->task); + res->task =NULL ; + } }EXPORT_SYMBOL (rdma_restrack_del); + +/** +* rdma_restrack_begin_del() - invalidate the object from the resource tracking +* database but preserve its index in the array. +* Since this preserves the index in the array until rdma_restrack_commit_del() +* is called, if rdma_restrack_add() is called in between with an old QP ID it +* can result in an untracked QP. +* @res: resource entry +*/ +void rdma_restrack_begin_del (struct rdma_restrack_entry *res) +{ +struct rdma_restrack_root *rt =NULL ; + +if (!res->valid) +return ; + +if (!res->no_track) { + rt =res_to_rt (res); +if (!rt) +return ; + } + +restrack_drain_res (rt, res); +} +EXPORT_SYMBOL (rdma_restrack_begin_del); + +/** +* rdma_restrack_commit_del() - delete object from the resource tracking +* database and free the task. +* @res: resource entry +*/ +void rdma_restrack_commit_del (struct rdma_restrack_entry *res) +{ +struct rdma_restrack_root *rt; + +if (!res->valid || res->no_track) + goto out; + + rt =res_to_rt (res); +if (!rt) +return ; + +xa_erase (&rt->xa, res->id); + +out: + res->valid = false; +if (res->task) { +put_task_struct (res->task); + res->task =NULL ; + } +} +EXPORT_SYMBOL (rdma_restrack_commit_del);
drivers/infiniband/core/restrack.h +3 -0
@@ -26,8 +26,11 @@ struct rdma_restrack_root {int rdma_restrack_init (struct ib_device *dev);void rdma_restrack_clean (struct ib_device *dev);void rdma_restrack_add (struct rdma_restrack_entry *res); +void rdma_restrack_abort_del (struct rdma_restrack_entry *res);void rdma_restrack_del (struct rdma_restrack_entry *res);void rdma_restrack_sync (struct rdma_restrack_entry *res); +void rdma_restrack_begin_del (struct rdma_restrack_entry *res); +void rdma_restrack_commit_del (struct rdma_restrack_entry *res);void rdma_restrack_new (struct rdma_restrack_entry *res,enum rdma_restrack_type type); void rdma_restrack_set_name(struct rdma_restrack_entry *res,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 631/1376 RDMA/core: Fix use after free in ib_query_qp()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 709ba0e5311bd034eb4d9c1c00cc4e1109d6dc3e ]
When querying a QP via the netlink flow the only synchronization mechanism for the said QP is rdma_restrack_get(), meanwhile during the QP destroy path rdma_restrack_del() is called at the end of the ib_destroy_qp_user() function which is too late, since by then the vendor specific resources for said QP would already be destroyed, and till the rdma_restrack_del() is called this QP can still be accessed, which could cause the use after free below.
Fix this by moving the rdma_restrack_begin_del() to the start of the ib_destroy_qp_user(), which in turn waits for all usages of the QP to be done then removes it from the database to prevent access to it while it is being destroyed.
RIP: 0010:ib_query_qp+0x15/0x50 [ib_core] Code: 48 83 05 5d 8e b9 ff 01 eb b5 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 c7 46 40 00 00 00 00 48 c7 46 78 00 00 00 00 <48> 8b 07 48 8b 80 88 01 00 00 48 85 c0 74 1a 48 83 05 54 91 b9 ff RSP: 0018:ff11000108a8f2f0 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ff11000108a8f370 RCX: ff11000108a8f370 RDX: 0000000000000000 RSI: ff11000108a8f3d8 RDI: 0000000000000000 RBP: ff1100010de5a000 R08: 0000000000000e80 R09: 0000000000000004 R10: ff110001057a604c R11: 0000000000000000 R12: ff11000108a8f370 R13: ff110001090e8000 R14: 0000000000000000 R15: ff110001057a602c FS: 00007f2ffd8db6c0(0000) GS:ff110008dc90b000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000010b9a7004 CR4: 0000000000373eb0 Call Trace: <TASK> mlx5_ib_gsi_query_qp+0x21/0x50 [mlx5_ib] mlx5_ib_query_qp+0x689/0x9d0 [mlx5_ib] ib_query_qp+0x35/0x50 [ib_core] fill_res_qp_entry_query.isra.0+0x47/0x280 [ib_core] ? __wake_up+0x40/0x50 ? netlink_broadcast_filtered+0x15a/0x550 ? kobject_uevent_env+0x562/0x710 ? ep_poll_callback+0x242/0x270 ? __nla_put+0xc/0x20 ? nla_put+0x28/0x40 ? nla_put_string+0x2e/0x40 [ib_core] fill_res_qp_entry+0x138/0x190 [ib_core] res_get_common_dumpit+0x4a5/0x800 [ib_core] ? fill_res_qp_entry_query.isra.0+0x280/0x280 [ib_core] nldev_res_get_qp_dumpit+0x1e/0x30 [ib_core] netlink_dump+0x16f/0x450 __netlink_dump_start+0x1ce/0x2e0 rdma_nl_rcv_msg+0x1d3/0x330 [ib_core] ? nldev_res_get_qp_raw_dumpit+0x30/0x30 [ib_core] rdma_nl_rcv_skb.constprop.0.isra.0+0x108/0x180 [ib_core] rdma_nl_rcv+0x12/0x20 [ib_core] netlink_unicast+0x255/0x380 ? __alloc_skb+0xfa/0x1e0 netlink_sendmsg+0x1f3/0x420 __sock_sendmsg+0x38/0x60 ____sys_sendmsg+0x1e8/0x230 ? copy_msghdr_from_user+0xea/0x170 ___sys_sendmsg+0x7c/0xb0 ? __futex_wait+0x95/0xf0 ? __futex_wake_mark+0x40/0x40 ? futex_wait+0x67/0x100 ? futex_wake+0xac/0x1b0 __sys_sendmsg+0x5f/0xb0 do_syscall_64+0x55/0xb90 entry_SYSCALL_64_after_hwframe+0x4b/0x53
--- drivers/infiniband/core/verbs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/infiniband/core/verbs.c +4 -1
@@ -2098,6 +2098,8 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)if (qp->real_qp != qp)return __ib_destroy_shared_qp (qp); +rdma_restrack_begin_del (&qp->res); + sec = qp->qp_sec;if (sec)ib_destroy_qp_security_begin (sec);
@@ -2110,6 +2112,7 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)if (ret) {if (sec)ib_destroy_qp_security_abort (sec); +rdma_restrack_abort_del (&qp->res);return ret; }
@@ -2122,7 +2125,7 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)if (sec)ib_destroy_qp_security_end (sec); -rdma_restrack_del (&qp->res); +rdma_restrack_commit_del (&qp->res);kfree (qp);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 632/1376 RDMA/core: Fix potential use after free in ib_destroy_cq_user()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 3481bec4dfc4aee24ffea5a547ee95b70b67d9d5 ]
When accessing a CQ via the netlink path the only synchronization mechanism for the said CQ is rdma_restrack_get(). Currently, rdma_restrack_del() is invoked at the end of ib_destroy_cq_user(), which is too late, since by that point vendor-specific resources associated with the CQ might already be freed. This can leave a short window where the CQ remains accessible through restrack, leading to a potential use-after-free.
Fix this by moving the rdma_restrack_begin_del() call to the start of ib_destroy_cq_user(), ensuring that the CQ is removed from restrack before its internal resources are released. This guarantees that no new users hold references to a CQ that is in the process of destruction.
In addition, this change preserves the intended inverted order between create and destroy routines: resources are added to restrack at the end of successful creation, and hence shall be removed from the restrack first thing during the destruction flow, which keeps the lifecycle management consistent and predictable.
--- drivers/infiniband/core/verbs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/infiniband/core/verbs.c +6 -2
@@ -2190,11 +2190,15 @@ int ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata *udata)if (atomic_read (&cq->usecnt))return -EBUSY ; +rdma_restrack_begin_del (&cq->res); + ret = cq->device->ops.destroy_cq (cq, udata); -if (ret) +if (ret) { +rdma_restrack_abort_del (&cq->res);return ret; + } -rdma_restrack_del (&cq->res); +rdma_restrack_commit_del (&cq->res);kfree (cq);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 633/1376 RDMA/core: Fix potential use after free in ib_destroy_srq_user()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 88244ecc71cc0b3ed200f5ef7ddea6686adfd730 ]
When accessing a SRQ via the netlink path the only synchronization mechanism for the said SRQ is rdma_restrack_get(). Currently, rdma_restrack_del() is invoked at the end of ib_destroy_srq_user(), which is too late, since by that point vendor-specific resources associated with the SRQ might already be freed. This can leave a short window where the SRQ remains accessible through restrack, leading to a potential use-after-free.
Fix this by moving the rdma_restrack_begin_del() call to the start of ib_destroy_srq_user(), ensuring that the SRQ is removed from restrack before its internal resources are released. This guarantees that no new users hold references to a SRQ that is in the process of destruction.
In addition, this change preserves the intended inverted order between create and destroy routines: resources are added to restrack at the end of successful creation, and hence shall be removed from the restrack first thing during the destruction flow, which keeps the lifecycle management consistent and predictable.
--- drivers/infiniband/core/verbs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/infiniband/core/verbs.c +6 -2
@@ -1083,16 +1083,20 @@ int ib_destroy_srq_user(struct ib_srq *srq, struct ib_udata *udata)if (atomic_read (&srq->usecnt))return -EBUSY ; +rdma_restrack_begin_del (&srq->res); + ret = srq->device->ops.destroy_srq (srq, udata); -if (ret) +if (ret) { +rdma_restrack_abort_del (&srq->res);return ret; + }atomic_dec (&srq->pd->usecnt);if (srq->srq_type ==IB_SRQT_XRC && srq->ext.xrc.xrcd)atomic_dec (&srq->ext.xrc.xrcd->usecnt);if (ib_srq_has_cq (srq->srq_type))atomic_dec (&srq->ext.cq->usecnt); -rdma_restrack_del (&srq->res); +rdma_restrack_commit_del (&srq->res);kfree (srq);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 634/1376 RDMA/core: Fix potential use after free in counter_release()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 235ef2d0e750885c29340b0fc40620a7a4f52e12 ]
When accessing a counter via the netlink path the only synchronization mechanism for the said counter is rdma_restrack_get(). Currently, rdma_restrack_del() is invoked at the end of counter_release(), which is too late, since by that point vendor-specific resources associated with the counter might already be freed. This can leave a short window where the counter remains accessible through restrack, leading to a potential use-after-free.
Fix this by moving the rdma_restrack_del() call to be before the freeing of the vendor-specific resources, ensuring that the counter is removed from restrack before its internal resources are released. This guarantees that no new users hold references to a counter that is in the process of destruction.
--- drivers/infiniband/core/counters.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/infiniband/core/counters.c +3 -2
@@ -217,7 +217,6 @@ static void rdma_counter_free(struct rdma_counter *counter)mutex_unlock (&port_counter->lock); -rdma_restrack_del (&counter->res);rdma_free_hw_stats_struct (counter->stats);kfree (counter); }
@@ -312,6 +311,7 @@ static void counter_release(struct kref *kref) counter = container_of(kref, struct rdma_counter, kref);counter_history_stat_update (counter); +rdma_restrack_del (&counter->res); counter->device->ops.counter_dealloc (counter);rdma_counter_free (counter); }
@@ -472,7 +472,8 @@ static struct rdma_counter *rdma_get_counter_by_id(struct ib_device *dev,return NULL ; counter = container_of(res, struct rdma_counter, res); -kref_get (&counter->kref); +if (!kref_get_unless_zero (&counter->kref)) + counter =NULL ;rdma_restrack_put (res);return counter;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 635/1376 RDMA/core: Add driver APIs pre_destroy_cq() and post_destroy_cq()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Zhang <[email protected]>
[ Upstream commit 5a2a5b65d5d67279be9e1f0e4b9baf39ee594cb1 ]
Currently in ib_free_cq, it disables IRQ or cancel the CQ work before driver destroy_cq. This isn't good as a new IRQ or a CQ work can be submitted immediately after disabling IRQ or canceling CQ work, which may run concurrently with destroy_cq and cause crashes.
The right flow should be:
1. Driver disables CQ to make sure no new CQ event will be submitted;
2. Disables IRQ or Cancels CQ work in core layer, to make sure no CQ
polling work is running;
3. Free all resources to destroy the CQ.
This patch adds 2 driver APIs:
- pre_destroy_cq(): Disable a CQ to prevent it from generating any new work completions, but not free any kernel resources;
- post_destroy_cq(): Free all kernel resources.
In ib_free_cq, the IRQ is disabled or CQ work is canceled after pre_destroy_cq, and before post_destroy_cq.
Stable-dep-of: 29dc2f8e1c97 ("RDMA/core: Fix potential use after free in ib_free_cq()")
--- drivers/infiniband/core/cq.c | 12 ++++++++++-- drivers/infiniband/core/device.c | 2 ++ include/rdma/ib_verbs.h | 9 +++++++++ 3 files changed, 21 insertions(+), 2 deletions(-)
drivers/infiniband/core/cq.c +10 -2
@@ -317,13 +317,18 @@ EXPORT_SYMBOL(__ib_alloc_cq_any);*/ void ib_free_cq (struct ib_cq *cq) { -int ret; +int ret =0 ;if (WARN_ON_ONCE (atomic_read (&cq->usecnt)))return ;if (WARN_ON_ONCE (cq->cqe_used))return ; +if (cq->device->ops.pre_destroy_cq) { + ret = cq->device->ops.pre_destroy_cq (cq); +WARN_ONCE (ret,"Disable of kernel CQ shouldn't fail" ); + } +switch (cq->poll_ctx) {case IB_POLL_DIRECT :break ;
@@ -340,7 +345,10 @@ void ib_free_cq(struct ib_cq *cq)rdma_dim_destroy (cq);trace_cq_free (cq); - ret = cq->device->ops.destroy_cq (cq,NULL ); +if (cq->device->ops.post_destroy_cq) + cq->device->ops.post_destroy_cq (cq); +else + ret = cq->device->ops.destroy_cq (cq,NULL );WARN_ONCE (ret,"Destroy of kernel CQ shouldn't fail" );rdma_restrack_del (&cq->res);kfree (cq->wc);
drivers/infiniband/core/device.c +2 -0
@@ -2783,8 +2783,10 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)SET_DEVICE_OP (dev_ops, modify_srq);SET_DEVICE_OP (dev_ops, modify_wq);SET_DEVICE_OP (dev_ops, peek_cq); +SET_DEVICE_OP (dev_ops, pre_destroy_cq);SET_DEVICE_OP (dev_ops, poll_cq);SET_DEVICE_OP (dev_ops, port_groups); +SET_DEVICE_OP (dev_ops, post_destroy_cq);SET_DEVICE_OP (dev_ops, post_recv);SET_DEVICE_OP (dev_ops, post_send);SET_DEVICE_OP (dev_ops, post_srq_recv);
include/rdma/ib_verbs.h +9 -0
@@ -2474,6 +2474,15 @@ struct ib_device_ops {int (*modify_cq)(struct ib_cq *cq,u16 cq_count,u16 cq_period);int (*destroy_cq)(struct ib_cq *cq,struct ib_udata *udata);int (*resize_cq)(struct ib_cq *cq,int cqe,struct ib_udata *udata); +/** +* pre_destroy_cq - Prevent a cq from generating any new work +* completions, but not free any kernel resources +*/ +int (*pre_destroy_cq)(struct ib_cq *cq); +/** +* post_destroy_cq - Free all kernel resources +*/ +void (*post_destroy_cq)(struct ib_cq *cq);struct ib_mr *(*get_dma_mr)(struct ib_pd *pd,int mr_access_flags); struct ib_mr *(*reg_user_mr)(struct ib_pd *pd, u64 start, u64 length, u64 virt_addr, int mr_access_flags,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 636/1376 RDMA/core: Fix potential use after free in ib_free_cq()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 29dc2f8e1c97372c2871a70088707933515fbd5b ]
When accessing a CQ via the netlink path the only synchronization mechanism for the said CQ is rdma_restrack_get(). Currently, rdma_restrack_del() is invoked at the end of ib_free_cq(), which is too late, since by that point vendor-specific resources associated with the CQ might already be freed. This can leave a short window where the CQ remains accessible through restrack, leading to a potential use-after-free.
Fix this by moving the rdma_restrack_del() call to be before the freeing of the vendor-specific resources ensuring that the CQ is removed from restrack before its internal resources are released.
This guarantees that no new users hold references to a CQ that is in the process of destruction.
--- drivers/infiniband/core/cq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/core/cq.c +1 -1
@@ -324,6 +324,7 @@ void ib_free_cq(struct ib_cq *cq)if (WARN_ON_ONCE (cq->cqe_used))return ; +rdma_restrack_del (&cq->res);if (cq->device->ops.pre_destroy_cq) { ret = cq->device->ops.pre_destroy_cq (cq);WARN_ONCE (ret,"Disable of kernel CQ shouldn't fail" );
@@ -350,7 +351,6 @@ void ib_free_cq(struct ib_cq *cq)else ret = cq->device->ops.destroy_cq (cq,NULL );WARN_ONCE (ret,"Destroy of kernel CQ shouldn't fail" ); -rdma_restrack_del (&cq->res);kfree (cq->wc);kfree (cq); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 637/1376 RDMA/core: Fix potential use after free in ib_dealloc_pd_user()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 8b90e701342275f414e36e7421c502237df241ad ]
When accessing a PD via the netlink path the only synchronization mechanism for the said PD is rdma_restrack_get(). Currently, rdma_restrack_del() is invoked at the end of ib_dealloc_pd_user(), which is too late, since by that point vendor-specific resources associated with the PD might already be freed. This can leave a short window where the PD remains accessible through restrack, leading to a potential use-after-free.
Fix this by moving the rdma_restrack_begin_del() call to the start of ib_dealloc_pd_user(), ensuring that the PD is removed from restrack before its internal resources are released. This guarantees that no new users hold references to a PD that is in the process of destruction.
In addition, this change preserves the intended inverted order between create and destroy routines: resources are added to restrack at the end of successful creation, and hence shall be removed from the restrack first thing during the destruction flow, which keeps the lifecycle management consistent and predictable.
--- drivers/infiniband/core/verbs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/infiniband/core/verbs.c +5 -2
@@ -335,6 +335,7 @@ int ib_dealloc_pd_user(struct ib_pd *pd, struct ib_udata *udata) {int ret; +rdma_restrack_begin_del (&pd->res);if (pd->__internal_mr) { ret = pd->device->ops.dereg_mr (pd->__internal_mr,NULL );WARN_ON (ret);
@@ -342,10 +343,12 @@ int ib_dealloc_pd_user(struct ib_pd *pd, struct ib_udata *udata) } ret = pd->device->ops.dealloc_pd (pd, udata); -if (ret) +if (ret) { +rdma_restrack_abort_del (&pd->res);return ret; + } -rdma_restrack_del (&pd->res); +rdma_restrack_commit_del (&pd->res);kfree (pd);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 638/1376 firmware: arm_scmi: Fix requested device removal race
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 2c4097e6c4aed276c5e9ec2ab331ab397ea780bf ]
scmi_protocol_device_unrequest() drops scmi_requested_devices_mtx while notifying listeners but continues to retain the per-protocol list head. When two SCMI drivers for the same protocol unregister concurrently, one thread can remove the final request and free the list head while the other is running its notifier. The latter then dereferences the freed list head after reacquiring the mutex and can free it a second time.
Complete the list and IDR updates, including freeing an empty list head, before dropping the mutex. Keep the blocking notifier outside the critical section and retain only the detached request across the callback.
--- drivers/firmware/arm_scmi/bus.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/firmware/arm_scmi/bus.c +13 -13
@@ -157,6 +157,7 @@ static int scmi_protocol_table_register(const struct scmi_device_id *id_table)*/ static void scmi_protocol_device_unrequest (const struct scmi_device_id *id_table) { +struct scmi_requested_dev *rdev, *victim =NULL ;struct list_head *phead; pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
@@ -165,29 +166,28 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_tablemutex_lock (&scmi_requested_devices_mtx); phead =idr_find (&scmi_requested_devices, id_table->protocol_id);if (phead) { -struct scmi_requested_dev *victim, *tmp; - -list_for_each_entry_safe (victim, tmp, phead, node) { -if (!strcmp (victim->id_table->name, id_table->name)) { -list_del (&victim->node); - -mutex_unlock (&scmi_requested_devices_mtx); -blocking_notifier_call_chain (&scmi_requested_devices_nh, -SCMI_BUS_NOTIFY_DEVICE_UNREQUEST , - (void *)victim->id_table); -kfree (victim); -mutex_lock (&scmi_requested_devices_mtx); +list_for_each_entry (rdev, phead, node) { +if (!strcmp (rdev->id_table->name, id_table->name)) { + victim = rdev; +list_del (&rdev->node);break ; } } -if (list_empty (phead)) { +if (victim &&list_empty (phead)) {idr_remove (&scmi_requested_devices, id_table->protocol_id);kfree (phead); } }mutex_unlock (&scmi_requested_devices_mtx); + +if (victim) { +blocking_notifier_call_chain (&scmi_requested_devices_nh, +SCMI_BUS_NOTIFY_DEVICE_UNREQUEST , + (void *)victim->id_table); +kfree (victim); + } } static void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 639/1376 iommu/qcom: Remove sysfs device on probe failure path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit c579f18e79599c16168925cb149e1db3f29eea5f ]
In qcom_iommu_device_probe(), if iommu_device_register() fails, the sysfs device created by iommu_device_sysfs_add() is not released. Add a goto label to do the cleanup.
--- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu/qcom_iommu.c +3 -1
@@ -860,7 +860,7 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) ret =iommu_device_register (&qcom_iommu->iommu, &qcom_iommu_ops, dev);if (ret) {dev_err (dev,"Failed to register iommu\n" ); - goto err_pm_disable; + goto err_sysfs_remove; }if (qcom_iommu->local_base) {
@@ -871,6 +871,8 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)return 0 ; +err_sysfs_remove: +iommu_device_sysfs_remove (&qcom_iommu->iommu); err_pm_disable:pm_runtime_disable (dev);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 640/1376 iommu/qcom: Fix inverted fault report check in qcom_iommu_fault()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 1f33b8208a1978b0c0d6ad60a47fe4bb7a235e58 ]
report_iommu_fault() returns 0 when a fault handler successfully handles the fault, and -ENOSYS when no handler is installed. The condition '!report_iommu_fault()' evaluates to true (printing "Unhandled context fault") precisely when the fault *was* handled, and stays silent when no handler is present — the opposite of what is intended.
Remove the '!' so the driver logs unhandled faults correctly.
--- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu/qcom_iommu.c +1 -1
@@ -200,7 +200,7 @@ static irqreturn_t qcom_iommu_fault(int irq, void *dev) fsynr =iommu_readl (ctx,ARM_SMMU_CB_FSYNR0 ); iova =iommu_readq (ctx,ARM_SMMU_CB_FAR ); -if (!report_iommu_fault (ctx->domain, ctx->dev, iova,0 )) { +if (report_iommu_fault (ctx->domain, ctx->dev, iova,0 )) { dev_err_ratelimited(ctx->dev, "Unhandled context fault: fsr=0x%x, " "iova=0x%016llx, fsynr=0x%x, cb=%d\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 641/1376 thermal: intel: int3400: clean up ODVP on probe failures
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit d83dc9ce57a746a6dca28439bcc0575d26fa6986 ]
evaluate_odvp() creates per-ODVP sysfs files before the thermal zone and later probe resources are registered. The current unwind path only calls cleanup_odvp() from the late sysfs failure path, so failures after evaluate_odvp() but before that label, including thermal_tripless_zone_device_register() failures, leave the ODVP files and storage behind.
Move the ODVP cleanup to the common ART/TRT unwind path so every failure after evaluate_odvp() releases the ODVP state. Also clear the cached ODVP pointers in cleanup_odvp(), because evaluate_odvp() can already call it for partial setup failures while probe continues.
--- drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/thermal/intel/int340x_thermal/int3400_thermal.c +3 -1
@@ -363,8 +363,10 @@ static void cleanup_odvp(struct int3400_thermal_priv *priv)kfree (priv->odvp_attrs[i].attr.attr.name); }kfree (priv->odvp_attrs); + priv->odvp_attrs =NULL ; }kfree (priv->odvp); + priv->odvp =NULL ; priv->odvp_count =0 ; }
@@ -646,7 +648,6 @@ static int int3400_thermal_probe(struct platform_device *pdev)acpi_remove_notify_handler (priv->adev->handle,ACPI_DEVICE_NOTIFY , int3400_notify); free_sysfs: -cleanup_odvp (priv);if (!ZERO_OR_NULL_PTR (priv->data_vault)) {sysfs_remove_group (&pdev->dev.kobj, &data_attribute_group);kfree (priv->data_vault);
@@ -660,6 +661,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)acpi_thermal_rel_misc_device_remove (priv->adev->handle);thermal_zone_device_unregister (priv->thermal); free_art_trt: +cleanup_odvp (priv);kfree (priv->trts);kfree (priv->arts); free_priv:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 642/1376 ext4: clear stale xarray tags on folios skipped during writeback
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerald Yang <[email protected]>
[ Upstream commit ec524aae479b4b2078c47492b90ec21200bce434 ]
In data=journal mode, the writeback thread can hit the WARN_ON_ONCE(sb_rdonly(sb)) in ext4_journal_check_start() while the superblock is being remounted read-only during reboot:
Workqueue: writeback wb_workfn (flush-253:0) RIP: 0010:ext4_journal_check_start+0x8b/0xd0 Call Trace: __ext4_journal_start_sb+0x3c/0x1e0 mpage_prepare_extent_to_map+0x4af/0x580 ext4_do_writepages+0x3c0/0x1080 ext4_writepages+0xc8/0x1a0 do_writepages+0xc4/0x180 __writeback_single_inode+0x45/0x2f0 writeback_sb_inodes+0x26b/0x5d0 __writeback_inodes_wb+0x54/0x100 wb_writeback+0x1ac/0x320 wb_workfn+0x394/0x470
And followed by the warning:
EXT4-fs warning (device vda1): ext4_evict_inode:195: inode #6263:
comm (sd-umount): data will be lost
This issue is not reproduced every time, but frequently.
The reproduction step is to create a VM with 8 CPUs, 16G memory and setup data=journal:
sudo tune2fs -o journal_data /dev/vda1
Run fio:
rm -f fiotest
fio --name=fiotest --rw=randwrite --bs=4k --runtime=6 --ioengine=libaio --iodepth=256 --numjobs=8 --filename=fiotest --filesize=30G --group_reporting
Reboot the VM, and check the console output from:
virsh console testvm
But there is no dirty inode, folio_clear_dirty_for_io clears PG_dirty but leaves tags PAGECACHE_TAG_DIRTY and PAGECACHE_TAG_TOWRITE set which are only cleared by __folio_start_writeback.
In data=journal mode, jbd2 checkpoints the journalled data to its final location and clears its own dirty flag without touching folio PG_dirty or xarray dirty flags.
The commit f4a2b42e7891 ("ext4: fix stale xarray tags after writeback") fixes when PG_dirty is still set but there is no dirty page. Another case is PG_dirty is cleared, but PAGECACHE_TAG_DIRTY and PAGECACHE_TAG_TOWRITE is still set. In this case, writeback thread checks clean folio and skips it in mpage_prepare_extent_to_map:
if (!folio_test_dirty(folio) ||
...
folio_unlcok(folio);
continueAnd never reaches ext4_bio_write_folio where the commit f4a2b42e7891 clears the stale xarray tags. Print debug logs after the filesystem is remounted read-only:
writepages RDONLY nrpages=2048 dirtytag=1 wbtag=0 towrite=1 sync=0 And all folios are actually clean:
folio idx=3 dirty=0 wb=0 checked=0 dirtybuf=0 jbddirty=0 mapped=1
...
We need to clear the xarray stale tags for such clean folios by cycling them through writeback in the skip path, the same way f4a2b42e7891 does in ext4_bio_write_folio.
--- fs/ext4/inode.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
fs/ext4/inode.c +15 -3
@@ -2489,13 +2489,25 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)* page is already under writeback and we are not doing * a data integrity writeback, skip the page */ -if (!folio_test_dirty (folio) || - (folio_test_writeback (folio) && - (mpd->wbc->sync_mode ==WB_SYNC_NONE )) || +if ((folio_test_writeback (folio) && + mpd->wbc->sync_mode ==WB_SYNC_NONE ) ||unlikely (folio->mapping != mapping)) {folio_unlock (folio);continue ; } +/* +* If the folio is clean, skip writing it back. +* Cycle the folio through the writeback state +* though, to clear stale xarray tags. +*/ +if (!folio_test_dirty (folio)) { +if (!folio_test_writeback (folio)) { +__folio_start_writeback (folio, false); +folio_end_writeback (folio); + } +folio_unlock (folio); +continue ; + }folio_wait_writeback (folio);BUG_ON (folio_test_writeback (folio));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 643/1376 ext4: drain in-flight DIO before buffered write fallback
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
[ Upstream commit 15cdefd0c0522f9d5e12d947fa04f4c11649b699 ]
generic/746 started failing intermittently on ext3 (no-extent inodes). The test triggers 'Page cache invalidation failure on direct I/O' warnings and subsequent fsync returns -EIO. Adding a 50ms delay between ext4_buffered_write_iter() and filemap_write_and_wait_range() in ext4_dio_write_iter() makes the race almost always reproducible.
On no-extent inodes, DIO writes to holes cannot use unwritten extents, so ext4_iomap_alloc() leaves m_flags=0 and ext4_map_blocks() returns 0. The iomap layer then returns -ENOTBLK, causing fallback to buffered I/O.
The fallback path in ext4_dio_write_iter() calls ext4_buffered_write_iter() which dirties pages, then does flush and invalidate. However, there's an unprotected window between ext4_buffered_write_iter() returning (with inode lock released) and the subsequent flush+invalidate.
Concurrent async DIO completions from other threads can run kiocb_invalidate_post_direct_write() during this window. If pages have been re-dirtied, post-invalidation finds dirty pages and triggers the warning, setting -EIO in the error sequence.
Consider a file with two 4k extents: [hole][written]. Thread A does DIO to the written extent, while thread B does DIO spanning both:
kworker A (4k DIO, allocated block) kworker B (8k DIO, fallback)
----------------------------------- ----------------------------
inode_lock_shared() inode_lock_shared()
iomap_dio_rw(): iomap_dio_rw():
kiocb_invalidate_pages -> clean iomap_begin -> -ENOTBLK
submit_bio (async) dio->size = 0 inode_unlock_shared() inode_unlock_shared()
[bio pending in block layer] /* fallback: lock released */
ext4_buffered_write_iter()
inode_lock(exclusive)
generic_perform_write()
-> dirty pages [0, 8k]
inode_unlock(exclusive)
/* pages dirty, no lock */
[bio completes] filemap_write_and_wait_range()
iomap_dio_complete() -> flush dirty pages
kiocb_invalidate_post_direct_write() invalidate_mapping_pages()
invalidate_inode_pages2_range()
-> finds dirty page!
-> dio_warn_stale_pagecache()
-> errseq_set(-EIO)This issue can be triggered through normal I/O paths, not just intentionally overlapping DIO writes from userspace. For example, generic/746 uses a loop device where multiple kworkers issue concurrent I/O to the backing file. Additionally, when block_size < folio_size, non-overlapping DIO writes that share a large folio can also trigger the race.
Add inode_dio_wait() in ext4_buffered_write_iter() before ext4_write_checks() to drain all in-flight DIO. This ensures that all DIO clears existing pages before submitting IO (via kiocb_invalidate_pages()), all BIO waits for all DIO to complete (via inode_dio_wait()), and ext4_write_checks() observes the inode size after all completed DIO so that ext4_block_zero_eof() does not race with in-flight DIO, thus eliminating the race.
--- fs/ext4/file.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/ext4/file.c +7 -0
@@ -292,6 +292,13 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,return -EOPNOTSUPP ;inode_lock (inode); + +/* +* Prevent concurrent direct I/O and buffered I/O to the same file +* range. Wait for in-flight DIO to finish before dirtying pages. +*/ +inode_dio_wait (inode); + ret =ext4_write_checks (iocb, from);if (ret <=0 ) goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 644/1376 wifi: ath6kl: avoid buffer overreads in WMI event handlers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit f57314aade9d74d30f3360ec5ef85a83654748be ]
The following WMI event handlers currently read from the event buffer without first verifying that the message was large enough to hold the expected event:ath6kl_wmi_scan_complete_rx() ath6kl_wmi_addba_req_event_rx() ath6kl_wmi_delba_req_event_rx()
Add length checks to prevent overread.
--- drivers/net/wireless/ath/ath6kl/wmi.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath6kl/wmi.c +15 -2
@@ -1296,6 +1296,9 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len, {struct wmi_scan_complete_event *ev; +if (len <sizeof (*ev)) +return -EINVAL ; + ev = (struct wmi_scan_complete_event *) datap;ath6kl_scan_complete_evt (vif,a_sle32_to_cpu (ev->status));
@@ -3372,7 +3375,12 @@ static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,static int ath6kl_wmi_addba_req_event_rx (struct wmi *wmi,u8 *datap,int len,struct ath6kl_vif *vif) { -struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap; +struct wmi_addba_req_event *cmd; + +if (len <sizeof (*cmd)) +return -EINVAL ; + + cmd = (struct wmi_addba_req_event *)datap;aggr_recv_addba_req_evt (vif, cmd->tid,le16_to_cpu (cmd->st_seq_no), cmd->win_sz);
@@ -3383,7 +3391,12 @@ static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,static int ath6kl_wmi_delba_req_event_rx (struct wmi *wmi,u8 *datap,int len,struct ath6kl_vif *vif) { -struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap; +struct wmi_delba_event *cmd; + +if (len <sizeof (*cmd)) +return -EINVAL ; + + cmd = (struct wmi_delba_event *)datap;aggr_recv_delba_req_evt (vif, cmd->tid);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 645/1376 wifi: ath12k: Correctly copy the hint BSSID in WMI scan request
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 7b0bd40e97a00991122122d5888ae455fb2bfc7a ]
Currently, in ath12k_wmi_send_scan_start_cmd(), the logic to populate the hint_bssid copies the BSSID in the wrong direction, from the firmware message to the argument buffer. Swap the parameters so that the BSSID is correctly populated in the firmware message from the argument buffer.
Compile tested only.
--- drivers/net/wireless/ath/ath12k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath12k/wmi.c +2 -2
@@ -2479,8 +2479,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,for (i =0 ; i < arg->num_hint_bssid; ++i) { hint_bssid->freq_flags = arg->hint_bssid[i].freq_flags; -ether_addr_copy (&arg->hint_bssid[i].bssid.addr[0 ], - &hint_bssid->bssid.addr[0 ]); +ether_addr_copy (&hint_bssid->bssid.addr[0 ], + &arg->hint_bssid[i].bssid.addr[0 ]); hint_bssid++; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 646/1376 wifi: ath11k: Correctly copy the hint BSSID in WMI scan request
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 6fe2dddf59bbb2a96be0fcf23a205807b25ac173 ]
Currently, in ath11k_wmi_send_scan_start_cmd(), the logic to populate the hint_bssid copies the BSSID in the wrong direction, from the firmware message to the argument buffer. Swap the parameters so that the BSSID is correctly populated in the firmware message from the argument buffer.
This issue was reported on ath12k, but exists in ath11k as well.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath11k/wmi.c +2 -2
@@ -2411,8 +2411,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,for (i =0 ; i < params->num_hint_bssid; ++i) { hint_bssid->freq_flags = params->hint_bssid[i].freq_flags; -ether_addr_copy (¶ms->hint_bssid[i].bssid.addr[0 ], - &hint_bssid->bssid.addr[0 ]); +ether_addr_copy (&hint_bssid->bssid.addr[0 ], + ¶ms->hint_bssid[i].bssid.addr[0 ]); hint_bssid++; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 647/1376 wifi: ath12k: Avoid buffer overread in ath12k_wmi_op_rx()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 7698656a2f7b045af5a6859766238cefea1b1945 ]
Currently, in ath12k_wmi_op_rx(), the firmware buffer is read without first verifying that the buffer has enough data to hold a header. This could result in a buffer overread.
Update the logic to verify the buffer contains at least enough data to hold a wmi_cmd_hdr before reading from the buffer.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
--- drivers/net/wireless/ath/ath12k/wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/ath12k/wmi.c +4 -4
@@ -7196,12 +7196,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)struct wmi_cmd_hdr *cmd_hdr;enum wmi_tlv_event_id id; - cmd_hdr = (struct wmi_cmd_hdr *)skb->data; - id =le32_get_bits (cmd_hdr->cmd_id,WMI_CMD_HDR_CMD_ID ); - -if (!skb_pull (skb,sizeof (struct wmi_cmd_hdr ))) + cmd_hdr =skb_pull_data (skb,sizeof (*cmd_hdr)); +if (!cmd_hdr) goto out; + id =le32_get_bits (cmd_hdr->cmd_id,WMI_CMD_HDR_CMD_ID ); +switch (id) {/* Process all the WMI events here */ case WMI_SERVICE_READY_EVENTID :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 648/1376 wifi: ath11k: Avoid buffer overread in ath11k_wmi_tlv_op_rx()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 9ef9dd30058cc9223c72f711dca1a28a5947d0c5 ]
Currently, in ath11k_wmi_tlv_op_rx(), the firmware buffer is read without first verifying that the buffer has enough data to hold a header. This could result in a buffer overread.
Add an upfront length check before dereferencing skb->data as a wmi_cmd_hdr. The check is placed before the trace_ath11k_wmi_event() call to preserve the existing trace semantics (tracing the full raw WMI event including the header), unlike the analogous ath12k fix which could use skb_pull_data() directly.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath11k/wmi.c +4 -2
@@ -8757,13 +8757,15 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)struct wmi_cmd_hdr *cmd_hdr;enum wmi_tlv_event_id id; +if (skb->len <sizeof (*cmd_hdr)) + goto out; + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; id =FIELD_GET (WMI_CMD_HDR_CMD_ID , (cmd_hdr->cmd_id));trace_ath11k_wmi_event (ab, id, skb->data, skb->len); -if (skb_pull (skb,sizeof (struct wmi_cmd_hdr )) ==NULL ) - goto out; +skb_pull (skb,sizeof (*cmd_hdr));switch (id) {/* Process all the WMI events here */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 649/1376 RDMA/bnxt_re: Clear VM_MAYWRITE on DBR/toggle page mmap
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <[email protected]>
[ Upstream commit 9b66c9af7172ffcf727214fa0ebe9a5e1ed6eb16 ]
bnxt_re_mmap() rejects VM_WRITE for the DBR_PAGE and TOGGLE_PAGE mmap flags, but a read-only mapping can still retain VM_MAYWRITE. nd later be upgraded with mprotect(PROT_WRITE). This can bypass the write check that only runs at mmap time.
Clear VM_MAYWRITE before vm_insert_page() in the shared DBR/toggle-page branch, matching the existing policy that userspace writes are not expected for these pages.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +4 -2
@@ -4389,11 +4389,13 @@ int bnxt_re_mmap(struct ib_ucontext *ib_uctx, struct vm_area_struct *vma)case BNXT_RE_MMAP_DBR_PAGE :case BNXT_RE_MMAP_TOGGLE_PAGE :/* Driver doesn't expect write access for user space */ -if (vma->vm_flags &VM_WRITE ) +if (vma->vm_flags &VM_WRITE ) { ret = -EFAULT ; -else + }else { +vm_flags_clear (vma,VM_MAYWRITE ); ret =vm_insert_page (vma, vma->vm_start,virt_to_page ((void *)bnxt_entry->mem_offset)); + }break ;default : ret = -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 650/1376 ext4: fix buffer_head leak in ext4_init_orphan_info
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
[ Upstream commit 05704335803b69c1bfa8637b7ada942bf2ee8a41 ]
ext4_init_orphan_info() reads orphan file blocks with ext4_bread() and stores the returned buffer_head in oi->of_binfo[i].ob_bh.
If ext4_bread() succeeds but the orphan block magic or checksum validation fails, the function jumps to out_free. However, the old out_free loop starts releasing buffers from i - 1, so the current buffer_head at index i is skipped.
This leaks the buffer_head reference obtained by ext4_bread() on the bad magic and bad checksum error paths.
Fix this by tracking the number of successfully read buffer_heads and releasing exactly those buffer_heads on the error path.
--- fs/ext4/orphan.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ext4/orphan.c +6 -2
@@ -573,6 +573,7 @@ int ext4_init_orphan_info(struct super_block *sb)int i, j;int ret;int free; +int loaded =0 ;__le32 *bdata;int inodes_per_ob =ext4_inodes_per_orphan_block (sb);struct ext4_orphan_block_tail *ot;
@@ -616,6 +617,7 @@ int ext4_init_orphan_info(struct super_block *sb) ret = -EIO ; goto out_free; } + loaded++; ot =ext4_orphan_block_tail (sb, oi->of_binfo[i].ob_bh);if (le32_to_cpu (ot->ob_magic) !=EXT4_ORPHAN_BLOCK_MAGIC ) {ext4_error (sb,"orphan file block %d: bad magic" , i);
@@ -638,8 +640,10 @@ int ext4_init_orphan_info(struct super_block *sb)iput (inode);return 0 ; out_free: -for (i--; i >=0 ; i--) -brelse (oi->of_binfo[i].ob_bh); +while (loaded >0 ) { + loaded--; +brelse (oi->of_binfo[loaded].ob_bh); + }kvfree (oi->of_binfo); out_put:iput (inode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 651/1376 ext4: check dir entry fits before reading the hash trailer in ext4_search_dir()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit c7e6b863d298f56522d0d08554bbea7f142e6588 ]
For casefolded encrypted directories ext4 stores an 8-byte hash trailer after the name (EXT4_DIRENT_HASHES()), at an offset derived from de->name_len. On the sb_no_casefold_compat_fallback() path ext4_match() reads that trailer, but ext4_search_dir()'s by-hand pre-check only tests de->name + de->name_len <= dlimit, which proves the name fits, not the rounded trailer. A crafted entry whose name ends at the block boundary passes the check while EXT4_DIRENT_HASHES(de) lands past the block end, so ext4_match() reads out of bounds on an ordinary lookup. KASAN reports it as a use-after-free when the page after the directory block holds a freed object:
BUG: KASAN: use-after-free in ext4_match (fs/ext4/namei.c:1435) Read of size 4 at addr ffff888010458000 by task exploit Call Trace: ext4_match (fs/ext4/namei.c:1435) ext4_search_dir (fs/ext4/namei.c:1470) __ext4_find_entry (fs/ext4/namei.c:1268 fs/ext4/namei.c:1632) ext4_lookup (fs/ext4/namei.c:1703 fs/ext4/namei.c:1769) ... filename_lookup (fs/namei.c:2842) vfs_statx (fs/stat.c:353) __do_sys_newfstatat (fs/stat.c:538) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Require, for hash-in-dirent directories, that the whole entry including the rounded trailer fits before calling ext4_match(). This is the same bound ext4_check_dir_entry() already enforces via ext4_dir_rec_len(), so no well-formed entry is rejected. The other caller, ext4_find_dest_de(), runs ext4_check_dir_entry() first and is unaffected.
--- fs/ext4/namei.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ext4/namei.c +2 -0
@@ -1499,6 +1499,8 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,/* this code is executed quadratically often */ /* do minimal checking `by hand' */ if (de->name + de->name_len <= dlimit && + (!ext4_hash_in_dirent (dir) || + (char *)de +ext4_dir_rec_len (de->name_len, dir) <= dlimit) &&ext4_match (dir, fname, de)) {/* found a match - just to be sure, do * a full check */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 652/1376 ARM: dts: allwinner: a10: Fix PMU interrupt
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andre Przywara <[email protected]>
[ Upstream commit eb7051f756460d7b951e94d9656e31ebb631ba28 ]
The Performance Monitoring Unit of the Cortex-A8 cores in the Allwinner A10 SoC is connected to interrupt line 66, not 3. This is shown in the manual (where interrupt 3 is assigned to UART2, also in our .dtsi), but has also been confirmed by triggering an PMU overflow interrupt and inspecting the IRQ controller status registers (from U-Boot). Please note that "perf stat" does not use interrupts, this might explain why this evaded the initial testing.
--- arch/arm/boot/dts/allwinner/sun4i-a10.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/allwinner/sun4i-a10.dtsi +1 -1
@@ -185,7 +185,7 @@ de: display-engine { pmu { compatible = "arm,cortex-a8-pmu"; - interrupts = <3>; + interrupts = <66>; }; reserved-memory {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 653/1376 cpufreq/amd-pstate: Store the boost numerator as highest perf again
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
[ Upstream commit 50a062a7620051c09adacd6d140ebd56881a333b ]
commit ad4caad58d91d ("cpufreq: amd-pstate: Merge amd_pstate_highest_perf_set() into amd_get_boost_ratio_numerator()") changed the semantics for highest perf and commit 18d9b52271213 ("cpufreq/amd-pstate: Use nominal perf for limits when boost is disabled") worked around those semantic changes.
This however is a confusing result and furthermore makes it awkward to change frequency limits and boost due to the scaling differences. Restore the boost numerator to highest perf again.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- Documentation/admin-guide/pm/amd-pstate.rst | 4 +--- drivers/cpufreq/amd-pstate.c | 25 ++++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-)
Documentation/admin-guide/pm/amd-pstate.rst +1 -3
@@ -251,9 +251,7 @@ performance supported in `AMD CPPC Performance Capability <perf_cap_>`_). In some ASICs, the highest CPPC performance is not the one in the ``_CPC`` table, so we need to expose it to sysfs. If boost is not active, but still supported, this maximum frequency will be larger than the one in -``cpuinfo``. On systems that support preferred core, the driver will have -different values for some cores than others and this will reflect the values -advertised by the platform at bootup. +``cpuinfo``. This attribute is read-only. ``amd_pstate_lowest_nonlinear_freq``
drivers/cpufreq/amd-pstate.c +15 -10
@@ -368,15 +368,19 @@ static inline int amd_pstate_enable(bool enable)static int pstate_init_perf (struct amd_cpudata *cpudata) { -u64 cap1; +u64 cap1, numerator;int ret =rdmsrl_safe_on_cpu (cpudata->cpu,MSR_AMD_CPPC_CAP1 , &cap1);if (ret)return ret; -WRITE_ONCE (cpudata->highest_perf,AMD_CPPC_HIGHEST_PERF (cap1)); -WRITE_ONCE (cpudata->max_limit_perf,AMD_CPPC_HIGHEST_PERF (cap1)); + ret =amd_get_boost_ratio_numerator (cpudata->cpu, &numerator); +if (ret) +return ret; + +WRITE_ONCE (cpudata->highest_perf, numerator); +WRITE_ONCE (cpudata->max_limit_perf, numerator);WRITE_ONCE (cpudata->nominal_perf,AMD_CPPC_NOMINAL_PERF (cap1));WRITE_ONCE (cpudata->lowest_nonlinear_perf,AMD_CPPC_LOWNONLIN_PERF (cap1));WRITE_ONCE (cpudata->lowest_perf,AMD_CPPC_LOWEST_PERF (cap1));
@@ -388,13 +392,18 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)static int cppc_init_perf (struct amd_cpudata *cpudata) {struct cppc_perf_caps cppc_perf; +u64 numerator;int ret =cppc_get_perf_caps (cpudata->cpu, &cppc_perf);if (ret)return ret; -WRITE_ONCE (cpudata->highest_perf, cppc_perf.highest_perf); -WRITE_ONCE (cpudata->max_limit_perf, cppc_perf.highest_perf); + ret =amd_get_boost_ratio_numerator (cpudata->cpu, &numerator); +if (ret) +return ret; + +WRITE_ONCE (cpudata->highest_perf, numerator); +WRITE_ONCE (cpudata->max_limit_perf, numerator);WRITE_ONCE (cpudata->nominal_perf, cppc_perf.nominal_perf);WRITE_ONCE (cpudata->lowest_nonlinear_perf, cppc_perf.lowest_nonlinear_perf);
@@ -867,7 +876,6 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) {int ret;u32 min_freq, max_freq; -u64 numerator;u32 nominal_perf, nominal_freq;u32 lowest_nonlinear_perf, lowest_nonlinear_freq;u32 boost_ratio, lowest_nonlinear_ratio;
@@ -889,10 +897,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) nominal_perf =READ_ONCE (cpudata->nominal_perf); - ret =amd_get_boost_ratio_numerator (cpudata->cpu, &numerator); -if (ret) -return ret; - boost_ratio =div_u64 (numerator <<SCHED_CAPACITY_SHIFT , nominal_perf); + boost_ratio =div_u64 (cpudata->highest_perf <<SCHED_CAPACITY_SHIFT , nominal_perf); max_freq = (nominal_freq * boost_ratio >>SCHED_CAPACITY_SHIFT ) *1000 ; lowest_nonlinear_perf =READ_ONCE (cpudata->lowest_nonlinear_perf);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 654/1376 ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit e3d7935a6c6138da51626d2b956a079dd0e6671b ]
In ACPI 6.5, s8.4.6.1 _CPC (Continuous Performance Control), whether each of the per-cpu cpc_regs[] is mandatory or optional is defined.
Since the CPC_SUPPORTED() check is only for optional _CPC fields, another macro to check if the field is optional is needed.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/acpi/cppc_acpi.c +14 -0
@@ -129,6 +129,20 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);#define CPC_SUPPORTED (cpc) ((cpc)->type == ACPI_TYPE_INTEGER ? \ !!(cpc)->cpc_entry.int_value : \ !IS_NULL_REG(&(cpc)->cpc_entry.reg)) + +/* +* Each bit indicates the optionality of the register in per-cpu +* cpc_regs[] with the corresponding index. 0 means mandatory and 1 +* means optional. +*/ +#define REG_OPTIONAL (0x1FC7D0) + +/* +* Use the index of the register in per-cpu cpc_regs[] to check if +* it's an optional one. +*/ +#define IS_OPTIONAL_CPC_REG (reg_idx) (REG_OPTIONAL & (1U << (reg_idx))) +/* * Arbitrary Retries in case the remote processor is slow to respond * to PCC commands. Keeping it high enough to cover emulators where
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 655/1376 ACPI: CPPC: Optimize cppc_get_perf()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit 45f3763a2122553e548fa0430b77605dc23f00cc ]
Optimize cppc_get_perf() with three changes:
1. Change the error kind to "no such device" when pcc_ss_id < 0, as other register value getting functions.
2. Add a check to ensure the pointer 'perf' is no null.
3. Add a check to verify if the register is supported to be read before using it. The logic is:
(1) If the register is of the integer type, check whether the register is optional and its value is 0. If yes, the register is not supported.
(2) If the register is of other types, a null one is not supported.
4. Return the result of cpc_read() instead of 0.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
drivers/acpi/cppc_acpi.c +17 -7
@@ -1195,6 +1195,9 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpunum);struct cpc_register_resource *reg; +if (perf ==NULL ) +return -EINVAL ; +if (!cpc_desc) {pr_debug ("No CPC descriptor for CPU:%d\n" , cpunum);return -ENODEV ;
@@ -1202,20 +1205,29 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) reg = &cpc_desc->cpc_regs[reg_idx]; +if ((reg->type ==ACPI_TYPE_INTEGER &&IS_OPTIONAL_CPC_REG (reg_idx) && + !reg->cpc_entry.int_value) || (reg->type !=ACPI_TYPE_INTEGER && +IS_NULL_REG (®->cpc_entry.reg))) { +pr_debug ("CPC register is not supported\n" ); +return -EOPNOTSUPP ; + } +if (CPC_IN_PCC (reg)) {int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpunum);struct cppc_pcc_data *pcc_ss_data =NULL ; -int ret =0 ; +int ret; -if (pcc_ss_id <0 ) -return -EIO ; +if (pcc_ss_id <0 ) { +pr_debug ("Invalid pcc_ss_id\n" ); +return -ENODEV ; + } pcc_ss_data = pcc_data[pcc_ss_id];down_write (&pcc_ss_data->pcc_lock);if (send_pcc_cmd (pcc_ss_id,CMD_READ ) >=0 ) -cpc_read (cpunum, reg, perf); + ret =cpc_read (cpunum, reg, perf);else ret = -EIO ;
@@ -1224,9 +1236,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)return ret; } -cpc_read (cpunum, reg, perf); - -return 0 ; +return cpc_read (cpunum, reg, perf); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 656/1376 ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit 714d103ce868cd0718d0e5262cbc76384a2eb03a ]
Rename cppc_get_perf() to cppc_get_reg_val() as a generic function to read CPPC registers.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
drivers/acpi/cppc_acpi.c +11 -11
@@ -1190,16 +1190,16 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)return ret_val; } -static int cppc_get_perf (int cpunum,enum cppc_regs reg_idx,u64 *perf) +static int cppc_get_reg_val (int cpu,enum cppc_regs reg_idx,u64 *val) { -struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpunum); +struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu);struct cpc_register_resource *reg; -if (perf ==NULL ) +if (val ==NULL )return -EINVAL ;if (!cpc_desc) { -pr_debug ("No CPC descriptor for CPU:%d\n" , cpunum); +pr_debug ("No CPC descriptor for CPU:%d\n" , cpu);return -ENODEV ; }
@@ -1213,7 +1213,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) }if (CPC_IN_PCC (reg)) { -int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpunum); +int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpu);struct cppc_pcc_data *pcc_ss_data =NULL ;int ret;
@@ -1227,7 +1227,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)down_write (&pcc_ss_data->pcc_lock);if (send_pcc_cmd (pcc_ss_id,CMD_READ ) >=0 ) - ret =cpc_read (cpunum, reg, perf); + ret =cpc_read (cpu, reg, val);else ret = -EIO ;
@@ -1236,7 +1236,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)return ret; } -return cpc_read (cpunum, reg, perf); +return cpc_read (cpu, reg, val); }/**
@@ -1248,7 +1248,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf)*/ int cppc_get_desired_perf (int cpunum,u64 *desired_perf) { -return cppc_get_perf (cpunum,DESIRED_PERF , desired_perf); +return cppc_get_reg_val (cpunum,DESIRED_PERF , desired_perf); }EXPORT_SYMBOL_GPL (cppc_get_desired_perf);
@@ -1261,7 +1261,7 @@ EXPORT_SYMBOL_GPL(cppc_get_desired_perf);*/ int cppc_get_nominal_perf (int cpunum,u64 *nominal_perf) { -return cppc_get_perf (cpunum,NOMINAL_PERF , nominal_perf); +return cppc_get_reg_val (cpunum,NOMINAL_PERF , nominal_perf); }/**
@@ -1273,7 +1273,7 @@ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf)*/ int cppc_get_highest_perf (int cpunum,u64 *highest_perf) { -return cppc_get_perf (cpunum,HIGHEST_PERF , highest_perf); +return cppc_get_reg_val (cpunum,HIGHEST_PERF , highest_perf); }EXPORT_SYMBOL_GPL (cppc_get_highest_perf);
@@ -1286,7 +1286,7 @@ EXPORT_SYMBOL_GPL(cppc_get_highest_perf);*/ int cppc_get_epp_perf (int cpunum,u64 *epp_perf) { -return cppc_get_perf (cpunum,ENERGY_PERF , epp_perf); +return cppc_get_reg_val (cpunum,ENERGY_PERF , epp_perf); }EXPORT_SYMBOL_GPL (cppc_get_epp_perf);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 657/1376 ACPI: CPPC: Add cppc_set_reg_val()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit e05c75072c2eaa6e0b152a558b3be5cbcf79a587 ]
Add cppc_set_reg_val() as a generic function for setting CPPC register values, with this features:
1. Check register. If a register is writeable, it must be a buffer and can not be null.
2. Extract the operations if register is in PCC out as
cppc_set_reg_val_in_pcc().
This function can be used to reduce some existing code duplication.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
drivers/acpi/cppc_acpi.c +49 -0
@@ -1239,6 +1239,55 @@ static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val)return cpc_read (cpu, reg, val); } +static int cppc_set_reg_val_in_pcc (int cpu,struct cpc_register_resource *reg,u64 val) +{ +int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpu); +struct cppc_pcc_data *pcc_ss_data =NULL ; +int ret; + +if (pcc_ss_id <0 ) { +pr_debug ("Invalid pcc_ss_id\n" ); +return -ENODEV ; + } + + ret =cpc_write (cpu, reg, val); +if (ret) +return ret; + + pcc_ss_data = pcc_data[pcc_ss_id]; + +down_write (&pcc_ss_data->pcc_lock); +/* after writing CPC, transfer the ownership of PCC to platform */ + ret =send_pcc_cmd (pcc_ss_id,CMD_WRITE ); +up_write (&pcc_ss_data->pcc_lock); + +return ret; +} + +static int cppc_set_reg_val (int cpu,enum cppc_regs reg_idx,u64 val) +{ +struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); +struct cpc_register_resource *reg; + +if (!cpc_desc) { +pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); +return -ENODEV ; + } + + reg = &cpc_desc->cpc_regs[reg_idx]; + +/* if a register is writeable, it must be a buffer and not null */ +if ((reg->type !=ACPI_TYPE_BUFFER ) ||IS_NULL_REG (®->cpc_entry.reg)) { +pr_debug ("CPC register is not supported\n" ); +return -EOPNOTSUPP ; + } + +if (CPC_IN_PCC (reg)) +return cppc_set_reg_val_in_pcc (cpu, reg, val); + +return cpc_write (cpu, reg, val); +} +/** * cppc_get_desired_perf - Get the desired performance register value. * @cpunum: CPU from which to get desired performance.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 658/1376 ACPI: CPPC: Refactor register value get and set ABIs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit ab482f1bac6b128b8fe910b6663a4f74a3a9796c ]
Refactor register value get and set ABIs by using cppc_get_reg_val(), cppc_set_reg_val() and CPPC_REG_VAL_READ().
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 111 +++------------------------------------ 1 file changed, 7 insertions(+), 104 deletions(-)
drivers/acpi/cppc_acpi.c +7 -104
@@ -1616,44 +1616,14 @@ EXPORT_SYMBOL_GPL(cppc_set_epp_perf);*/ int cppc_get_auto_sel_caps (int cpunum,struct cppc_perf_caps *perf_caps) { -struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpunum); -struct cpc_register_resource *auto_sel_reg; -u64 auto_sel; - -if (!cpc_desc) { -pr_debug ("No CPC descriptor for CPU:%d\n" , cpunum); -return -ENODEV ; - } - - auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE ]; - -if (!CPC_SUPPORTED (auto_sel_reg)) -pr_warn_once ("Autonomous mode is not unsupported!\n" ); - -if (CPC_IN_PCC (auto_sel_reg)) { -int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpunum); -struct cppc_pcc_data *pcc_ss_data =NULL ; -int ret =0 ; - -if (pcc_ss_id <0 ) -return -ENODEV ; - - pcc_ss_data = pcc_data[pcc_ss_id]; - -down_write (&pcc_ss_data->pcc_lock); - -if (send_pcc_cmd (pcc_ss_id,CMD_READ ) >=0 ) { -cpc_read (cpunum, auto_sel_reg, &auto_sel); - perf_caps->auto_sel = (bool )auto_sel; - }else { - ret = -EIO ; - } - -up_write (&pcc_ss_data->pcc_lock); +u64 auto_sel; +int ret; + ret =cppc_get_reg_val (cpunum,AUTO_SEL_ENABLE , &auto_sel); +if (ret)return ret; - } + perf_caps->auto_sel = (bool )auto_sel;return 0 ; }EXPORT_SYMBOL_GPL (cppc_get_auto_sel_caps);
@@ -1665,43 +1635,7 @@ EXPORT_SYMBOL_GPL(cppc_get_auto_sel_caps);*/ int cppc_set_auto_sel (int cpu,bool enable) { -int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpu); -struct cpc_register_resource *auto_sel_reg; -struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); -struct cppc_pcc_data *pcc_ss_data =NULL ; -int ret = -EINVAL ; - -if (!cpc_desc) { -pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); -return -ENODEV ; - } - - auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE ]; - -if (CPC_IN_PCC (auto_sel_reg)) { -if (pcc_ss_id <0 ) { -pr_debug ("Invalid pcc_ss_id\n" ); -return -ENODEV ; - } - -if (CPC_SUPPORTED (auto_sel_reg)) { - ret =cpc_write (cpu, auto_sel_reg, enable); -if (ret) -return ret; - } - - pcc_ss_data = pcc_data[pcc_ss_id]; - -down_write (&pcc_ss_data->pcc_lock); -/* after writing CPC, transfer the ownership of PCC to platform */ - ret =send_pcc_cmd (pcc_ss_id,CMD_WRITE ); -up_write (&pcc_ss_data->pcc_lock); - }else { - ret = -ENOTSUPP ; -pr_debug ("_CPC in PCC is not supported\n" ); - } - -return ret; +return cppc_set_reg_val (cpu,AUTO_SEL_ENABLE , enable); }EXPORT_SYMBOL_GPL (cppc_set_auto_sel);
@@ -1715,38 +1649,7 @@ EXPORT_SYMBOL_GPL(cppc_set_auto_sel);*/ int cppc_set_enable (int cpu,bool enable) { -int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpu); -struct cpc_register_resource *enable_reg; -struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); -struct cppc_pcc_data *pcc_ss_data =NULL ; -int ret = -EINVAL ; - -if (!cpc_desc) { -pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); -return -EINVAL ; - } - - enable_reg = &cpc_desc->cpc_regs[ENABLE ]; - -if (CPC_IN_PCC (enable_reg)) { - -if (pcc_ss_id <0 ) -return -EIO ; - - ret =cpc_write (cpu, enable_reg, enable); -if (ret) -return ret; - - pcc_ss_data = pcc_data[pcc_ss_id]; - -down_write (&pcc_ss_data->pcc_lock); -/* after writing CPC, transfer the ownership of PCC to platfrom */ - ret =send_pcc_cmd (pcc_ss_id,CMD_WRITE ); -up_write (&pcc_ss_data->pcc_lock); -return ret; - } - -return cpc_write (cpu, enable_reg, enable); +return cppc_set_reg_val (cpu,ENABLE , enable); }EXPORT_SYMBOL_GPL (cppc_set_enable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 659/1376 ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lifeng Zheng <[email protected]>
[ Upstream commit 2605e4ab6615ef43361b18fc6d08dd884896aad8 ]
Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel(). Using a cppc_perf_caps to carry the value is unnecessary.
Add a check to ensure the pointer 'enable' is not null.
Stable-dep-of: 9dfd13f80c85 ("cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems")
--- drivers/acpi/cppc_acpi.c | 18 +++++++++++------- drivers/cpufreq/amd-pstate.c | 3 ++- include/acpi/cppc_acpi.h | 6 +++--- 3 files changed, 16 insertions(+), 11 deletions(-)
drivers/acpi/cppc_acpi.c +11 -7
@@ -1610,23 +1610,27 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)EXPORT_SYMBOL_GPL (cppc_set_epp_perf);/** -* cppc_get_auto_sel_caps - Read autonomous selection register. -* @cpunum : CPU from which to read register. -* @perf_caps : struct where autonomous selection register value is updated. +* cppc_get_auto_sel() - Read autonomous selection register. +* @cpu: CPU from which to read register. +* @enable: Return address. */ -int cppc_get_auto_sel_caps (int cpunum,struct cppc_perf_caps *perf_caps) +int cppc_get_auto_sel (int cpu,bool *enable) {u64 auto_sel;int ret; - ret =cppc_get_reg_val (cpunum,AUTO_SEL_ENABLE , &auto_sel); +if (enable ==NULL ) +return -EINVAL ; + + ret =cppc_get_reg_val (cpu,AUTO_SEL_ENABLE , &auto_sel);if (ret)return ret; - perf_caps->auto_sel = (bool )auto_sel; + *enable = (bool )auto_sel; +return 0 ; } -EXPORT_SYMBOL_GPL (cppc_get_auto_sel_caps); +EXPORT_SYMBOL_GPL (cppc_get_auto_sel);/** * cppc_set_auto_sel - Write autonomous selection register.
drivers/cpufreq/amd-pstate.c +2 -1
@@ -393,6 +393,7 @@ static int cppc_init_perf(struct amd_cpudata *cpudata) {struct cppc_perf_caps cppc_perf;u64 numerator; +bool auto_sel;int ret =cppc_get_perf_caps (cpudata->cpu, &cppc_perf);if (ret)
@@ -414,7 +415,7 @@ static int cppc_init_perf(struct amd_cpudata *cpudata)if (cppc_state ==AMD_PSTATE_ACTIVE )return 0 ; - ret =cppc_get_auto_sel_caps (cpudata->cpu, &cppc_perf); + ret =cppc_get_auto_sel (cpudata->cpu, &auto_sel);if (ret) {pr_warn ("failed to get auto_sel, ret: %d\n" , ret);return 0 ;
include/acpi/cppc_acpi.h +3 -3
@@ -159,7 +159,7 @@ extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);extern int cpc_write_ffh (int cpunum,struct cpc_reg *reg,u64 val);extern int cppc_get_epp_perf (int cpunum,u64 *epp_perf);extern int cppc_set_epp_perf (int cpu,struct cppc_perf_ctrls *perf_ctrls,bool enable); -extern int cppc_get_auto_sel_caps (int cpunum,struct cppc_perf_caps *perf_caps); +extern int cppc_get_auto_sel (int cpu,bool *enable);extern int cppc_set_auto_sel (int cpu,bool enable);extern int amd_get_highest_perf (unsigned int cpu,u32 *highest_perf);extern int amd_get_boost_ratio_numerator (unsigned int cpu,u64 *numerator);
@@ -229,11 +229,11 @@ static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf) {return -EOPNOTSUPP ; } -static inline int cppc_set_auto_sel (int cpu,bool enable) +static inline int cppc_get_auto_sel (int cpu,bool *enable) {return -EOPNOTSUPP ; } -static inline int cppc_get_auto_sel_caps (int cpunum,struct cppc_perf_caps *perf_caps) +static inline int cppc_set_auto_sel (int cpu,bool enable) {return -EOPNOTSUPP ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 660/1376 cpufreq/amd-pstate: Toggle auto_sel in active mode on shared memory systems
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Scardovi <[email protected]>
[ Upstream commit 9dfd13f80c856eab79130403a13fa3b83199346b ]
On shared memory systems, the EPP configuration path (handled via cppc_set_epp_perf()) is responsible for toggling on the CPPC autonomous selection register (auto_sel).
Currently, shmem_init_perf() returns early without doing any of the auto_sel configuration steps if cppc_state is AMD_PSTATE_ACTIVE. This skips enabling auto_sel, leaving the CPU in non-autonomous mode.
Remove the early return check in shmem_init_perf() when cppc_state is AMD_PSTATE_ACTIVE. Toggling auto_sel is necessary for the active mode on shared memory systems to function based on the ACPI spec for CPPC v2 and below.
--- drivers/cpufreq/amd-pstate.c | 3 --- 1 file changed, 3 deletions(-)
drivers/cpufreq/amd-pstate.c +0 -3
@@ -412,9 +412,6 @@ static int cppc_init_perf(struct amd_cpudata *cpudata)WRITE_ONCE (cpudata->prefcore_ranking, cppc_perf.highest_perf);WRITE_ONCE (cpudata->min_limit_perf, cppc_perf.lowest_perf); -if (cppc_state ==AMD_PSTATE_ACTIVE ) -return 0 ; - ret =cppc_get_auto_sel (cpudata->cpu, &auto_sel);if (ret) {pr_warn ("failed to get auto_sel, ret: %d\n" , ret);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 661/1376 firmware: arm_scmi: Roll back partial protocol table registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 2224b622260ba590ab56ea1585d6bf7610be25b2 ]
scmi_protocol_table_register() can leave earlier requests registered when a later entry in the same ID table fails. Each request retains a pointer to the driver's ID table, so a failed module load can leave a dangling pointer after the module storage is released.
Unrequest only the successfully registered prefix, in reverse order, before returning the failure. Leave the failed entry and the remaining entries untouched because matching requests can be owned by another driver.
--- drivers/firmware/arm_scmi/bus.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
drivers/firmware/arm_scmi/bus.c +20 -11
@@ -134,17 +134,6 @@ static int scmi_protocol_device_request(const struct scmi_device_id *id_table)return ret; } -static int scmi_protocol_table_register (const struct scmi_device_id *id_table) -{ -int ret =0 ; -const struct scmi_device_id *entry; - -for (entry = id_table; entry->name && ret ==0 ; entry++) - ret =scmi_protocol_device_request (entry); - -return ret; -} -/** * scmi_protocol_device_unrequest - Helper to unrequest a device *
@@ -190,6 +179,26 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table } } +static int scmi_protocol_table_register (const struct scmi_device_id *id_table) +{ +const struct scmi_device_id *entry; +int ret; + +for (entry = id_table; entry->name; entry++) { + ret =scmi_protocol_device_request (entry); +if (ret) + goto err_unrequest; + } + +return 0 ; + +err_unrequest: +while (entry != id_table) +scmi_protocol_device_unrequest (--entry); + +return ret; +} +static void scmi_protocol_table_unregister (const struct scmi_device_id *id_table) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 662/1376 firmware: arm_scmi: Unrequest devices if driver registration fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <[email protected]>
[ Upstream commit 9f7cd6a62aa754ed6b48cbd5d50de40add1bcc86 ]
scmi_driver_register() requests protocol devices before registering the driver. If driver_register() fails, those requests remain in the global IDR and retain pointers to the module's ID table. Once the failed module load releases that storage, later request matching or SCMI device creation can dereference the stale pointers.
Unrequest the complete protocol table before returning the registration failure. At this point table registration succeeded, so every entry is owned by the current registration attempt.
--- drivers/firmware/arm_scmi/bus.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/firmware/arm_scmi/bus.c +7 -3
@@ -314,10 +314,14 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, driver->driver.mod_name = mod_name; retval =driver_register (&driver->driver); -if (!retval) -pr_debug ("Registered new scmi driver %s\n" , driver->name); +if (retval) { +scmi_protocol_table_unregister (driver->id_table); +return retval; + } -return retval; +pr_debug ("Registered new scmi driver %s\n" , driver->name); + +return 0 ; }EXPORT_SYMBOL_GPL (scmi_driver_register);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 663/1376 perf cs-etm: Flush thread stacks after decoder reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit ea5075e3776846d4941dddf1549426ebd3feb81f ]
Perf resets the CoreSight decoder when moving to a new AUX trace buffer, this causes trace discontinunity globally.
For callchain synthesis, keeping thread-stack state after decoder reset can leave stale call/return history attached to threads that are decoded later, producing incorrect synthesized callchains.
Flush all host thread stacks after a decoder reset. When virtualization is present, flush the guest thread stacks as well.
Stable-dep-of: ec99be8a31db ("perf cs-etm: Avoid truncating AUX buffer sizes to int")
--- tools/perf/util/cs-etm.c | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
tools/perf/util/cs-etm.c +45 -0
@@ -2039,6 +2039,45 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,return 0 ; } + +static int cs_etm__flush_stack_cb (struct thread *thread, +void *data__maybe_unused ) +{ +thread_stack__flush (thread); +return 0 ; +} + +static void cs_etm__flush_machine_stack (struct cs_etm_queue *etmq,pid_t pid) +{ +struct machine *machine; + + machine =machines__find (&etmq->etm->session->machines, pid); +if (machine) +machine__for_each_thread (machine, cs_etm__flush_stack_cb,NULL ); +} + +static void cs_etm__flush_all_stack (struct cs_etm_queue *etmq) +{ +enum cs_etm_pid_fmt pid_fmt =cs_etm__get_pid_fmt (etmq); + +if (!etmq->etm->synth_opts.last_branch) +return ; + +switch (pid_fmt) { +case CS_ETM_PIDFMT_CTXTID2 : +/* Clear the guest stack if virtualization is supported */ +cs_etm__flush_machine_stack (etmq,DEFAULT_GUEST_KERNEL_ID ); + fallthrough; +case CS_ETM_PIDFMT_CTXTID : +cs_etm__flush_machine_stack (etmq,HOST_KERNEL_ID ); +break ; +case CS_ETM_PIDFMT_NONE : +default : +break ; + + } +} +/* * cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue * if need be.
@@ -2061,6 +2100,12 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) ret =cs_etm_decoder__reset (etmq->decoder);if (ret)return ret; + +/* +* Since the decoder is reset, this causes a global trace +* discontinuity. Flush all thread stacks. +*/ +cs_etm__flush_all_stack (etmq); }return etmq->buf_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1376 perf cs-etm: Avoid truncating AUX buffer sizes to int
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit ec99be8a31db999a4f866be74ea7db61dbb19f24 ]
cs_etm__get_trace() returns an int, but it used to return etmq->buf_len on success. That value comes from auxtrace_buffer::size, which is a size_t. For a large AUX trace block, returning the byte count through an int can overflow and make a valid buffer look like a negative error.
The callers do not need the actual byte count from cs_etm__get_trace(). The buffer length is already stored in the etmq->buf_len. The callers only need to distinguish three states:
< 0: error
= 0: no more AUX buffers
Quoted 1 line
0: data is available
Make cs_etm__get_trace() return 0 for all non-error cases and use etmq->buf_len to indicate whether a new buffer was found. Then make cs_etm__get_data_block() return 1 whenever data is available, instead of returning the buffer length.
Also refactor cs_etm__get_data_block() to make its return value semantics clearer.
--- tools/perf/util/cs-etm.c | 46 +++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-)
tools/perf/util/cs-etm.c +26 -20
@@ -1484,8 +1484,7 @@ cs_etm__get_trace(struct cs_etm_queue *etmq) etmq->buf_used =0 ; etmq->buf_len = aux_buffer->size; etmq->buf = aux_buffer->data; - -return etmq->buf_len; +return 0 ; }/*
@@ -2089,26 +2088,33 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) {int ret; -if (!etmq->buf_len) { - ret =cs_etm__get_trace (etmq); -if (ret <=0 ) -return ret; -/* -* We cannot assume consecutive blocks in the data file -* are contiguous, reset the decoder to force re-sync. -*/ - ret =cs_etm_decoder__reset (etmq->decoder); -if (ret) -return ret; +/* The current block is not finished */ +if (etmq->buf_len) +return 1 ; -/* -* Since the decoder is reset, this causes a global trace -* discontinuity. Flush all thread stacks. -*/ -cs_etm__flush_all_stack (etmq); - } + ret =cs_etm__get_trace (etmq); +if (ret <0 ) +return ret; + +/* No more buffer to read */ +if (!etmq->buf_len) +return 0 ; + +/* +* We cannot assume consecutive blocks in the data file +* are contiguous, reset the decoder to force re-sync. +*/ + ret =cs_etm_decoder__reset (etmq->decoder); +if (ret) +return ret; + +/* +* Since the decoder is reset, this causes a global trace +* discontinuity. Flush all thread stacks. +*/ +cs_etm__flush_all_stack (etmq); -return etmq->buf_len; +return 1 ; } static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1376 xfrm: Fix skb double-free in xfrm_dev_direct_output()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanghyun Park <[email protected]>
[ Upstream commit 2aed51fc58d9ce450e2c116efb956160fd06fa02 ]
A return value other than 1 from local_out() means that the skb has been consumed or its ownership was transferred. xfrm_dev_direct_output() nevertheless frees the skb on this path, causing a double-free when netfilter drops the packet and invalidating any other owner.
Return the local_out() result directly, matching the ownership handling in xfrm_output_resume().
--- net/xfrm/xfrm_output.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/xfrm/xfrm_output.c +1 -3
@@ -627,10 +627,8 @@ static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x,nf_reset_ct (skb); err =skb_dst (skb)->ops->local_out (net, sk, skb); -if (unlikely (err !=1 )) { -kfree_skb (skb); +if (unlikely (err !=1 ))return err; - }/* In transport mode, network destination is * directly reachable, while in tunnel mode,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1376 RDMA/erdma: Probe the erdma RoCEv2 device
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit a883e71345a0101ff33be23a8d13f112ec4defb5 ]
Currently, the erdma driver supports both the iWARP and RoCEv2 protocols. The erdma driver reads the ERDMA_REGS_DEV_PROTO_REG register to identify the protocol used by the erdma device. Since each protocol requires different ib_device_ops, we introduce the erdma_device_ops_iwarp and erdma_device_ops_rocev2 for iWARP and RoCEv2 protocols, respectively.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/Kconfig | 2 +- drivers/infiniband/hw/erdma/erdma.h | 3 +- drivers/infiniband/hw/erdma/erdma_hw.h | 7 +++++ drivers/infiniband/hw/erdma/erdma_main.c | 34 +++++++++++++++++------ drivers/infiniband/hw/erdma/erdma_verbs.c | 16 ++++++++++- drivers/infiniband/hw/erdma/erdma_verbs.h | 12 ++++++++ 6 files changed, 62 insertions(+), 12 deletions(-)
drivers/infiniband/hw/erdma/Kconfig +1 -1
@@ -5,7 +5,7 @@ config INFINIBAND_ERDMA depends on INFINIBAND_ADDR_TRANS depends on INFINIBAND_USER_ACCESS help - This is a RDMA/iWarp driver for Alibaba Elastic RDMA Adapter(ERDMA), + This is a RDMA driver for Alibaba Elastic RDMA Adapter(ERDMA), which supports RDMA features in Alibaba cloud environment. To compile this driver as module, choose M here. The module will be
drivers/infiniband/hw/erdma/erdma.h +2 -1
@@ -16,7 +16,7 @@#include "erdma_hw.h" #define DRV_MODULE_NAME "erdma" -#define ERDMA_NODE_DESC "Elastic RDMA(iWARP) stack" +#define ERDMA_NODE_DESC "Elastic RDMA Adapter stack"struct erdma_eq {void *qbuf;
@@ -215,6 +215,7 @@ struct erdma_dev {struct dma_pool *db_pool;struct dma_pool *resp_pool; +enum erdma_proto_type proto; };static inline void *get_queue_entry (void *qbuf,u32 idx,u32 depth,u32 shift)
drivers/infiniband/hw/erdma/erdma_hw.h +7 -0
@@ -21,8 +21,15 @@#define ERDMA_NUM_MSIX_VEC 32U#define ERDMA_MSIX_VECTOR_CMDQ 0 +/* erdma device protocol type */ +enum erdma_proto_type { +ERDMA_PROTO_IWARP =0 , +ERDMA_PROTO_ROCEV2 =1 , +}; +/* PCIe Bar0 Registers. */ #define ERDMA_REGS_VERSION_REG 0x0 +#define ERDMA_REGS_DEV_PROTO_REG 0xC#define ERDMA_REGS_DEV_CTRL_REG 0x10#define ERDMA_REGS_DEV_ST_REG 0x14#define ERDMA_REGS_NETDEV_MAC_L_REG 0x18
drivers/infiniband/hw/erdma/erdma_main.c +25 -9
@@ -172,6 +172,8 @@ static int erdma_device_init(struct erdma_dev *dev, struct pci_dev *pdev) {int ret; + dev->proto =erdma_reg_read32 (dev,ERDMA_REGS_DEV_PROTO_REG ); + dev->resp_pool =dma_pool_create ("erdma_resp_pool" , &pdev->dev,ERDMA_HW_RESP_SIZE ,ERDMA_HW_RESP_SIZE ,0 );
@@ -474,6 +476,21 @@ static void erdma_res_cb_free(struct erdma_dev *dev)bitmap_free (dev->res_cb[i].bitmap); } +static const struct ib_device_ops erdma_device_ops_rocev2 = { + .get_link_layer = erdma_get_link_layer, +}; + +static const struct ib_device_ops erdma_device_ops_iwarp = { + .iw_accept = erdma_accept, + .iw_add_ref = erdma_qp_get_ref, + .iw_connect = erdma_connect, + .iw_create_listen = erdma_create_listen, + .iw_destroy_listen = erdma_destroy_listen, + .iw_get_qp = erdma_get_ibqp, + .iw_reject = erdma_reject, + .iw_rem_ref = erdma_qp_put_ref, +}; +static const struct ib_device_ops erdma_device_ops = { .owner =THIS_MODULE , .driver_id =RDMA_DRIVER_ERDMA ,
@@ -494,14 +511,6 @@ static const struct ib_device_ops erdma_device_ops = { .get_dma_mr = erdma_get_dma_mr, .get_hw_stats = erdma_get_hw_stats, .get_port_immutable = erdma_get_port_immutable, - .iw_accept = erdma_accept, - .iw_add_ref = erdma_qp_get_ref, - .iw_connect = erdma_connect, - .iw_create_listen = erdma_create_listen, - .iw_destroy_listen = erdma_destroy_listen, - .iw_get_qp = erdma_get_ibqp, - .iw_reject = erdma_reject, - .iw_rem_ref = erdma_qp_put_ref, .map_mr_sg = erdma_map_mr_sg, .mmap = erdma_mmap, .mmap_free = erdma_mmap_free,
@@ -537,7 +546,14 @@ static int erdma_ib_device_add(struct pci_dev *pdev)if (ret)return ret; - ibdev->node_type =RDMA_NODE_RNIC ; +if (erdma_device_iwarp (dev)) { + ibdev->node_type =RDMA_NODE_RNIC ; +ib_set_device_ops (ibdev, &erdma_device_ops_iwarp); + }else { + ibdev->node_type =RDMA_NODE_IB_CA ; +ib_set_device_ops (ibdev, &erdma_device_ops_rocev2); + } +memcpy (ibdev->node_desc,ERDMA_NODE_DESC ,sizeof (ERDMA_NODE_DESC ));/*
drivers/infiniband/hw/erdma/erdma_verbs.c +15 -1
@@ -395,8 +395,17 @@ int erdma_query_port(struct ib_device *ibdev, u32 port,int erdma_get_port_immutable (struct ib_device *ibdev,u32 port,struct ib_port_immutable *port_immutable) { +struct erdma_dev *dev =to_edev (ibdev); + +if (erdma_device_iwarp (dev)) { + port_immutable->core_cap_flags =RDMA_CORE_PORT_IWARP ; + }else { + port_immutable->core_cap_flags = +RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP ; + port_immutable->max_mad_size =IB_MGMT_MAD_SIZE ; + } + port_immutable->gid_tbl_len =1 ; - port_immutable->core_cap_flags =RDMA_CORE_PORT_IWARP ;return 0 ; }
@@ -1842,3 +1851,8 @@ int erdma_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,return stats->num_counters; } + +enum rdma_link_layer erdma_get_link_layer (struct ib_device *ibdev,u32 port_num) +{ +return IB_LINK_LAYER_ETHERNET ; +}
drivers/infiniband/hw/erdma/erdma_verbs.h +12 -0
@@ -291,6 +291,16 @@ int erdma_modify_qp_internal(struct erdma_qp *qp, struct erdma_qp_attrs *attrs,void erdma_qp_llp_close (struct erdma_qp *qp);void erdma_qp_cm_drop (struct erdma_qp *qp); +static inline bool erdma_device_iwarp (struct erdma_dev *dev) +{ +return dev->proto ==ERDMA_PROTO_IWARP ; +} + +static inline bool erdma_device_rocev2 (struct erdma_dev *dev) +{ +return dev->proto ==ERDMA_PROTO_ROCEV2 ; +} +static inline struct erdma_ucontext *to_ectx (struct ib_ucontext *ibctx) { return container_of(ibctx, struct erdma_ucontext, ibucontext);
@@ -370,5 +380,7 @@ struct rdma_hw_stats *erdma_alloc_hw_port_stats(struct ib_device *device, u32 port_num);int erdma_get_hw_stats (struct ib_device *ibdev,struct rdma_hw_stats *stats,u32 port,int index); +enum rdma_link_layer erdma_get_link_layer (struct ib_device *ibdev, +u32 port_num);#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1376 RDMA/erdma: Add GID table management interfaces
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 6edc15abc256f676ae44ac2ddc914567859bd1a7 ]
The erdma_add_gid() interface inserts a GID entry at the specified index. The erdma_del_gid() interface deletes the GID entry at the specified index. Additionally, programs can invoke the erdma_query_port() and erdma_get_port_immutable() interfaces to query the GID table length.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma.h | 1 + drivers/infiniband/hw/erdma/erdma_hw.h | 28 +++++++++++- drivers/infiniband/hw/erdma/erdma_main.c | 3 ++ drivers/infiniband/hw/erdma/erdma_verbs.c | 56 +++++++++++++++++++++-- drivers/infiniband/hw/erdma/erdma_verbs.h | 12 +++++ 5 files changed, 96 insertions(+), 4 deletions(-)
drivers/infiniband/hw/erdma/erdma.h +1 -0
@@ -148,6 +148,7 @@ struct erdma_devattr {u32 max_mr;u32 max_pd;u32 max_mw; +u32 max_gid;u32 local_dma_key; };
drivers/infiniband/hw/erdma/erdma_hw.h +27 -1
@@ -21,6 +21,9 @@#define ERDMA_NUM_MSIX_VEC 32U#define ERDMA_MSIX_VECTOR_CMDQ 0 +/* RoCEv2 related */ +#define ERDMA_ROCEV2_GID_SIZE 16 +/* erdma device protocol type */ enum erdma_proto_type {ERDMA_PROTO_IWARP =0 ,
@@ -143,7 +146,8 @@ enum CMDQ_RDMA_OPCODE {CMDQ_OPCODE_DESTROY_CQ =5 ,CMDQ_OPCODE_REFLUSH =6 ,CMDQ_OPCODE_REG_MR =8 , -CMDQ_OPCODE_DEREG_MR =9 +CMDQ_OPCODE_DEREG_MR =9 , + CMDQ_OPCODE_SET_GID = 14, }; enum CMDQ_COMMON_OPCODE {
@@ -401,7 +405,29 @@ struct erdma_cmdq_query_stats_resp {u64 rx_pps_meter_drop_packets_cnt; }; +enum erdma_network_type { +ERDMA_NETWORK_TYPE_IPV4 =0 , +ERDMA_NETWORK_TYPE_IPV6 =1 , +}; + +enum erdma_set_gid_op { +ERDMA_SET_GID_OP_ADD =0 , +ERDMA_SET_GID_OP_DEL =1 , +}; + +/* set gid cfg */ +#define ERDMA_CMD_SET_GID_SGID_IDX_MASK GENMASK(15, 0) +#define ERDMA_CMD_SET_GID_NTYPE_MASK BIT(16) +#define ERDMA_CMD_SET_GID_OP_MASK BIT(31) + +struct erdma_cmdq_set_gid_req { +u64 hdr; +u32 cfg; +u8 gid[ERDMA_ROCEV2_GID_SIZE ]; +}; +/* cap qword 0 definition */ +#define ERDMA_CMD_DEV_CAP_MAX_GID_MASK GENMASK_ULL(51, 48)#define ERDMA_CMD_DEV_CAP_MAX_CQE_MASK GENMASK_ULL(47, 40)#define ERDMA_CMD_DEV_CAP_FLAGS_MASK GENMASK_ULL(31, 24)#define ERDMA_CMD_DEV_CAP_MAX_RECV_WR_MASK GENMASK_ULL(23, 16)
drivers/infiniband/hw/erdma/erdma_main.c +3 -0
@@ -400,6 +400,7 @@ static int erdma_dev_attrs_init(struct erdma_dev *dev) dev->attrs.max_mr_size =1ULL <<ERDMA_GET_CAP (MAX_MR_SIZE , cap0); dev->attrs.max_mw =1 <<ERDMA_GET_CAP (MAX_MW , cap1); dev->attrs.max_recv_wr =1 <<ERDMA_GET_CAP (MAX_RECV_WR , cap0); + dev->attrs.max_gid =1 <<ERDMA_GET_CAP (MAX_GID , cap0); dev->attrs.local_dma_key =ERDMA_GET_CAP (DMA_LOCAL_KEY , cap1); dev->attrs.cc =ERDMA_GET_CAP (DEFAULT_CC , cap1); dev->attrs.max_qp =ERDMA_NQP_PER_QBLOCK *ERDMA_GET_CAP (QBLOCK , cap1);
@@ -478,6 +479,8 @@ static void erdma_res_cb_free(struct erdma_dev *dev)static const struct ib_device_ops erdma_device_ops_rocev2 = { .get_link_layer = erdma_get_link_layer, + .add_gid = erdma_add_gid, + .del_gid = erdma_del_gid, };static const struct ib_device_ops erdma_device_ops_iwarp = {
drivers/infiniband/hw/erdma/erdma_verbs.c +53 -3
77 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.h +12 -0
@@ -326,6 +326,16 @@ static inline struct erdma_cq *to_ecq(struct ib_cq *ibcq) return container_of(ibcq, struct erdma_cq, ibcq); } +static inline int erdma_check_gid_attr (const struct ib_gid_attr *attr) +{ +u8 ntype =rdma_gid_attr_network_type (attr); + +if (ntype !=RDMA_NETWORK_IPV4 && ntype !=RDMA_NETWORK_IPV6 ) +return -EINVAL ; + +return 0 ; +} +static inline struct erdma_user_mmap_entry *to_emmap (struct rdma_user_mmap_entry *ibmmap) {
@@ -382,5 +392,7 @@ int erdma_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats, u32 port, int index);enum rdma_link_layer erdma_get_link_layer (struct ib_device *ibdev,u32 port_num); +int erdma_add_gid (const struct ib_gid_attr *attr,void **context); +int erdma_del_gid (const struct ib_gid_attr *attr,void **context);#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1376 RDMA/erdma: Add the erdma_query_pkey() interface
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 14bcf7354a0ed2004da85b4b03afe44effd5e445 ]
The erdma_query_pkey() interface queries the PKey at the specified index. Currently, erdma supports only one partition and returns the default PKey for each query. Besides, the correct length of the PKey table can be obtained by calling the erdma_query_port() and erdma_get_port_immutable() interfaces.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma_hw.h | 2 ++ drivers/infiniband/hw/erdma/erdma_main.c | 1 + drivers/infiniband/hw/erdma/erdma_verbs.c | 14 ++++++++++++++ drivers/infiniband/hw/erdma/erdma_verbs.h | 1 + 4 files changed, 18 insertions(+)
drivers/infiniband/hw/erdma/erdma_hw.h +2 -0
@@ -23,6 +23,8 @@/* RoCEv2 related */ #define ERDMA_ROCEV2_GID_SIZE 16 +#define ERDMA_MAX_PKEYS 1 +#define ERDMA_DEFAULT_PKEY 0xFFFF/* erdma device protocol type */ enum erdma_proto_type {
drivers/infiniband/hw/erdma/erdma_main.c +1 -0
@@ -481,6 +481,7 @@ static const struct ib_device_ops erdma_device_ops_rocev2 = { .get_link_layer = erdma_get_link_layer, .add_gid = erdma_add_gid, .del_gid = erdma_del_gid, + .query_pkey = erdma_query_pkey, };static const struct ib_device_ops erdma_device_ops_iwarp = {
drivers/infiniband/hw/erdma/erdma_verbs.c +14 -0
@@ -336,6 +336,9 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, attr->max_fast_reg_page_list_len =ERDMA_MAX_FRMR_PA ; attr->page_size_cap =ERDMA_PAGE_SIZE_SUPPORT ; +if (erdma_device_rocev2 (dev)) + attr->max_pkeys =ERDMA_MAX_PKEYS ; +if (dev->attrs.cap_flags &ERDMA_DEV_CAP_FLAGS_ATOMIC ) attr->atomic_cap =IB_ATOMIC_GLOB ;
@@ -372,6 +375,7 @@ int erdma_query_port(struct ib_device *ibdev, u32 port, }else { attr->gid_tbl_len = dev->attrs.max_gid; attr->ip_gids = true; + attr->pkey_tbl_len =ERDMA_MAX_PKEYS ; } attr->port_cap_flags =IB_PORT_CM_SUP |IB_PORT_DEVICE_MGMT_SUP ;
@@ -411,6 +415,7 @@ int erdma_get_port_immutable(struct ib_device *ibdev, u32 port,RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP ; port_immutable->max_mad_size =IB_MGMT_MAD_SIZE ; port_immutable->gid_tbl_len = dev->attrs.max_gid; + port_immutable->pkey_tbl_len =ERDMA_MAX_PKEYS ; }return 0 ;
@@ -1906,3 +1911,12 @@ int erdma_del_gid(const struct ib_gid_attr *attr, void **context)return erdma_set_gid (to_edev (attr->device),ERDMA_SET_GID_OP_DEL , attr->index,NULL ); } + +int erdma_query_pkey (struct ib_device *ibdev,u32 port,u16 index,u16 *pkey) +{ +if (index >=ERDMA_MAX_PKEYS ) +return -EINVAL ; + + *pkey =ERDMA_DEFAULT_PKEY ; +return 0 ; +}
drivers/infiniband/hw/erdma/erdma_verbs.h +1 -0
@@ -394,5 +394,6 @@ enum rdma_link_layer erdma_get_link_layer(struct ib_device *ibdev, u32 port_num);int erdma_add_gid (const struct ib_gid_attr *attr,void **context);int erdma_del_gid (const struct ib_gid_attr *attr,void **context); +int erdma_query_pkey (struct ib_device *ibdev,u32 port,u16 index,u16 *pkey);#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1376 RDMA/erdma: Add address handle implementation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 41dcaf48ff9e31d1441b6a74ed488360aad096d4 ]
The address handle contains the necessary information to transmit messages to a remote peer in the RoCEv2 protocol. This commit implements the erdma_create_ah(), erdma_destroy_ah(), and erdma_query_ah() interfaces, which are used to create, destroy, and query an address handle, respectively.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma.h | 4 +- drivers/infiniband/hw/erdma/erdma_hw.h | 34 +++++++ drivers/infiniband/hw/erdma/erdma_main.c | 4 + drivers/infiniband/hw/erdma/erdma_verbs.c | 114 +++++++++++++++++++++- drivers/infiniband/hw/erdma/erdma_verbs.h | 28 ++++++ 5 files changed, 182 insertions(+), 2 deletions(-)
drivers/infiniband/hw/erdma/erdma.h +3 -1
@@ -149,6 +149,7 @@ struct erdma_devattr {u32 max_pd;u32 max_mw;u32 max_gid; +u32 max_ah;u32 local_dma_key; };
@@ -178,7 +179,8 @@ struct erdma_resource_cb {enum {ERDMA_RES_TYPE_PD =0 ,ERDMA_RES_TYPE_STAG_IDX =1 , -ERDMA_RES_CNT =2 , +ERDMA_RES_TYPE_AH =2 , +ERDMA_RES_CNT =3 , };struct erdma_dev {
drivers/infiniband/hw/erdma/erdma_hw.h +34 -0
@@ -9,6 +9,7 @@#include <linux/kernel.h> #include <linux/types.h> +#include <linux/if_ether.h> /* PCIe device related definition. */ #define ERDMA_PCI_WIDTH 64
@@ -150,6 +151,8 @@ enum CMDQ_RDMA_OPCODE {CMDQ_OPCODE_REG_MR =8 ,CMDQ_OPCODE_DEREG_MR =9 ,CMDQ_OPCODE_SET_GID =14 , +CMDQ_OPCODE_CREATE_AH =15 , + CMDQ_OPCODE_DESTROY_AH = 16, }; enum CMDQ_COMMON_OPCODE {
@@ -297,6 +300,36 @@ struct erdma_cmdq_dereg_mr_req {u32 cfg; }; +/* create_av cfg0 */ +#define ERDMA_CMD_CREATE_AV_FL_MASK GENMASK(19, 0) +#define ERDMA_CMD_CREATE_AV_NTYPE_MASK BIT(20) + +struct erdma_av_cfg { +u32 cfg0; +u8 traffic_class; +u8 hop_limit; +u8 sl; +u8 rsvd; +u16 udp_sport; +u16 sgid_index; +u8 dmac[ETH_ALEN ]; +u8 padding[2 ]; +u8 dgid[ERDMA_ROCEV2_GID_SIZE ]; +}; + +struct erdma_cmdq_create_ah_req { +u64 hdr; +u32 pdn; +u32 ahn; +struct erdma_av_cfg av_cfg; +}; + +struct erdma_cmdq_destroy_ah_req { +u64 hdr; +u32 pdn; +u32 ahn; +}; +/* modify qp cfg */ #define ERDMA_CMD_MODIFY_QP_STATE_MASK GENMASK(31, 24)#define ERDMA_CMD_MODIFY_QP_CC_MASK GENMASK(23, 20)
@@ -433,6 +466,7 @@ struct erdma_cmdq_set_gid_req {#define ERDMA_CMD_DEV_CAP_MAX_CQE_MASK GENMASK_ULL(47, 40)#define ERDMA_CMD_DEV_CAP_FLAGS_MASK GENMASK_ULL(31, 24)#define ERDMA_CMD_DEV_CAP_MAX_RECV_WR_MASK GENMASK_ULL(23, 16) +#define ERDMA_CMD_DEV_CAP_MAX_AH_MASK GENMASK_ULL(15, 8)#define ERDMA_CMD_DEV_CAP_MAX_MR_SIZE_MASK GENMASK_ULL(7, 0)/* cap qword 1 definition */
drivers/infiniband/hw/erdma/erdma_main.c +4 -0
@@ -401,6 +401,7 @@ static int erdma_dev_attrs_init(struct erdma_dev *dev) dev->attrs.max_mw =1 <<ERDMA_GET_CAP (MAX_MW , cap1); dev->attrs.max_recv_wr =1 <<ERDMA_GET_CAP (MAX_RECV_WR , cap0); dev->attrs.max_gid =1 <<ERDMA_GET_CAP (MAX_GID , cap0); + dev->attrs.max_ah =1 <<ERDMA_GET_CAP (MAX_AH , cap0); dev->attrs.local_dma_key =ERDMA_GET_CAP (DMA_LOCAL_KEY , cap1); dev->attrs.cc =ERDMA_GET_CAP (DEFAULT_CC , cap1); dev->attrs.max_qp =ERDMA_NQP_PER_QBLOCK *ERDMA_GET_CAP (QBLOCK , cap1);
@@ -418,6 +419,7 @@ static int erdma_dev_attrs_init(struct erdma_dev *dev) dev->res_cb[ERDMA_RES_TYPE_PD ].max_cap =ERDMA_MAX_PD ; dev->res_cb[ERDMA_RES_TYPE_STAG_IDX ].max_cap = dev->attrs.max_mr; + dev->res_cb[ERDMA_RES_TYPE_AH ].max_cap = dev->attrs.max_ah;erdma_cmdq_build_reqhdr (&req_hdr,CMDQ_SUBMOD_COMMON ,CMDQ_OPCODE_QUERY_FW_INFO );
@@ -482,6 +484,8 @@ static const struct ib_device_ops erdma_device_ops_rocev2 = { .add_gid = erdma_add_gid, .del_gid = erdma_del_gid, .query_pkey = erdma_query_pkey, + .create_ah = erdma_create_ah, + .destroy_ah = erdma_destroy_ah, };static const struct ib_device_ops erdma_device_ops_iwarp = {
drivers/infiniband/hw/erdma/erdma_verbs.c +113 -1
124 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.h +28 -0
@@ -136,6 +136,25 @@ struct erdma_user_dbrecords_page {int refcnt; }; +struct erdma_av { +u8 port; +u8 hop_limit; +u8 traffic_class; +u8 sl; +u8 sgid_index; +u16 udp_sport; +u32 flow_label; +u8 dmac[ETH_ALEN ]; +u8 dgid[ERDMA_ROCEV2_GID_SIZE ]; +enum erdma_network_type ntype; +}; + +struct erdma_ah { +struct ib_ah ibah; +struct erdma_av av; +u32 ahn; +}; +struct erdma_uqp {struct erdma_mem sq_mem;struct erdma_mem rq_mem;
@@ -326,6 +345,11 @@ static inline struct erdma_cq *to_ecq(struct ib_cq *ibcq) return container_of(ibcq, struct erdma_cq, ibcq); } +static inline struct erdma_ah *to_eah (struct ib_ah *ibah) +{ + return container_of(ibah, struct erdma_ah, ibah); +} +static inline int erdma_check_gid_attr (const struct ib_gid_attr *attr) {u8 ntype =rdma_gid_attr_network_type (attr);
@@ -395,5 +419,9 @@ enum rdma_link_layer erdma_get_link_layer(struct ib_device *ibdev,int erdma_add_gid (const struct ib_gid_attr *attr,void **context);int erdma_del_gid (const struct ib_gid_attr *attr,void **context);int erdma_query_pkey (struct ib_device *ibdev,u32 port,u16 index,u16 *pkey); +int erdma_create_ah (struct ib_ah *ibah,struct rdma_ah_init_attr *init_attr, +struct ib_udata *udata); +int erdma_destroy_ah (struct ib_ah *ibah,u32 flags); +int erdma_query_ah (struct ib_ah *ibah,struct rdma_ah_attr *ah_attr);#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1376 RDMA/erdma: Add erdma_modify_qp_rocev2() interface
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 9566cf6a7742f2e2bb8044b4624a7a1e66b6a549 ]
The QP state machines in the RoCEv2 and iWARP protocols are different. To handle these differences for the erdma RoCEv2 device, we provide the erdma_modify_qp_rocev2() interface, which transitions the QP state and modifies QP attributes accordingly.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma_cq.c | 45 +++++ drivers/infiniband/hw/erdma/erdma_hw.h | 14 ++ drivers/infiniband/hw/erdma/erdma_main.c | 3 +- drivers/infiniband/hw/erdma/erdma_qp.c | 92 +++++++++ drivers/infiniband/hw/erdma/erdma_verbs.c | 221 +++++++++++++++++++--- drivers/infiniband/hw/erdma/erdma_verbs.h | 44 +++++ 6 files changed, 388 insertions(+), 31 deletions(-)
drivers/infiniband/hw/erdma/erdma_cq.c +45 -0
@@ -201,3 +201,48 @@ int erdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)return npolled; } + +void erdma_remove_cqes_of_qp (struct ib_cq *ibcq,u32 qpn) +{ +struct erdma_cq *cq =to_ecq (ibcq); +struct erdma_cqe *cqe, *dst_cqe; +u32 prev_cq_ci, cur_cq_ci; +u32 ncqe =0 , nqp_cqe =0 ; +unsigned long flags; +u8 owner; + +spin_lock_irqsave (&cq->kern_cq.lock, flags); + + prev_cq_ci = cq->kern_cq.ci; + +while (ncqe < cq->depth && (cqe =get_next_valid_cqe (cq)) !=NULL ) { + ++cq->kern_cq.ci; + ++ncqe; + } + +while (ncqe >0 ) { + cur_cq_ci = prev_cq_ci + ncqe -1 ; + cqe =get_queue_entry (cq->kern_cq.qbuf, cur_cq_ci, cq->depth, +CQE_SHIFT ); + +if (be32_to_cpu (cqe->qpn) == qpn) { + ++nqp_cqe; + }else if (nqp_cqe) { + dst_cqe =get_queue_entry (cq->kern_cq.qbuf, + cur_cq_ci + nqp_cqe, + cq->depth,CQE_SHIFT ); + owner =FIELD_GET (ERDMA_CQE_HDR_OWNER_MASK , +be32_to_cpu (dst_cqe->hdr)); + cqe->hdr =cpu_to_be32 ( + (be32_to_cpu (cqe->hdr) & + ~ERDMA_CQE_HDR_OWNER_MASK ) | +FIELD_PREP (ERDMA_CQE_HDR_OWNER_MASK , owner)); +memcpy (dst_cqe, cqe,sizeof (*cqe)); + } + + --ncqe; + } + + cq->kern_cq.ci = prev_cq_ci + nqp_cqe; +spin_unlock_irqrestore (&cq->kern_cq.lock, flags); +}
drivers/infiniband/hw/erdma/erdma_hw.h +14 -0
@@ -347,6 +347,20 @@ struct erdma_cmdq_modify_qp_req {u32 recv_nxt; }; +/* modify qp cfg1 for roce device */ +#define ERDMA_CMD_MODIFY_QP_DQPN_MASK GENMASK(19, 0) + +struct erdma_cmdq_mod_qp_req_rocev2 { +u64 hdr; +u32 cfg0; +u32 cfg1; +u32 attr_mask; +u32 qkey; +u32 rq_psn; +u32 sq_psn; +struct erdma_av_cfg av_cfg; +}; +/* create qp cfg0 */ #define ERDMA_CMD_CREATE_QP_SQ_DEPTH_MASK GENMASK(31, 20)#define ERDMA_CMD_CREATE_QP_QPN_MASK GENMASK(19, 0)
drivers/infiniband/hw/erdma/erdma_main.c +2 -1
@@ -486,6 +486,7 @@ static const struct ib_device_ops erdma_device_ops_rocev2 = { .query_pkey = erdma_query_pkey, .create_ah = erdma_create_ah, .destroy_ah = erdma_destroy_ah, + .modify_qp = erdma_modify_qp_rocev2, };static const struct ib_device_ops erdma_device_ops_iwarp = {
@@ -497,6 +498,7 @@ static const struct ib_device_ops erdma_device_ops_iwarp = { .iw_get_qp = erdma_get_ibqp, .iw_reject = erdma_reject, .iw_rem_ref = erdma_qp_put_ref, + .modify_qp = erdma_modify_qp, };static const struct ib_device_ops erdma_device_ops = {
@@ -522,7 +524,6 @@ static const struct ib_device_ops erdma_device_ops = { .map_mr_sg = erdma_map_mr_sg, .mmap = erdma_mmap, .mmap_free = erdma_mmap_free, - .modify_qp = erdma_modify_qp, .post_recv = erdma_post_recv, .post_send = erdma_post_send, .poll_cq = erdma_poll_cq,
drivers/infiniband/hw/erdma/erdma_qp.c +92 -0
98 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.c +191 -30
274 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.h +44 -0
84 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1376 RDMA/erdma: Refactor the code of the modify_qp interface
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit de5b8008aa4da7e1e750cc780c086d45242ba51e ]
The procedure for modifying QP is similar for both the iWARP and RoCEv2 protocols. Therefore, we unify the code and provide the erdma_modify_qp() interface for both protocols.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma_cm.c | 71 ++++---- drivers/infiniband/hw/erdma/erdma_hw.h | 1 + drivers/infiniband/hw/erdma/erdma_main.c | 3 +- drivers/infiniband/hw/erdma/erdma_qp.c | 136 ++++++++------ drivers/infiniband/hw/erdma/erdma_verbs.c | 210 +++++++++++----------- drivers/infiniband/hw/erdma/erdma_verbs.h | 75 +++++--- 6 files changed, 276 insertions(+), 220 deletions(-)
drivers/infiniband/hw/erdma/erdma_cm.c +39 -32
@@ -567,7 +567,8 @@ static int erdma_proc_mpareq(struct erdma_cep *cep)static int erdma_proc_mpareply (struct erdma_cep *cep) { -struct erdma_qp_attrs qp_attrs; +enum erdma_qpa_mask_iwarp to_modify_attrs =0 ; +struct erdma_mod_qp_params_iwarp params;struct erdma_qp *qp = cep->qp;struct mpa_rr *rep;int ret;
@@ -597,26 +598,29 @@ static int erdma_proc_mpareply(struct erdma_cep *cep)return -EINVAL ; } -memset (&qp_attrs,0 ,sizeof (qp_attrs)); - qp_attrs.irq_size = cep->ird; - qp_attrs.orq_size = cep->ord; - qp_attrs.state =ERDMA_QP_STATE_RTS ; +memset (¶ms,0 ,sizeof (params)); + params.state =ERDMA_QPS_IWARP_RTS ; + params.irq_size = cep->ird; + params.orq_size = cep->ord;down_write (&qp->state_lock); -if (qp->attrs.state >ERDMA_QP_STATE_RTR ) { +if (qp->attrs.iwarp.state >ERDMA_QPS_IWARP_RTR ) { ret = -EINVAL ;up_write (&qp->state_lock); goto out_err; } - qp->attrs.qp_type =ERDMA_QP_ACTIVE ; -if (__mpa_ext_cc (cep->mpa.ext_data.bits) != qp->attrs.cc) - qp->attrs.cc =COMPROMISE_CC ; + to_modify_attrs =ERDMA_QPA_IWARP_STATE |ERDMA_QPA_IWARP_LLP_HANDLE | +ERDMA_QPA_IWARP_MPA |ERDMA_QPA_IWARP_IRD | +ERDMA_QPA_IWARP_ORD ; - ret =erdma_modify_qp_internal (qp, &qp_attrs, -ERDMA_QP_ATTR_STATE | -ERDMA_QP_ATTR_LLP_HANDLE | -ERDMA_QP_ATTR_MPA ); + params.qp_type =ERDMA_QP_ACTIVE ; +if (__mpa_ext_cc (cep->mpa.ext_data.bits) != qp->attrs.cc) { + to_modify_attrs |=ERDMA_QPA_IWARP_CC ; + params.cc =COMPROMISE_CC ; + } + + ret =erdma_modify_qp_state_iwarp (qp, ¶ms, to_modify_attrs);up_write (&qp->state_lock);
@@ -721,7 +725,7 @@ static int erdma_newconn_connected(struct erdma_cep *cep)__mpa_rr_set_revision (&cep->mpa.hdr.params.bits,MPA_REVISION_EXT_1 );memcpy (cep->mpa.hdr.key,MPA_KEY_REQ ,MPA_KEY_SIZE ); - cep->mpa.ext_data.cookie =cpu_to_be32 (cep->qp->attrs.cookie); + cep->mpa.ext_data.cookie =cpu_to_be32 (cep->qp->attrs.iwarp.cookie);__mpa_ext_set_cc (&cep->mpa.ext_data.bits, cep->qp->attrs.cc); ret =erdma_send_mpareqrep (cep, cep->private_data, cep->pd_len);
@@ -1125,10 +1129,11 @@ int erdma_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)int erdma_accept (struct iw_cm_id *id,struct iw_cm_conn_param *params) { -struct erdma_dev *dev =to_edev (id->device);struct erdma_cep *cep = (struct erdma_cep *)id->provider_data; +struct erdma_mod_qp_params_iwarp mod_qp_params; +enum erdma_qpa_mask_iwarp to_modify_attrs =0 ; +struct erdma_dev *dev =to_edev (id->device);struct erdma_qp *qp; -struct erdma_qp_attrs qp_attrs;int ret;erdma_cep_set_inuse (cep);
@@ -1155,7 +1160,7 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)erdma_qp_get (qp);down_write (&qp->state_lock); -if (qp->attrs.state >ERDMA_QP_STATE_RTR ) { +if (qp->attrs.iwarp.state >ERDMA_QPS_IWARP_RTR ) { ret = -EINVAL ;up_write (&qp->state_lock); goto error;
@@ -1180,11 +1185,11 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->cm_id = id; id->add_ref (id); -memset (&qp_attrs,0 ,sizeof (qp_attrs)); - qp_attrs.orq_size = params->ord; - qp_attrs.irq_size = params->ird; +memset (&mod_qp_params,0 ,sizeof (mod_qp_params)); - qp_attrs.state =ERDMA_QP_STATE_RTS ; + mod_qp_params.irq_size = params->ird; + mod_qp_params.orq_size = params->ord; + mod_qp_params.state =ERDMA_QPS_IWARP_RTS ;/* Associate QP with CEP */ erdma_cep_get (cep);
@@ -1193,19 +1198,21 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state =ERDMA_EPSTATE_RDMA_MODE ; - qp->attrs.qp_type =ERDMA_QP_PASSIVE ; - qp->attrs.pd_len = params->private_data_len; + mod_qp_params.qp_type =ERDMA_QP_PASSIVE ; + mod_qp_params.pd_len = params->private_data_len; -if (qp->attrs.cc !=__mpa_ext_cc (cep->mpa.ext_data.bits)) - qp->attrs.cc =COMPROMISE_CC ; + to_modify_attrs =ERDMA_QPA_IWARP_STATE |ERDMA_QPA_IWARP_ORD | +ERDMA_QPA_IWARP_LLP_HANDLE |ERDMA_QPA_IWARP_IRD | +ERDMA_QPA_IWARP_MPA ; + +if (qp->attrs.cc !=__mpa_ext_cc (cep->mpa.ext_data.bits)) { + to_modify_attrs |=ERDMA_QPA_IWARP_CC ; + mod_qp_params.cc =COMPROMISE_CC ; + }/* move to rts */ - ret =erdma_modify_qp_internal (qp, &qp_attrs, -ERDMA_QP_ATTR_STATE | -ERDMA_QP_ATTR_ORD | -ERDMA_QP_ATTR_LLP_HANDLE | -ERDMA_QP_ATTR_IRD | -ERDMA_QP_ATTR_MPA ); + ret =erdma_modify_qp_state_iwarp (qp, &mod_qp_params, to_modify_attrs); +up_write (&qp->state_lock);if (ret)
@@ -1213,7 +1220,7 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->mpa.ext_data.bits =0 ;__mpa_ext_set_cc (&cep->mpa.ext_data.bits, qp->attrs.cc); - cep->mpa.ext_data.cookie =cpu_to_be32 (cep->qp->attrs.cookie); + cep->mpa.ext_data.cookie =cpu_to_be32 (cep->qp->attrs.iwarp.cookie); ret =erdma_send_mpareqrep (cep, params->private_data, params->private_data_len);
drivers/infiniband/hw/erdma/erdma_hw.h +1 -0
@@ -31,6 +31,7 @@enum erdma_proto_type {ERDMA_PROTO_IWARP =0 ,ERDMA_PROTO_ROCEV2 =1 , +ERDMA_PROTO_COUNT =2 , };/* PCIe Bar0 Registers. */
drivers/infiniband/hw/erdma/erdma_main.c +1 -2
@@ -486,7 +486,6 @@ static const struct ib_device_ops erdma_device_ops_rocev2 = { .query_pkey = erdma_query_pkey, .create_ah = erdma_create_ah, .destroy_ah = erdma_destroy_ah, - .modify_qp = erdma_modify_qp_rocev2, };static const struct ib_device_ops erdma_device_ops_iwarp = {
@@ -498,7 +497,6 @@ static const struct ib_device_ops erdma_device_ops_iwarp = { .iw_get_qp = erdma_get_ibqp, .iw_reject = erdma_reject, .iw_rem_ref = erdma_qp_put_ref, - .modify_qp = erdma_modify_qp, };static const struct ib_device_ops erdma_device_ops = {
@@ -533,6 +531,7 @@ static const struct ib_device_ops erdma_device_ops = { .query_qp = erdma_query_qp, .req_notify_cq = erdma_req_notify_cq, .reg_user_mr = erdma_reg_user_mr, + .modify_qp = erdma_modify_qp,INIT_RDMA_OBJ_SIZE (ib_cq, erdma_cq, ibcq), INIT_RDMA_OBJ_SIZE(ib_pd, erdma_pd, ibpd),
drivers/infiniband/hw/erdma/erdma_qp.c +80 -56
220 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.c +108 -102
292 lines not on this page · raw message
drivers/infiniband/hw/erdma/erdma_verbs.h +47 -28
119 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1376 RDMA/erdma: Add the query_qp command to the cmdq
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 1cccbd3eec3d6370ddf9a003c1a1baeb8c155b3b ]
Certian QP attributes, such as sq_draining, can only be obtained by querying the hardware on the erdma RoCEv2 device. To address this, we add the query_qp command to the cmdq and parse the response to retrieve corresponding QP attributes.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma_hw.h | 12 +++++ drivers/infiniband/hw/erdma/erdma_verbs.c | 58 +++++++++++++++++++---- 2 files changed, 60 insertions(+), 10 deletions(-)
drivers/infiniband/hw/erdma/erdma_hw.h +12 -0
@@ -154,6 +154,7 @@ enum CMDQ_RDMA_OPCODE {CMDQ_OPCODE_SET_GID =14 ,CMDQ_OPCODE_CREATE_AH =15 ,CMDQ_OPCODE_DESTROY_AH =16 , + CMDQ_OPCODE_QUERY_QP = 17, }; enum CMDQ_COMMON_OPCODE {
@@ -362,6 +363,17 @@ struct erdma_cmdq_mod_qp_req_rocev2 {struct erdma_av_cfg av_cfg; }; +/* query qp response mask */ +#define ERDMA_CMD_QUERY_QP_RESP_SQ_PSN_MASK GENMASK_ULL(23, 0) +#define ERDMA_CMD_QUERY_QP_RESP_RQ_PSN_MASK GENMASK_ULL(47, 24) +#define ERDMA_CMD_QUERY_QP_RESP_QP_STATE_MASK GENMASK_ULL(55, 48) +#define ERDMA_CMD_QUERY_QP_RESP_SQ_DRAINING_MASK GENMASK_ULL(56, 56) + +struct erdma_cmdq_query_qp_req_rocev2 { +u64 hdr; +u32 qpn; +}; +/* create qp cfg0 */ #define ERDMA_CMD_CREATE_QP_SQ_DEPTH_MASK GENMASK(31, 20)#define ERDMA_CMD_CREATE_QP_QPN_MASK GENMASK(19, 0)
drivers/infiniband/hw/erdma/erdma_verbs.c +48 -10
84 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1376 RDMA/erdma: Fix incorrect response returned from query_qp
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 3761e0ad79c137d61baf5f1518e4795f35fe8159 ]
The erdma_post_cmd_wait() function returns the cmdq response only when both resp0 and resp1 are not NULL.
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma_verbs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/infiniband/hw/erdma/erdma_verbs.c +8 -8
@@ -1783,7 +1783,7 @@ int erdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,struct erdma_cmdq_query_qp_req_rocev2 req;struct erdma_dev *dev;struct erdma_qp *qp; -u64 resp; +u64 resp0, resp1;int ret;if (ibqp && qp_attr && qp_init_attr) {
@@ -1817,20 +1817,20 @@ int erdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, CMDQ_OPCODE_QUERY_QP); req.qpn =QP_ID (qp); - ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req), &resp, -NULL ); + ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req), &resp0, + &resp1);if (ret)return ret; qp_attr->sq_psn = -FIELD_GET (ERDMA_CMD_QUERY_QP_RESP_SQ_PSN_MASK , resp); +FIELD_GET (ERDMA_CMD_QUERY_QP_RESP_SQ_PSN_MASK , resp0); qp_attr->rq_psn = -FIELD_GET (ERDMA_CMD_QUERY_QP_RESP_RQ_PSN_MASK , resp); - qp_attr->qp_state =rocev2_to_ib_qps ( -FIELD_GET (ERDMA_CMD_QUERY_QP_RESP_QP_STATE_MASK , resp)); +FIELD_GET (ERDMA_CMD_QUERY_QP_RESP_RQ_PSN_MASK , resp0); + qp_attr->qp_state =rocev2_to_ib_qps (FIELD_GET ( +ERDMA_CMD_QUERY_QP_RESP_QP_STATE_MASK , resp0)); qp_attr->cur_qp_state = qp_attr->qp_state; qp_attr->sq_draining =FIELD_GET ( -ERDMA_CMD_QUERY_QP_RESP_SQ_DRAINING_MASK , resp); +ERDMA_CMD_QUERY_QP_RESP_SQ_DRAINING_MASK , resp0); qp_attr->pkey_index =0 ; qp_attr->dest_qp_num = qp->attrs.rocev2.dst_qpn;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1376 RDMA/erdma: Support non-sleeping erdma_post_cmd_wait()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boshi Yu <[email protected]>
[ Upstream commit 26981e688ca896e9310e1918d104a79cb140ce85 ]
Several scenarios require posting commands to the cmdq in a non-sleepable context. For example, the cm_alloc_msg() might call erdma_create_ah() while still holding a spinlock. So we add support for non-sleeping erdma_post_cmd_wait().
Stable-dep-of: 652befcba956 ("RDMA/erdma: complete object teardown when the destroy command fails")
--- drivers/infiniband/hw/erdma/erdma.h | 4 +-- drivers/infiniband/hw/erdma/erdma_cmdq.c | 26 +++++++------- drivers/infiniband/hw/erdma/erdma_eq.c | 6 ++-- drivers/infiniband/hw/erdma/erdma_main.c | 7 ++-- drivers/infiniband/hw/erdma/erdma_qp.c | 8 +++-- drivers/infiniband/hw/erdma/erdma_verbs.c | 44 ++++++++++++++--------- 6 files changed, 54 insertions(+), 41 deletions(-)
drivers/infiniband/hw/erdma/erdma.h +1 -3
@@ -101,8 +101,6 @@ struct erdma_cmdq {struct erdma_comp_wait *wait_pool;spinlock_t lock; -bool use_event; -struct erdma_cmdq_sq sq;struct erdma_cmdq_cq cq;struct erdma_eq eq;
@@ -269,7 +267,7 @@ void erdma_cmdq_destroy(struct erdma_dev *dev);void erdma_cmdq_build_reqhdr (u64 *hdr,u32 mod,u32 op);int erdma_post_cmd_wait (struct erdma_cmdq *cmdq,void *req,u32 req_size, -u64 *resp0,u64 *resp1); +u64 *resp0,u64 *resp1,bool sleepable);void erdma_cmdq_completion_handler (struct erdma_cmdq *cmdq);int erdma_ceqs_init (struct erdma_dev *dev);
drivers/infiniband/hw/erdma/erdma_cmdq.c +12 -14
@@ -182,7 +182,6 @@ int erdma_cmdq_init(struct erdma_dev *dev)int err; cmdq->max_outstandings =ERDMA_CMDQ_MAX_OUTSTANDING ; - cmdq->use_event = false;sema_init (&cmdq->credits, cmdq->max_outstandings);
@@ -223,8 +222,6 @@ int erdma_cmdq_init(struct erdma_dev *dev)void erdma_finish_cmdq_init (struct erdma_dev *dev) { -/* after device init successfully, change cmdq to event mode. */ - dev->cmdq.use_event = true;arm_cmdq_cq (&dev->cmdq); }
@@ -312,8 +309,7 @@ static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq)/* Copy 16B comp data after cqe hdr to outer */ be32_to_cpu_array (comp_wait->comp_data, cqe +2 ,4 ); -if (cmdq->use_event) -complete (&comp_wait->wait_event); +complete (&comp_wait->wait_event);return 0 ; }
@@ -332,9 +328,6 @@ static void erdma_polling_cmd_completions(struct erdma_cmdq *cmdq)if (erdma_poll_single_cmd_completion (cmdq))break ; -if (comp_num && cmdq->use_event) -arm_cmdq_cq (cmdq); -spin_unlock_irqrestore (&cmdq->cq.lock, flags); }
@@ -342,8 +335,7 @@ void erdma_cmdq_completion_handler(struct erdma_cmdq *cmdq) {int got_event =0 ; -if (!test_bit (ERDMA_CMDQ_STATE_OK_BIT , &cmdq->state) || - !cmdq->use_event) +if (!test_bit (ERDMA_CMDQ_STATE_OK_BIT , &cmdq->state))return ;while (get_next_valid_eqe (&cmdq->eq)) {
@@ -354,6 +346,7 @@ void erdma_cmdq_completion_handler(struct erdma_cmdq *cmdq)if (got_event) { cmdq->cq.cmdsn++;erdma_polling_cmd_completions (cmdq); +arm_cmdq_cq (cmdq); }notify_eq (&cmdq->eq);
@@ -372,7 +365,7 @@ static int erdma_poll_cmd_completion(struct erdma_comp_wait *comp_ctx,if (time_is_before_jiffies (comp_timeout))return -ETIME ; -msleep (20 ); +udelay (20 ); }return 0 ;
@@ -403,7 +396,7 @@ void erdma_cmdq_build_reqhdr(u64 *hdr, u32 mod, u32 op) }int erdma_post_cmd_wait (struct erdma_cmdq *cmdq,void *req,u32 req_size, -u64 *resp0,u64 *resp1) +u64 *resp0,u64 *resp1,bool sleepable) {struct erdma_comp_wait *comp_wait;int ret;
@@ -411,7 +404,12 @@ int erdma_post_cmd_wait(struct erdma_cmdq *cmdq, void *req, u32 req_size,if (!test_bit (ERDMA_CMDQ_STATE_OK_BIT , &cmdq->state))return -ENODEV ; -down (&cmdq->credits); +if (!sleepable) { +while (down_trylock (&cmdq->credits)) + ; + }else { +down (&cmdq->credits); + } comp_wait =get_comp_wait (cmdq);if (IS_ERR (comp_wait)) {
@@ -425,7 +423,7 @@ int erdma_post_cmd_wait(struct erdma_cmdq *cmdq, void *req, u32 req_size,push_cmdq_sqe (cmdq, req, req_size, comp_wait);spin_unlock (&cmdq->sq.lock); -if (cmdq->use_event) +if (sleepable) ret =erdma_wait_cmd_completion (comp_wait, cmdq,ERDMA_CMDQ_TIMEOUT_MS );else
drivers/infiniband/hw/erdma/erdma_eq.c +4 -2
@@ -237,7 +237,8 @@ static int create_eq_cmd(struct erdma_dev *dev, u32 eqn, struct erdma_eq *eq) req.db_dma_addr_l =lower_32_bits (eq->dbrec_dma); req.db_dma_addr_h =upper_32_bits (eq->dbrec_dma); -return erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL ); +return erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , + false); }static int erdma_ceq_init_one (struct erdma_dev *dev,u16 ceqn)
@@ -279,7 +280,8 @@ static void erdma_ceq_uninit_one(struct erdma_dev *dev, u16 ceqn) req.qtype =ERDMA_EQ_TYPE_CEQ ; req.vector_idx = ceqn +1 ; - err =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL ); + err =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , + false);if (err)return ;
drivers/infiniband/hw/erdma/erdma_main.c +4 -3
@@ -392,7 +392,7 @@ static int erdma_dev_attrs_init(struct erdma_dev *dev) CMDQ_OPCODE_QUERY_DEVICE); err =erdma_post_cmd_wait (&dev->cmdq, &req_hdr,sizeof (req_hdr), &cap0, - &cap1); + &cap1, true);if (err)return err;
@@ -425,7 +425,7 @@ static int erdma_dev_attrs_init(struct erdma_dev *dev) CMDQ_OPCODE_QUERY_FW_INFO); err =erdma_post_cmd_wait (&dev->cmdq, &req_hdr,sizeof (req_hdr), &cap0, - &cap1); + &cap1, true);if (!err) dev->attrs.fw_version =FIELD_GET (ERDMA_CMD_INFO0_FW_VER_MASK , cap0);
@@ -446,7 +446,8 @@ static int erdma_device_config(struct erdma_dev *dev) req.cfg =FIELD_PREP (ERDMA_CMD_CONFIG_DEVICE_PGSHIFT_MASK ,PAGE_SHIFT ) |FIELD_PREP (ERDMA_CMD_CONFIG_DEVICE_PS_EN_MASK ,1 ); -return erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL ); +return erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , + true); }static int erdma_res_cb_init (struct erdma_dev *dev)
drivers/infiniband/hw/erdma/erdma_qp.c +5 -3
@@ -98,7 +98,8 @@ erdma_modify_qp_state_to_rts(struct erdma_qp *qp, req.send_nxt +=MPA_DEFAULT_HDR_LEN + params->pd_len; req.recv_nxt = tp->rcv_nxt; - ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL ); + ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , + true);if (ret)return ret;
@@ -131,7 +132,8 @@ erdma_modify_qp_state_to_stop(struct erdma_qp *qp, req.cfg =FIELD_PREP (ERDMA_CMD_MODIFY_QP_STATE_MASK , params->state) |FIELD_PREP (ERDMA_CMD_MODIFY_QP_QPN_MASK ,QP_ID (qp)); - ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL ); + ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , + true);if (ret)return ret;
@@ -246,7 +248,7 @@ static int modify_qp_cmd_rocev2(struct erdma_qp *qp, req.attr_mask = attr_mask;return erdma_post_cmd_wait (&qp->dev->cmdq, &req,sizeof (req),NULL , -NULL ); +NULL , true); }static void erdma_reset_qp (struct erdma_qp *qp)
drivers/infiniband/hw/erdma/erdma_verbs.c +28 -16
134 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1376 RDMA/erdma: complete object teardown when the destroy command fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 652befcba956ef357f480525ccbe25c59bc81d4d ]
erdma_destroy_qp(), erdma_destroy_cq(), erdma_dereg_mr(), and erdma_destroy_ah() returned early when erdma_post_cmd_wait() failed, leaking the queue buffers, MTTs, doorbells and the STAG, QPN, CQN and AHN identifiers. A command timeout clears ERDMA_CMDQ_STATE_OK_BIT and permanently disables the command queue, so no retry can succeed; the RDMA core keeps the object after a failed destructor and forced uverbs cleanup then nulls the pointers, making the resources unreachable.
Warn on failure but release every software-owned resource and return success, since during terminal destruction the hardware command result is only diagnostic.
--- drivers/infiniband/hw/erdma/erdma_verbs.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/infiniband/hw/erdma/erdma_verbs.c +17 -4
@@ -1254,8 +1254,15 @@ int erdma_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , true); +/* +* A timeout disables the command queue, so retry cannot succeed. Treat +* terminal command failures as diagnostic; propagating them can make +* forced uverbs cleanup discard the last software resource pointers. +*/ if (ret) -return ret; +ibdev_warn_ratelimited (&dev->ibdev, +"failed to deregister MR 0x%x: %d\n" , + ibmr->lkey, ret);erdma_free_idx (&dev->res_cb[ERDMA_RES_TYPE_STAG_IDX ], ibmr->lkey >>8 );
@@ -1281,7 +1288,9 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) err =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , true);if (err) -return err; +ibdev_warn_ratelimited (&dev->ibdev, +"failed to destroy CQ %u: %d\n" , + cq->cqn, err);if (rdma_is_kernel_res (&cq->ibcq.res)) { dma_free_coherent(&dev->pdev->dev, cq->depth << CQE_SHIFT,
@@ -1329,7 +1338,9 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) err =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , true);if (err) -return err; +ibdev_warn_ratelimited (&dev->ibdev, +"failed to destroy QP %u: %d\n" , +QP_ID (qp), err);erdma_qp_put (qp);wait_for_completion (&qp->safe_free);
@@ -2233,7 +2244,9 @@ int erdma_destroy_ah(struct ib_ah *ibah, u32 flags) ret =erdma_post_cmd_wait (&dev->cmdq, &req,sizeof (req),NULL ,NULL , true);if (ret) -return ret; +ibdev_warn_ratelimited (&dev->ibdev, +"failed to destroy AH %u: %d\n" , + ah->ahn, ret);erdma_free_idx (&dev->res_cb[ERDMA_RES_TYPE_AH ], ah->ahn);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1376 PM: hibernate: Fix memory leak in snapshot_write_next() error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Malaya Kumar Rout <[email protected]>
[ Upstream commit 21d5c4cee31c5ce78f6decc7fafc7e7759af391f ]
When memory_bm_create() succeeds for copy_bm but fails for zero_bm, the function returns without freeing the resources allocated for copy_bm. This results in a memory leak that includes radix tree nodes, zone structures, and page lists.
Fix this by calling memory_bm_free() to release copy_bm's resources before returning the error code when zero_bm allocation fails.
--- kernel/power/snapshot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/power/snapshot.c +3 -2
@@ -2803,9 +2803,10 @@ int snapshot_write_next(struct snapshot_handle *handle)return error; error =memory_bm_create (&zero_bm,GFP_ATOMIC ,PG_ANY ); -if (error) +if (error) { +memory_bm_free (©_bm,PG_UNSAFE_CLEAR );return error; - + } nr_zero_pages =0 ;hibernate_restore_protection_begin ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1376 leds: pca9532: Fix phantom device registration on missing hardware
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmo Chou <[email protected]>
[ Upstream commit 8d6b6c05b8e33d11e3fb3203309385e1a9cceecd ]
The initial PWM and PSC register writes in pca9532_configure() do not check the return values of i2c_smbus_write_byte_data(). If the I2C device is physically absent from the bus, the write fails with -ENXIO. However, the driver ignores this error and allows probe() to complete successfully.
This results in the registration of phantom LED class devices and gpiochips backed by non-existent hardware. Subsequent GPIO reads from these phantom chips return bogus values (due to -ENXIO being truncated to an unsigned char in pca9532_gpio_get_value()), silently corrupting hardware state tracking in userspace.
Propagate the I2C write failures back to probe() so the driver core can gracefully abort binding and release devres-managed resources.
--- drivers/leds/leds-pca9532.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/leds/leds-pca9532.c +8 -4
@@ -394,10 +394,14 @@ static int pca9532_configure(struct i2c_client *client,for (i =0 ; i <2 ; i++) { data->pwm[i] = pdata->pwm[i]; data->psc[i] = pdata->psc[i]; -i2c_smbus_write_byte_data (client,PCA9532_REG_PWM (maxleds, i), - data->pwm[i]); -i2c_smbus_write_byte_data (client,PCA9532_REG_PSC (maxleds, i), - data->psc[i]); + err =i2c_smbus_write_byte_data (client,PCA9532_REG_PWM (maxleds, i), + data->pwm[i]); +if (err <0 ) +return err; + err =i2c_smbus_write_byte_data (client,PCA9532_REG_PSC (maxleds, i), + data->psc[i]); +if (err <0 ) +return err; } data->hw_blink = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1376 drm/tve200: add OF module alias for autoloading
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
[ Upstream commit b6c3585f2058e0fbfa8cb403458f5cc6cf5c5e06 ]
The TVE200 DRM driver can be built as a module and uses tve200_of_match as its OF match table, but the table is not exported for module alias generation.
Add the MODULE_DEVICE_TABLE(of, ...) entry so modpost can generate OF module aliases for OF based module autoloading.
--- drivers/gpu/drm/tve200/tve200_drv.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/tve200/tve200_drv.c +1 -0
@@ -261,6 +261,7 @@ static const struct of_device_id tve200_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE (of, tve200_of_match);static struct platform_driver tve200_driver = { .driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1376 netfilter: nf_nat_sip: rewind offset when NAT shrinks the packet
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 16aecbe3036f6097c26b51b12e4c1cf207769690 ]
sashiko says:
If map_addr() changes the packet length, such as when the public NAT IP string is shorter or longer than the internal IP, coff will still point to the offset relative to the pre-mangled packet.
If the packet shrinks, coff could overshoot the correct position, potentially causing the next ct_sip_parse_header_uri() call to silently skip bytes and miss subsequent Contact headers. Could this lead to a failure to NAT those subsequent headers and leak internal network details?
--- net/netfilter/nf_nat_sip.c | 5 +++++ 1 file changed, 5 insertions(+)
net/netfilter/nf_nat_sip.c +5 -0
@@ -267,12 +267,17 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, SIP_HDR_CONTACT, &in_header, &matchoff, &matchlen, &addr, &port) > 0) { +int old_len = skb->len, delta; +if (!map_addr (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) {nf_ct_helper_log (skb, ct,"cannot mangle contact" );return NF_DROP ; } + + delta = (int )skb->len - old_len; + coff += delta; } if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1376 fs/ntfs3: fix out-of-bounds read of INDEX_ROOT in reparse/objid init
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Wu <[email protected]>
[ Upstream commit 2064bc663f89e61b8681c1fb9d1ce445de72063d ]
ntfs_reparse_init() and ntfs_objid_init() parse the index root of the $Extend/$Reparse and $Extend/$ObjId metafiles (the INDEX_ROOT attributes named $R and $O). They read its type and rule fields through resident_data(), which does not check that the resident attribute is large enough to hold them.
mi_enum_attr() accepts a resident attribute with data_off == asize and data_size == 0. For such an attribute placed last in its MFT record, resident_data() returns a pointer to the end of the record_size buffer, so reading root->type / root->rule reads past the allocation.
Use resident_data_ex(attr, sizeof(struct INDEX_ROOT)) and bail out when it returns NULL, as ntfs_security_init() already does for $SDH / $SII.
The attribute is only parsed while mounting a crafted image, so this needs CAP_SYS_ADMIN.
BUG: KASAN: slab-out-of-bounds in ntfs_reparse_init (fs/ntfs3/fsntfs.c:2306) Read of size 4 at addr ffff88801219dc00 by task mount ntfs_reparse_init (fs/ntfs3/fsntfs.c:2306) ntfs_fill_super (fs/ntfs3/super.c:1604) get_tree_bdev_flags (fs/super.c:1703) vfs_get_tree (fs/super.c:1758) path_mount (fs/namespace.c:4131) __x64_sys_mount (fs/namespace.c:4360)
--- fs/ntfs3/fsntfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/ntfs3/fsntfs.c +4 -4
@@ -2317,8 +2317,8 @@ int ntfs_reparse_init(struct ntfs_sb_info *sbi) goto out; } - root_r =resident_data (attr); -if (root_r->type !=ATTR_ZERO || + root_r =resident_data_ex (attr,sizeof (struct INDEX_ROOT )); +if (!root_r || root_r->type !=ATTR_ZERO || root_r->rule !=NTFS_COLLATION_TYPE_UINTS ) { err = -EINVAL ; goto out;
@@ -2355,8 +2355,8 @@ int ntfs_objid_init(struct ntfs_sb_info *sbi) goto out; } - root =resident_data (attr); -if (root->type !=ATTR_ZERO || + root =resident_data_ex (attr,sizeof (struct INDEX_ROOT )); +if (!root || root->type !=ATTR_ZERO || root->rule !=NTFS_COLLATION_TYPE_UINTS ) { err = -EINVAL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1376 drm/panthor: return PTR_ERR() from devm_drm_dev_alloc()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
[ Upstream commit abc1e559f8e5996eee506dfdc8e3781c2a1e04f9 ]
devm_drm_dev_alloc() returns an ERR_PTR() on failure, but panthor_probe() always converts that failure to -ENOMEM. Preserve the actual error code returned by the DRM core instead.
--- drivers/gpu/drm/panthor/panthor_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/panthor/panthor_drv.c +1 -1
@@ -1427,7 +1427,7 @@ static int panthor_probe(struct platform_device *pdev) ptdev =devm_drm_dev_alloc (&pdev->dev, &panthor_drm_driver, struct panthor_device, base);if (IS_ERR (ptdev)) -return -ENOMEM ; +return PTR_ERR (ptdev);platform_set_drvdata (pdev, ptdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1376 arm64: dts: rockchip: Fix Gru WLAN sideband interrupt
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Estevam <[email protected]>
[ Upstream commit a761818d9ee11183df0aefd16bf9fe46cc1c4c6d ]
The Marvell WLAN host wake interrupt is wired to GPIO0 8 and is not one of the PCI INTx interrupts. The PCI device schema therefore interprets the two-cell GPIO interrupt specifier as an invalid PCI interrupt and reports dtbs_check warnings:
pcie@0,0: wifi@0,0:interrupts:0:0: 8 is not one of [1, 2, 3, 4] pcie@0,0: wifi@0,0:interrupts:0: [8, 8] is too long
Describe the sideband interrupt with interrupts-extended, which explicitly carries the interrupt controller and removes the ambiguity.
--- arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi +1 -2
@@ -510,8 +510,7 @@ &pci_rootport { mvl_wifi: wifi@0,0 { compatible = "pci1b4b,2b42"; reg = <0x0000 0x0 0x0 0x0 0x0>; - interrupt-parent = <&gpio0>; - interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio0 8 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&wlan_host_wake_l>; wakeup-source;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1376 ARM: lpc32xx: only run SoC init on LPC32xx hardware
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 717ea4000867e6dffee5e1ed92150a9704ae9f68 ]
lpc32xx_check_uid() and lpc32xx_pm_init() are arch_initcalls that poke LPC32xx-only registers. Since the multiplatform conversion they also run on other ARCH_MULTI_V5 boards where access faults e.g. on versatile:
Unable to handle kernel paging request at virtual address f4004130 PC is at lpc32xx_check_uid+0x2c/0x9c
Drop the arch_initcall() registrations and call both functions directly from lpc3250_machine_init(), the machine's .init_machine hook. The calls are placed in link order (common.c, pm.c, phy3250.c) to keep their previous relative ordering.
--- arch/arm/mach-lpc32xx/common.c | 5 +---- arch/arm/mach-lpc32xx/common.h | 2 ++ arch/arm/mach-lpc32xx/phy3250.c | 2 ++ arch/arm/mach-lpc32xx/pm.c | 5 +---- 4 files changed, 6 insertions(+), 8 deletions(-)
arch/arm/mach-lpc32xx/common.c +1 -4
@@ -106,7 +106,7 @@ void __init lpc32xx_map_io(void)iotable_init (lpc32xx_io_desc,ARRAY_SIZE (lpc32xx_io_desc)); } -static int __init lpc32xx_check_uid (void ) +void __init lpc32xx_check_uid (void ) {u32 uid[4 ];
@@ -119,7 +119,4 @@ static int __init lpc32xx_check_uid(void) system_serial_low = uid[0 ]; system_serial_high = uid[1 ]; } - -return 1 ; } -arch_initcall (lpc32xx_check_uid);
arch/arm/mach-lpc32xx/common.h +2 -0
@@ -16,6 +16,8 @@* Other arch specific structures and functions */ extern void __init lpc32xx_map_io (void ); +extern void __init lpc32xx_check_uid (void ); +extern void __init lpc32xx_pm_init (void );extern void __init lpc32xx_serial_init (void );/*
arch/arm/mach-lpc32xx/phy3250.c +2 -0
@@ -71,6 +71,8 @@ static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {static void __init lpc3250_machine_init (void ) { +lpc32xx_check_uid (); +lpc32xx_pm_init ();lpc32xx_serial_init ();of_platform_default_populate (NULL , lpc32xx_auxdata_lookup,NULL );
arch/arm/mach-lpc32xx/pm.c +1 -4
@@ -120,7 +120,7 @@ static const struct platform_suspend_ops lpc32xx_pm_ops = {#define EMC_DYN_MEM_CTRL_OFS 0x20#define EMC_SRMMC (1 << 3)#define EMC_CTRL_REG io_p2v(LPC32XX_EMC_BASE + EMC_DYN_MEM_CTRL_OFS) -static int __init lpc32xx_pm_init (void ) +void __init lpc32xx_pm_init (void ) {/* * Setup SDRAM self-refresh clock to automatically disable o
@@ -129,7 +129,4 @@ static int __init lpc32xx_pm_init(void)__raw_writel (__raw_readl (EMC_CTRL_REG ) |EMC_SRMMC ,EMC_CTRL_REG );suspend_set_ops (&lpc32xx_pm_ops); - -return 0 ; } -arch_initcall (lpc32xx_pm_init);
Signature · 1 line
2.53.0