6.6.157-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 984/1424 drm/msm/dsi: Drop dev_pm_opp_set_rate(0)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 06b7ba206561619bb34116f49e0ef26b867ce3aa ]
dev_pm_opp_set_rate(0) removes the vote specified in required-opps but does not actually park the clock, making it run without the necessary power backing. Drop the explicit call to it.
Every call site of ops->link_clk_disable() is followed by pm_runtime_put(), so the power vote will be rescinded if deemed safe.
Patchwork: https://patchwork.freedesktop.org/patch/742783/
--- drivers/gpu/drm/msm/dsi/dsi_host.c | 2 -- 1 file changed, 2 deletions(-)
drivers/gpu/drm/msm/dsi/dsi_host.c +0 -2
@@ -513,8 +513,6 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)void dsi_link_clk_disable_6g (struct msm_dsi_host *msm_host) { -/* Drop the performance state vote */ -dev_pm_opp_set_rate (&msm_host->pdev->dev,0 );clk_disable_unprepare (msm_host->esc_clk);clk_disable_unprepare (msm_host->pixel_clk);clk_disable_unprepare (msm_host->byte_intf_clk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 985/1424 wifi: ath11k: fix leak in ath11k_service_ready_ext_event()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 0293be2212d319d59589082461abf2a9b626cd1c ]
Currently, during ath11k_service_ready_ext_event() processing, svc_rdy_ext.mac_phy_caps can be allocated during TLV parsing. This is a temporary allocation that is freed on the success path, but not on the error path. If parsing succeeds far enough to allocate mac_phy_caps and then fails on a later TLV, the allocation leaks. So free the allocation on the error path.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/ath/ath11k/wmi.c +1 -0
@@ -4959,6 +4959,7 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab,return 0 ; err: +kfree (svc_rdy_ext.mac_phy_caps);ath11k_wmi_free_dbring_caps (ab);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 986/1424 regulator: core: use system_freezable_wq for init complete work
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joy Zou <[email protected]>
[ Upstream commit 03eab318cedd6ae34ecd34533cd986edf5237164 ]
schedule_delayed_work() uses system_wq, which is non-freezable, allowing regulator_init_complete_work to run concurrently with system suspend. This work fires ~30s after boot to disable unused regulators via I2C. When it races with PM suspend, the I2C adapter may already be suspended, triggering a -ESHUTDOWN warning in __i2c_transfer():
WARNING: ... at __i2c_transfer+0x36c/0x3c8
Call trace: __i2c_transfer i2c_transfer regmap_i2c_write _regmap_update_bits regulator_disable_regmap _regulator_do_disable regulator_late_cleanup regulator_init_complete_work_function process_one_work
Switch to system_freezable_wq so the work is frozen before any device is suspended, eliminating the race.
--- drivers/regulator/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/regulator/core.c +4 -2
@@ -26,6 +26,7 @@#include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/module.h> +#include <linux/workqueue.h> #define CREATE_TRACE_POINTS #include <trace/events/regulator.h>
@@ -6327,8 +6328,9 @@ static int __init regulator_init_complete(void)* we'd only do this on systems that need it, and a kernel * command line option might be useful. */ -schedule_delayed_work (®ulator_init_complete_work, -msecs_to_jiffies (30000 )); +queue_delayed_work (system_freezable_wq, + ®ulator_init_complete_work, +msecs_to_jiffies (30000 ));return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 987/1424 perf machine: Fix NULL parent dereference in fork event processing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 73ac546bd6ba8ed4dc8d7a90fcb9bb8236de1568 ]
machine__process_fork_event() calls machine__findnew_thread() for the parent thread, which can return NULL on allocation failure. The code then dereferences parent via thread__pid(parent) without a NULL check when validating whether the parent PID matches. The later NULL check at thread__fork() does not prevent this earlier dereference.
Add a NULL guard before accessing the parent thread.
--- tools/perf/util/machine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +2 -1
@@ -2103,7 +2103,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event* (fork) event that would have removed the thread was lost. Assume the * latter case and continue on as best we can. */ -if (thread__pid (parent) != (pid_t )event->fork.ppid) { +if (parent !=NULL && +thread__pid (parent) != (pid_t )event->fork.ppid) {dump_printf ("removing erroneous parent thread %d/%d\n" ,thread__pid (parent),thread__tid (parent));machine__remove_thread (machine, parent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 988/1424 perf machine: Guard against NULL strlist in machines__findnew()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit e27b96d0a34e1dc87affecf221a99fee8f6c5afc ]
The static 'seen' strlist caches guestmount paths that have already been reported as inaccessible, to avoid repeating the error message. If strlist__new() fails (OOM), 'seen' stays NULL and the next call dereferences it via strlist__has_entry() and strlist__add().
Guard both calls so that on allocation failure the error message is still printed (just not deduplicated) instead of crashing.
--- tools/perf/util/machine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +3 -2
@@ -376,9 +376,10 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if (!seen) seen =strlist__new (NULL ,NULL ); -if (!strlist__has_entry (seen, path)) { +if (!seen || !strlist__has_entry (seen, path)) {pr_err ("Can't access file %s\n" , path); -strlist__add (seen, path); +if (seen) +strlist__add (seen, path); } machine =NULL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 989/1424 perf machine: Use snprintf() for guestmount path construction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fe63d3bca288c5bb983304efd5fc3a5ff3183403 ]
machines__findnew() and machines__create_guest_kernel_maps() use sprintf() to build paths by prepending symbol_conf.guestmount. Both write into PATH_MAX stack buffers, but guestmount comes from user configuration and is not length-checked. A guestmount path at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof() to prevent overflow. The subsequent access()/fopen() calls will fail on a truncated path.
Stable-dep-of: cc6abe0012bf ("perf machine: Check snprintf truncation in machines__findnew()")
--- tools/perf/util/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +4 -4
@@ -369,7 +369,7 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -sprintf (path,"%s/%d" , symbol_conf.guestmount, pid); +snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid);if (access (path,R_OK )) {static struct strlist *seen;
@@ -1416,9 +1416,9 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);continue ; } -sprintf (path,"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name); ret =access (path,R_OK );if (ret) {pr_debug ("Can't access file %s\n" , path);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 990/1424 perf machine: Check snprintf truncation in machines__findnew()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cc6abe0012bf8c04af8275266f8ed7c55ba4a5fb ]
The guestmount path is built with snprintf() into a PATH_MAX buffer without checking the return value. If symbol_conf.guestmount is long enough to cause truncation, the truncated path could match a different directory, causing the wrong guest to be associated with the pid.
Check for truncation and bail out early.
--- tools/perf/util/machine.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +6 -1
@@ -369,7 +369,12 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid); +if (snprintf (path,sizeof (path),"%s/%d" , + symbol_conf.guestmount, pid) >= (int )sizeof (path)) { +pr_err ("Guest path too long for pid %d\n" , pid); + machine =NULL ; + goto out; + }if (access (path,R_OK )) {static struct strlist *seen;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 991/1424 perf machine: Dont abort guest map creation on first inaccessible dir
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit b687e1a418fb819ef83c362d84c216a6a841e3b0 ]
machines__create_guest_kernel_maps() jumps to the failure label when one guest directory's kallsyms file fails access(), skipping all remaining valid guest directories. An inaccessible directory is not fatal — other guests may still be reachable.
Replace 'goto failure' with 'continue' so the loop processes all directories, and remove the now-unreferenced failure label.
--- tools/perf/util/machine.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +2 -4
@@ -1424,14 +1424,12 @@ int machines__create_guest_kernel_maps(struct machines *machines)snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , symbol_conf.guestmount, namelist[i]->d_name); - ret =access (path,R_OK ); -if (ret) { +if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path); - goto failure; +continue ; }machines__create_kernel_maps (machines, pid); } -failure:free (namelist); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 992/1424 perf machine: Reset errno before strtol in guest kernel map creation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 29ec46e43f6ca7d6a6651db724d4ffd820f46e8b ]
machines__create_guest_kernel_maps() checks errno == ERANGE after strtol() to detect overflow, but does not clear errno first. A stale ERANGE from an earlier library call (e.g. scandir internals) causes valid numeric directory names to be incorrectly skipped.
Set errno = 0 before strtol() so only the current conversion can trigger the ERANGE check.
--- tools/perf/util/machine.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/machine.c +1 -0
@@ -1413,6 +1413,7 @@ int machines__create_guest_kernel_maps(struct machines *machines)/* Filter out . and .. */ continue ; } + errno =0 ; pid = (pid_t )strtol (namelist[i]->d_name, &endp,10 ); if ((*endp != '\0') || (endp == namelist[i]->d_name) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 993/1424 perf machine: Free scandir entries in guest kernel map creation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit f53bf58dcd11e1cb088d3b91a035fef77062094b ]
machines__create_guest_kernel_maps() calls scandir() which allocates both the namelist array and each individual dirent entry. The code frees the namelist array but not the individual entries, leaking memory proportional to the number of directories under guestmount.
Free each namelist[i] after it is no longer needed.
--- tools/perf/util/machine.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/util/machine.c +4 -0
@@ -1411,6 +1411,7 @@ int machines__create_guest_kernel_maps(struct machines *machines)for (i =0 ; i < items; i++) {if (!isdigit (namelist[i]->d_name[0 ])) {/* Filter out . and .. */ +free (namelist[i]);continue ; } errno =0 ;
@@ -1420,6 +1421,7 @@ int machines__create_guest_kernel_maps(struct machines *machines) (errno == ERANGE)) {pr_debug ("invalid directory (%s). Skipping.\n" , namelist[i]->d_name); +free (namelist[i]);continue ; } snprintf(path, sizeof(path), "%s/%s/proc/kallsyms",
@@ -1427,9 +1429,11 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path); +free (namelist[i]);continue ; }machines__create_kernel_maps (machines, pid); +free (namelist[i]); }free (namelist); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 994/1424 perf machine: Check snprintf truncation for guest kallsyms path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit d04ef71492fad7230d474efe33d05f4c0563d409 ]
machines__create_guest_kernel_maps() builds the guest kallsyms path with snprintf() without checking the return value. A truncated path could pass the access() check if a prefix directory happens to contain a file named "kallsyms", leading to the wrong file being used for symbol resolution.
Check for truncation and skip the directory.
--- tools/perf/util/machine.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +8 -3
@@ -1424,9 +1424,14 @@ int machines__create_guest_kernel_maps(struct machines *machines)free (namelist[i]);continue ; } -snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +if (snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name) >= (int )sizeof (path)) { +pr_debug ("Guest kallsyms path too long for %s. Skipping.\n" , + namelist[i]->d_name); +free (namelist[i]); +continue ; + }if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path);free (namelist[i]);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 995/1424 wifi: mt76: mt7915: unlink TWT flow if the MCU rejects the agreement
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 16a04441eab0dcd4d7126a6f66b370adbf28f96d ]
The flow is added to dev->twt_list before sending the agreement to the firmware, but the error path leaves it linked while flowid_mask is never set. The flow slot can then be reused and memset while still on the list, corrupting twt_list, and station removal leaves a dangling entry behind that mt7915_mac_twt_sched_list_add() later walks.
--- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +3 -1
@@ -2363,8 +2363,10 @@ void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, } flow->tsf =le64_to_cpu (twt_agrt->twt); -if (mt7915_mcu_twt_agrt_update (dev, msta->vif, flow,MCU_TWT_AGRT_ADD )) +if (mt7915_mcu_twt_agrt_update (dev, msta->vif, flow,MCU_TWT_AGRT_ADD )) { +list_del (&flow->list); goto unlock; + } setup_cmd =TWT_SETUP_CMD_ACCEPT ; dev->twt.table_mask |=BIT (table_id);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 996/1424 wifi: mt76: mt7915: fix double hif2 init on the non-WED path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 3ae8ad277e2819a281b0e36b55633c8515c16ce7 ]
mt7915_pci_init_hif2() was called unconditionally and again inside the WED-inactive branch. The helper increments the global hif_idx, writes the PCIe RECOG_ID register and takes a get_device() reference via mt7915_pci_get_hif2(), while removal only drops one reference. On non-WED dual-hif hardware this double-incremented hif_idx, wrote RECOG_ID twice and leaked a device reference. Only the call inside the WED-inactive branch is correct; drop the unconditional one. hif2 is already initialised to NULL.
--- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/pci.c +0 -1
@@ -135,7 +135,6 @@ static int mt7915_pci_probe(struct pci_dev *pdev, mdev = &dev->mt76;mt7915_wfsys_reset (dev); - hif2 =mt7915_pci_init_hif2 (pdev); ret =mt7915_mmio_wed_init (dev, pdev, true, &irq);if (ret <0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 997/1424 wifi: mt76: mt7915: fix ext PHY use-after-free on register error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 15b960014f24dce5388d4a2e7274e6490cb3c421 ]
After mt7915_register_ext_phy() succeeded, a failure of the main PHY mt7915_init_debugfs() or mt7915_coredump_register() unwound through free_phy2, which called ieee80211_free_hw() on the ext PHY hw while it was still registered with mac80211, since mt76_unregister_device() only unregisters the main hw. Unregister the ext PHY (thermal + phy + hw) first and skip the redundant free.
--- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +7 -2
@@ -1232,14 +1232,19 @@ int mt7915_register_device(struct mt7915_dev *dev) ret =mt7915_init_debugfs (&dev->phy);if (ret) - goto unreg_thermal; + goto unreg_ext_phy; ret =mt7915_coredump_register (dev);if (ret) - goto unreg_thermal; + goto unreg_ext_phy;return 0 ; +unreg_ext_phy: +if (phy2) { +mt7915_unregister_ext_phy (dev); + phy2 =NULL ; + } unreg_thermal:mt7915_unregister_thermal (&dev->phy); unreg_dev:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 998/1424 wifi: mt76: mt7915: release hif2 reference on probe IRQ failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 8370aebd26a9dfa2e0de665e3ab504c0e97ee730 ]
The hif2 reference obtained by mt7915_pci_init_hif2() is only released on error paths that key off dev->hif2, which is not assigned until after the IRQ setup. If pci_alloc_irq_vectors() or the primary devm_request_irq() fails, the reference leaks. Drop it explicitly on those paths via mt7915_put_hif2().
--- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/pci.c +6 -2
@@ -144,16 +144,20 @@ static int mt7915_pci_probe(struct pci_dev *pdev, hif2 =mt7915_pci_init_hif2 (pdev); ret =pci_alloc_irq_vectors (pdev,1 ,1 ,PCI_IRQ_ALL_TYPES ); -if (ret <0 ) +if (ret <0 ) { +mt7915_put_hif2 (hif2); goto free_device; + } irq = pdev->irq; } ret =devm_request_irq (mdev->dev, irq, mt7915_irq_handler,IRQF_SHARED ,KBUILD_MODNAME , dev); -if (ret) +if (ret) { +mt7915_put_hif2 (hif2); goto free_wed_or_irq_vector; + }/* master switch of PCIe tnterrupt enable */ mt76_wr (dev,MT_PCIE_MAC_INT_ENABLE ,0xff );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 999/1424 wifi: mt76: mt7996: fix reg addr remap when addr is 0
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: StanleyYP Wang <[email protected]>
[ Upstream commit eb906eeff2d1e84b628dc210dada325269c71383 ]
When addr is less than the hardcoded threshold in __mt7996_reg_addr, it indicates that remapping is unnecessary.
Currently, the flow remaps address 0x0 to MT_HIF_REMAP_BASE_L2, which is incorrect.
To address this, modify __mt7996_reg_addr to return INVALID_REG_ADDR if the address is not below the hardcoded value or is not present in the mt7996_reg_map array.
Additionally, update the remap condition to check if addr is equal to INVALID_REG_ADDR.
--- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +7 -5
@@ -11,6 +11,8 @@#include "mac.h" #include "../trace.h" +#define INVALID_REG_ADDR 0xffffffff +static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE ] = { {0x820e2000 ,0x820f2000 ,0x830e2000 } }, [WF_ARB_BASE ] = { {0x820e3000 ,0x820f3000 ,0x830e3000 } },
@@ -125,7 +127,7 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)return dev->reg.map[i].mapped + ofs; } -return 0 ; +return INVALID_REG_ADDR ; }static u32 __mt7996_reg_remap_addr (struct mt7996_dev *dev,u32 addr)
@@ -154,7 +156,7 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, {u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) { +if (addr !=INVALID_REG_ADDR ) {memcpy_fromio (buf, dev->mt76.mmio.regs + addr, len);return ; }
@@ -170,7 +172,7 @@ static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset), val; -if (addr) +if (addr !=INVALID_REG_ADDR )return dev->bus_ops->rr (mdev, addr);spin_lock_bh (&dev->reg_lock);
@@ -185,7 +187,7 @@ static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) { +if (addr !=INVALID_REG_ADDR ) { dev->bus_ops->wr (mdev, addr, val);return ; }
@@ -200,7 +202,7 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) +if (addr !=INVALID_REG_ADDR )return dev->bus_ops->rmw (mdev, addr, mask, val);spin_lock_bh (&dev->reg_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1000/1424 wifi: mt76: mt7915: fix chainmask handling for non-dbdc phys on band 1
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit ea891799eccc9e43ebba0dc157d4b197ad6c1a0e ]
On single-adie mt7986 the only phy is bound to band 1, but its chainmask is stored unshifted, because dev->chainshift is still zero while the eeprom is parsed for the main phy. mt7915_set_antenna() on the other hand shifts by chainshift * band_idx, so the representation of the chainmask changed as soon as the antenna configuration was touched. Until then, mt7915_mcu_set_chan_info() passed rx_path = 0 to the firmware, since shifting the unshifted mask down clears all bits.
Keep the unshifted form for that case and add helpers for the band local chainmask, so that only the band 1 phy of a dbdc device uses the shifted form.
--- .../net/wireless/mediatek/mt76/mt7915/eeprom.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/main.c | 6 +++--- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/mt7915.h | 18 ++++++++++++++++++ .../wireless/mediatek/mt76/mt7915/testmode.c | 5 +---- 5 files changed, 24 insertions(+), 9 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +1 -1
@@ -246,7 +246,7 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, nss =min_t (u8,min_t (u8, nss_max, nss), path); mphy->chainmask =BIT (path) -1 ; -if (band) +if (band && dev->dbdc_support) mphy->chainmask <<= dev->chainshift; mphy->antenna_mask =BIT (nss) -1 ; dev->chainmask |= mphy->chainmask;
drivers/net/wireless/mediatek/mt76/mt7915/main.c +3 -3
@@ -1038,7 +1038,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)struct mt7915_dev *dev =mt7915_hw_dev (hw);struct mt7915_phy *phy =mt7915_hw_phy (hw);int max_nss =hweight8 (hw->wiphy->available_antennas_tx); -u8 chainshift = dev->chainshift; +u8 shift =mt7915_band_chainshift (phy);u8 band = phy->mt76->band_idx;if (!tx_ant || tx_ant != rx_ant ||ffs (tx_ant) > max_nss)
@@ -1051,9 +1051,9 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)/* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ if ((is_mt7916 (&dev->mt76) ||is_mt7981 (&dev->mt76)) && band &&hweight8 (tx_ant) == max_nss) - phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; + phy->mt76->chainmask = (dev->chainmask >> shift) << shift;else - phy->mt76->chainmask = tx_ant << (chainshift * band); + phy->mt76->chainmask = tx_ant << shift;mt76_set_stream_caps (phy->mt76, true);mt7915_set_stream_vht_txbf_caps (phy);
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +1 -1
@@ -2743,7 +2743,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), + .rx_path = mt7915_band_chainmask(phy), .band_idx = band, .channel_band = ch_band[chandef->chan->band], };
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +18 -0
@@ -377,6 +377,24 @@ mt7915_ext_phy(struct mt7915_dev *dev)return phy->priv; } +/* without dbdc, the chainmask is stored unshifted, even if the phy is +* bound to band 1 +*/ +static inline u8 mt7915_band_chainshift (struct mt7915_phy *phy) +{ +struct mt7915_dev *dev = phy->dev; + +if (!dev->dbdc_support) +return 0 ; + +return phy->mt76->band_idx * dev->chainshift; +} + +static inline u16 mt7915_band_chainmask (struct mt7915_phy *phy) +{ +return phy->mt76->chainmask >>mt7915_band_chainshift (phy); +} +static inline u32 mt7915_check_adie (struct mt7915_dev *dev,bool sku) {u32 mask = sku ?MT_CONNINFRA_SKU_MASK :MT_ADIE_TYPE_MASK ;
drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +1 -4
@@ -692,9 +692,7 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, {struct mt76_testmode_data *td = &mphy->test;struct mt7915_phy *phy = mphy->priv; -struct mt7915_dev *dev = phy->dev; -u32 chainmask = mphy->chainmask, changed =0 ; -bool ext_phy = phy != &dev->phy; +u32 chainmask =mt7915_band_chainmask (phy), changed =0 ;int i;BUILD_BUG_ON (NUM_TM_CHANGED >=32 );
@@ -703,7 +701,6 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, td->state == MT76_TM_STATE_OFF)return 0 ; - chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask;if (td->tx_antenna_mask > chainmask)return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1001/1424 wifi: mt76: mt7915: report RX chain signal for all RX paths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit b53c44fe65792608f58028c7b0953e610ad652ee ]
status->chains was set from the antenna mask, which is derived from the number of spatial streams, while the chain_signal array is filled from all RCPI fields. On boards where the number of RX paths exceeds the stream count, e.g. the 3T3R mt7916/mt7981 variant with 2 streams on the 5 GHz band, the RSSI of the extra chains was never reported.
Use the band local RX path chainmask instead.
--- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +1 -1
@@ -437,7 +437,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,if (v0 &MT_PRXV_HT_AD_CODE ) status->enc_flags |=RX_ENC_FLAG_LDPC ; - status->chains = mphy->antenna_mask; + status->chains =mt7915_band_chainmask (phy); status->chain_signal[0 ] =to_rssi (MT_PRXV_RCPI0 , v1); status->chain_signal[1 ] =to_rssi (MT_PRXV_RCPI1 , v1); status->chain_signal[2 ] =to_rssi (MT_PRXV_RCPI2 , v1);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1002/1424 wifi: ath10k: snoc: use memcpy_fromio() for MSA ramdump
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linghui Wu <[email protected]>
[ Upstream commit 4f25071afe9218aaae1c63fbf75e229aa6405319 ]
On WCN3990/SNOC the MSA region is mapped with devm_memremap(MEMREMAP_WT). On arm64 such a mapping is not Normal-cacheable, so unaligned accesses to it are not permitted. ath10k_msa_dump_memory() copies the region with a plain memcpy(), whose optimized __pi_memcpy_generic implementation issues wide/unaligned loads. This triggers an alignment fault (FSC=0x21) Oops in ath10k_snoc_fw_crashed_dump() while collecting the devcoredump:
Unable to handle kernel paging request ... FSC=0x21: alignment fault pc : __pi_memcpy_generic lr : ath10k_snoc_fw_crashed_dump [ath10k_snoc]
The Oops both leaves the firmware RAM dump buffer zeroed (no dump is captured) and crashes the kernel, which in turn breaks modem SSR recovery.
Use memcpy_fromio(), which only performs accesses that are valid for such a device-memory mapping. The generic memcpy_fromio() implementation aligns the source before issuing word-sized reads and stores the destination with put_unaligned(), so it is also safe for the coherent DMA allocation used on the non-reserved-memory path. ath11k and ath12k use the same pattern when copying target memory into crash dumps, so call it unconditionally here too.
The MEMREMAP_WT pointer is a plain void *, so an explicit __iomem cast is needed; use __force to keep sparse happy.
Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.3.7.c5-00107-QCAHLSWMTPL-1
--- drivers/net/wireless/ath/ath10k/snoc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath10k/snoc.c +7 -2
@@ -5,6 +5,7 @@#include <linux/bits.h> #include <linux/clk.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h>
@@ -1452,11 +1453,15 @@ static void ath10k_msa_dump_memory(struct ath10k *ar, hdr->length =cpu_to_le32 (ar->msa.mem_size);if (current_region->len < ar->msa.mem_size) { -memcpy (buf, ar->msa.vaddr, current_region->len); +memcpy_fromio (buf, + (const void __iomem __force *)ar->msa.vaddr, + current_region->len);ath10k_warn (ar,"msa dump length is less than msa size %x, %x\n" , current_region->len, ar->msa.mem_size); }else { -memcpy (buf, ar->msa.vaddr, ar->msa.mem_size); +memcpy_fromio (buf, + (const void __iomem __force *)ar->msa.vaddr, + ar->msa.mem_size); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1003/1424 iommu/arm-smmu-v3: Convert to use atomic poll timeout
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pranjal Shrivastava <[email protected]>
[ Upstream commit eced8058c82a3a81ae480a6546e2da32100dddfa ]
The arm_smmu_write_reg_sync() helper is currently implemented using readl_relaxed_poll_timeout() (that relies on usleep_range() internally) which becomes a critical issue when used in the gerror irq handler.
If the SMMU hits a gerror and enters Service Failure Mode (GERROR_SFM_ERR), the gerror handler calls arm_smmu_device_disable() in hard-irq context. This becomes a problem as arm_smmu_device_disable() inevitably calls arm_smmu_write_reg_sync() which might attempt to sleep inside a hard-irq context.
Fix this by converting the arm_smmu_write_reg_sync to use the readl_relaxed_poll_timeout_atomic() polling helper.
(Discovered while running Sashiko locally on another patch series).
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3 -2
@@ -3128,8 +3128,9 @@ static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,u32 reg;writel_relaxed (val, smmu->base + reg_off); -return readl_relaxed_poll_timeout (smmu->base + ack_off, reg, reg == val, -1 ,ARM_SMMU_POLL_TIMEOUT_US ); +return readl_relaxed_poll_timeout_atomic (smmu->base + ack_off, reg, + reg == val,1 , +ARM_SMMU_POLL_TIMEOUT_US ); }/* GBPA is "special" */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1004/1424 perf/cxlpmu: Fix 64-bit write to 32-bit HDM filter register
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
[ Upstream commit ea434e8fd3a539e9c53285b10d3c7e539e228591 ]
The HDM decoder filter configuration register is 32 bits wide, but the driver programs it with a 64-bit writeq(). The filter value never exceeds 32 bits, so the upper half of the write is always zero and lands in the adjacent Filter ID 1 (Channel/Rank/Bank) configuration register at offset+4.
--- drivers/perf/cxl_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/perf/cxl_pmu.c +1 -1
@@ -643,7 +643,7 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags) cfg =cxl_pmu_config2_get_hdm_decoder (event); else cfg =GENMASK (31 ,0 );/* No filtering if 0xFFFF_FFFF */ -writeq (cfg, base +CXL_PMU_FILTER_CFG_REG (hwc->idx,0 )); +writel (cfg, base +CXL_PMU_FILTER_CFG_REG (hwc->idx,0 )); } cfg =readq (base +CXL_PMU_COUNTER_CFG_REG (hwc->idx));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1005/1424 wifi: mac80211: send TWT teardown to peer after setup TX failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit a28fcce6ee74be8a4526e6cfa16dc7786d62a784 ]
When an AP's TWT Setup response is not acknowledged, ieee80211_s1g_tx_twt_setup_fail() asks the driver to tear down the local agreement and sends a TWT teardown action as the peer notification. It uses the response SA as the destination, but ieee80211_s1g_send_twt_setup() built that response with SA set to the AP's address. The teardown is therefore queued with DA, SA and BSSID all set to the AP address and never reaches the station.
The in-tree driver callbacks update local hardware state and emit no action frame. The station receives no notification that mac80211 asked the driver to remove the agreement and can keep following the TWT schedule, leaving the peers' power-save state desynchronized.
Address the teardown to the response DA, the station to which the failed response was sent. This also matches the station lookup the transmit status path already performs on the same frame.
--- net/mac80211/s1g.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mac80211/s1g.c +1 -1
@@ -146,7 +146,7 @@ ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,drv_twt_teardown_request (sdata->local, sdata, &sta->sta, flowid); -ieee80211_s1g_send_twt_teardown (sdata, mgmt->sa, sdata->vif.addr, +ieee80211_s1g_send_twt_teardown (sdata, mgmt->da, sdata->vif.addr, flowid); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1006/1424 wifi: zd1211rw: reject secondary interfaces to prevent conflicts
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Slawomir Stepien <[email protected]>
[ Upstream commit 0e4532ec658606f76f62eb277e7a933919d36cbb ]
The zd1211rw driver is designed for single-function Wi-Fi dongles and hardcodes its USB endpoints. When a malformed USB device exposes multiple interfaces that match the driver's device ID, the driver blindly binds to all of them.
During probe(), the driver calls usb_reset_device(), which iterates over all interfaces and invokes the pre_reset() callback for each bound interface. Since multiple interfaces are bound to zd1211rw, pre_reset() is called sequentially for each instance, acquiring their respective &mac->chip.mutex. Because all instances initialize their mutexes with the same lock class, lockdep detects a task acquiring a lock of the same class it already holds and flags it as a possible recursive deadlock:
WARNING: possible recursive locking detected kworker/0:1/11 is trying to acquire lock:ffff88810371dde0 (&chip->mutex){+.+.}-{4:4}, at:zd_chip_disable_rxtx+0x20/0x50 drivers/net/wireless/zydas/zd1211rw/zd_chip.c:1465
but task is already holding lock:ffff8881138ddde0 (&chip->mutex){+.+.}-{4:4}, at: pre_reset+0x28c/0x380 drivers/net/wireless/zydas/zd1211rw/zd_usb.c:1505
Fix this by explicitly rejecting secondary interfaces (bInterfaceNumber !=
0) during probe(). This ensures that only a single instance of the driver binds to the device, eliminating the recursive locking scenario.
--- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/wireless/zydas/zd1211rw/zd_usb.c +8 -0
@@ -1351,6 +1351,14 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)struct zd_usb *usb;struct ieee80211_hw *hw =NULL ; +/* +* ZD1211 devices are single-function. Reject secondary interfaces +* to prevent multiple instances from conflicting on hardcoded endpoints +* and triggering recursive locking warnings. +*/ +if (intf->cur_altsetting->desc.bInterfaceNumber !=0 ) +return -ENODEV ; +print_id (udev);if (id->driver_info &DEVICE_INSTALLER )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1007/1424 wifi: mac80211: skip unused probe response countdown offsets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit fd2bf5e718108c00732eb07fd94a5d8830f62a9f ]
mac80211 copies cfg80211's variable-length countdown offset list into a zero-initialized fixed-size array, leaving unused entries at zero. The beacon branch already skips those zero entries, but the AP probe-response branch writes through them unconditionally.
When a probe-response template has no countdown offset, the write through an unused zero entry overwrites resp->data[0], corrupting the first byte of the template. cfg80211 already bounds explicitly supplied non-zero offsets in nl80211_parse_counter_offsets(), so this is a zero-sentinel bug, not an out-of-bounds write.
Skip zero probe-response offsets, matching the beacon path.
--- net/mac80211/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/mac80211/tx.c +2 -1
@@ -5035,7 +5035,8 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,if (sdata->vif.type ==NL80211_IFTYPE_AP && resp) {u16 *resp_offsets = resp->cntdwn_counter_offsets; - resp->data[resp_offsets[i]] = count; +if (resp_offsets[i]) + resp->data[resp_offsets[i]] = count; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1008/1424 firmware: google: Add bounds checks in coreboot_table_populate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Titouan Ameline de Cadeville <[email protected]>
[ Upstream commit 7b1a1af4556a4f95ef273e91435fe804cbfcd223 ]
coreboot_table_populate() iterates over firmware-provided table entries with no validation that the entries stay within the mapped memory region. A corrupt table with a large entry->size advances ptr_entry past the mapped region, causing an out-of-bounds read on the next iteration.
Add a check before dereferencing ptr_entry to ensure the entry header is readable, and a second check after reading entry->size to ensure the full entry stays within the mapped region.
Pass len from coreboot_table_probe() into coreboot_table_populate() to make the mapped region size available for validation.
Stable-dep-of: a58a57a1076f ("firmware: coreboot: Validate table bounds")
--- drivers/firmware/google/coreboot_table.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/firmware/google/coreboot_table.c +9 -2
@@ -81,16 +81,20 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) }EXPORT_SYMBOL (coreboot_driver_unregister); -static int coreboot_table_populate (struct device *dev,void *ptr) +static int coreboot_table_populate (struct device *dev,void *ptr,resource_size_t len) {int i, ret;void *ptr_entry;struct coreboot_device *device;struct coreboot_table_entry *entry;struct coreboot_table_header *header = ptr; +void *ptr_end; + ptr_end = ptr + len; ptr_entry = ptr + header->header_bytes;for (i =0 ; i < header->table_entries; i++) { +if (ptr_entry +sizeof (*entry) > ptr_end) +return -EINVAL ; entry = ptr_entry;if (entry->size <sizeof (*entry)) {
@@ -98,6 +102,9 @@ static int coreboot_table_populate(struct device *dev, void *ptr)return -EINVAL ; } +if (ptr_entry + entry->size > ptr_end) +return -EINVAL ; + device =kzalloc (sizeof (device->dev) + entry->size,GFP_KERNEL );if (!device)return -ENOMEM ;
@@ -163,7 +170,7 @@ static int coreboot_table_probe(struct platform_device *pdev)if (!ptr)return -ENOMEM ; - ret =coreboot_table_populate (dev, ptr); + ret =coreboot_table_populate (dev, ptr, len);memunmap (ptr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1009/1424 firmware: coreboot: Validate table bounds
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
[ Upstream commit a58a57a1076f8c5dae0327e3710899478c3be901 ]
The existing coreboot_table_populate() bounds checks limit individual entries to the mapped length. However, coreboot_table_probe() replaces the platform resource length with header and table sizes supplied by firmware before mapping the full table.
A malformed table can overflow the 32-bit size addition or advertise an extent beyond the resource, causing the driver to map and parse memory outside the resource. A resource shorter than the fixed header is also mapped as though it contained a complete header.
Reject resources shorter than the fixed header. After validating the signature, require a complete header, calculate the advertised extent with overflow checking, and reject extents beyond the resource before remapping the table.
--- drivers/firmware/google/coreboot_table.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/firmware/google/coreboot_table.c +13 -4
@@ -139,6 +139,7 @@ static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_static int coreboot_table_probe (struct platform_device *pdev) {resource_size_t len; +resource_size_t table_span;struct coreboot_table_header *header;struct resource *res;struct device *dev = &pdev->dev;
@@ -150,7 +151,7 @@ static int coreboot_table_probe(struct platform_device *pdev)return -EINVAL ; len =resource_size (res); -if (!res->start || !len) +if (!res->start || len <sizeof (*header))return -EINVAL ;/* Check just the header first to make sure things are sane */
@@ -158,19 +159,27 @@ static int coreboot_table_probe(struct platform_device *pdev)if (!header)return -ENOMEM ; - len = header->header_bytes + header->table_bytes; ret =strncmp (header->signature,"LBIO" ,sizeof (header->signature)); + +if (!ret && + (header->header_bytes <sizeof (*header) || +check_add_overflow ((resource_size_t )header->header_bytes, + (resource_size_t )header->table_bytes, + &table_span) || + table_span > len)) + ret = -EINVAL ; +memunmap (header);if (ret) {dev_warn (dev,"coreboot table missing or corrupt!\n" );return -ENODEV ; } - ptr =memremap (res->start, len,MEMREMAP_WB ); + ptr =memremap (res->start, table_span,MEMREMAP_WB );if (!ptr)return -ENOMEM ; - ret =coreboot_table_populate (dev, ptr, len); + ret =coreboot_table_populate (dev, ptr, table_span);memunmap (ptr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1010/1424 powerpc/smp: add NULL guard for cause_ipi in smp_muxed_ipi_message_pass
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <[email protected]>
[ Upstream commit 5aabc192702defb8950e7c81b05c3f4ca8ee43ec ]
smp_muxed_ipi_message_pass() calls smp_ops->cause_ipi() without checking whether it has been set.
On platforms using muxed IPI (e.g. powernv/pseries), smp_ops->cause_ipi is initialized to NULL in the static smp_ops and only assigned during the platform smp_probe() handler. If the IPI subsystem fails to initialize -- for example when xive_init_ipis() fails and xive_smp_probe() returns an error -- the probe handler returns early and cause_ipi is never set. Any subsequent IPI send (e.g. arch_smp_send_reschedule()) would dereference the NULL pointer.
Add a NULL check to avoid the crash in that situation.
--- arch/powerpc/kernel/smp.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/kernel/smp.c +3 -0
@@ -297,6 +297,9 @@ void smp_muxed_ipi_set_message(int cpu, int msg)void smp_muxed_ipi_message_pass (int cpu,int msg) { +if (!smp_ops->cause_ipi) +return ; +smp_muxed_ipi_set_message (cpu, msg);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1011/1424 powerpc/irq: Fix missing r2 clobber in PCREL inline assembly
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Saket Kumar Bhaskar <[email protected]>
[ Upstream commit 00be69070d91d2be978e752bb117a0a4db0e1281 ]
In CONFIG_PPC_KERNEL_PCREL mode, r2 is no longer reserved for the TOC pointer and is available as a caller-saved register [0].
Both call_do_irq() and call_do_softirq() use inline assembly to call functions with stack switching, but fail to list r2 in their clobber lists. This causes the compiler to assume r2 is preserved across these calls, leading to register corruption when the called functions (__do_irq and __do_softirq) clobber r2.
As a result of this kernel crash during interrupt handling is seen and the kernel fails to boot:
BUG: Unable to handle kernel data access on write at 0xc000000404697638 Faulting instruction address: 0xc0000000000181ec Oops: Kernel access of bad area, sig: 11 [#1] NIP [c0000000000181ec] __do_IRQ+0x6c/0xc0
With older GCC, the compiler would conservatively allocate callee-saved registers (like r31) for values spanning function calls, accidentally avoiding the bug:
<__do_IRQ>:
00 00 00 60 nop
a6 02 08 7c mflr r0 f8 ff e1 fb std r31,-8(r1) f0 ff c1 fb std r30,-16(r1) 2d 03 10 06 pla r31,53297316
...
3d e8 ff 4b bl c0000000000165ac <__do_irq> 00 00 21 e8 ld r1,0(r1) 28 00 4d e9 ld r10,40(r13) 40 00 21 38 addi r1,r1,64 2a f9 aa 7f stdx r29,r10,r31
With newer GCC 14, the compiler uses r2 for such values, exposing the missing clobber specification:
<__do_IRQ>:
00 00 00 60 nop a6 02 08 7c mflr r0 f0 ff c1 fb std r30,-16(r1) f8 ff e1 fb std r31,-8(r1) 29 02 10 06 pla r2,36252592 # c0000000022aadc0 <__irq_regs>
...
85 dc ff 4b bl c000000000015ee0 <__do_irq> 00 00 21 e8 ld r1,0(r1) 28 00 2d e9 ld r9,40(r13) 30 00 21 38 addi r1,r1,48 2a 11 c9 7f stdx r30,r9,r2
Fix this by adding r2 to the clobber list for both call_do_irq() and call_do_softirq() when CONFIG_PPC_KERNEL_PCREL is enabled.
[0]: https://www.mail-archive.com/[email protected]/msg313226.html
--- arch/powerpc/kernel/irq.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
arch/powerpc/kernel/irq.c +12 -4
@@ -217,8 +217,12 @@ static __always_inline void call_do_softirq(const void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_softirq) : // Clobbers -"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" , -"cr7" ,"r0" ,"r3" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" , +"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" ,"cr7" ,"r0" , +/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL +"r2" , +#endif +"r3" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" ,"r11" ,"r12" ); }
@@ -275,8 +279,12 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_irq) : // Clobbers -"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" , -"cr7" ,"r0" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" , +"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" ,"cr7" ,"r0" , +/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL +"r2" , +#endif +"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" ,"r11" ,"r12" ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1012/1424 MIPS: ptrace: Fix syscall skipping via PTRACE_SYSCALL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Bogendoerfer <[email protected]>
[ Upstream commit 5475c03fa25f31cfd5f8c7e552f8d10347bbaad9 ]
If tracer wanted to skip a syscall return value was always overwritten with -ENOSYS. Fix this by checking against original syscall number and only return -ENOSYS, if it is negative.
--- arch/mips/kernel/ptrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/mips/kernel/ptrace.c +5 -1
@@ -1319,8 +1319,12 @@ long arch_ptrace(struct task_struct *child, long request,*/ asmlinkage long syscall_trace_enter (struct pt_regs *regs) { +long syscall; +user_exit (); + syscall =current_thread_info ()->syscall; +if (test_thread_flag (TIF_SYSCALL_TRACE )) {if (ptrace_report_syscall_entry (regs))return -1 ;
@@ -1356,7 +1360,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs)* Negative syscall numbers are mistaken for rejected syscalls, but * won't have had the return value set appropriately, so we do so now. */ -if (current_thread_info ()->syscall <0 ) +if (syscall <0 )syscall_set_return_value (current, regs, -ENOSYS ,0 );return current_thread_info ()->syscall; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1013/1424 serial: amba-pl011: unprepare console clock on unregister
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 7f93da9d78d433c37836d85de475c5d884ad58ed ]
pl011_console_setup() calls clk_prepare() on the UART clock, but the console provides no matching teardown, so the clock is never unprepared when the console is unregistered -- via the sysfs "console" attribute or a driver unbind. Each re-registration prepares the clock again, leaking one prepare reference per cycle.
Even where preparing the clock has no hardware effect, the stale reference leaves the clock framework's prepare count unbalanced. For providers with prepare/unprepare operations or runtime-PM integration, it may also retain resources after the console is unregistered.
Add a console .exit() callback that clk_unprepare()s the clock, balancing the clk_prepare() in pl011_console_setup().
--- drivers/tty/serial/amba-pl011.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/tty/serial/amba-pl011.c +10 -0
@@ -2457,6 +2457,15 @@ static int pl011_console_setup(struct console *co, char *options)return uart_set_options (&uap->port, co, baud, parity, bits, flow); } +static int pl011_console_exit (struct console *co) +{ +struct uart_amba_port *uap = amba_ports[co->index]; + +clk_unprepare (uap->clk); + +return 0 ; +} +/** * pl011_console_match - non-standard console matching * @co: registering console
@@ -2523,6 +2532,7 @@ static struct console amba_console = { .write = pl011_console_write, .device = uart_console_device, .setup = pl011_console_setup, + .exit = pl011_console_exit, .match = pl011_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1014/1424 tty: clear cdev pointer after cdev_add() failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 6645856f0df3aeecd45519cb611415b4b89c2223 ]
tty_cdev_add() drops the cdev reference when cdev_add() fails, but leaves driver->cdevs[index] pointing to freed memory. tty_unregister_device() later passes that stale pointer to cdev_del(), causing a use-after-free.
Clear the slot after dropping the reference.
--- drivers/tty/tty_io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/tty/tty_io.c +3 -1
@@ -3157,8 +3157,10 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, driver->cdevs[index]->ops = &tty_fops; driver->cdevs[index]->owner = driver->owner; err =cdev_add (driver->cdevs[index], dev, count); -if (err) +if (err) {kobject_put (&driver->cdevs[index]->kobj); + driver->cdevs[index] =NULL ; + }return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1015/1424 HID: i2c-hid: Refactor _DSM helper and add i2c-hid-acpi-prp0001 driver
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: 谢致邦 (XIE Zhibang) <[email protected]>
[ Upstream commit fd7c67d05fb695b1deb07f9e213dd7e80e3a8427 ]
Move the _DSM call that gets the HID descriptor address from i2c-hid-acpi.c into i2c-hid-acpi.h as a static inline so both the ACPI and the new PRP0001 driver can use it. While refactoring, move the blacklist check and the _DSM call to the top of probe() to avoid a pointless alloc when the device is blacklisted or does not implement the _DSM.
Some devices, for example the Lenovo KaiTian N60d and Inspur CP300L3, are declared with _HID "PRP0001" and _DSD compatible "hid-over-i2c" but lack "hid-descr-addr" from the _DSD and provide the HID descriptor address only through an ACPI _DSM. The OF driver fails to probe them because it requires hid-descr-addr. Add a new driver that handles these devices by calling the shared _DSM helper.
--- drivers/hid/i2c-hid/Makefile | 2 +- drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c | 104 +++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-acpi.c | 52 +++-------- drivers/hid/i2c-hid/i2c-hid-acpi.h | 33 +++++++ 4 files changed, 152 insertions(+), 39 deletions(-) create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi.h
drivers/hid/i2c-hid/Makefile +1 -1
@@ -8,7 +8,7 @@ obj-$(CONFIG_I2C_HID_CORE) += i2c-hid.o i2c-hid-objs = i2c-hid-core.o i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o -obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o +obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o i2c-hid-acpi-prp0001.o obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o obj-$(CONFIG_I2C_HID_OF_ELAN) += i2c-hid-of-elan.o obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o
drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c new file +104 -0
104 lines not on this page · raw message
drivers/hid/i2c-hid/i2c-hid-acpi.c +14 -38
86 lines not on this page · raw message
drivers/hid/i2c-hid/i2c-hid-acpi.h new file +33 -0
@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _I2C_HID_ACPI_H +#define _I2C_HID_ACPI_H + +#include <linux/acpi.h> +#include <linux/uuid.h> + +static inline int i2c_hid_acpi_get_descriptor (struct acpi_device *adev) +{ +/* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */ +static const guid_t i2c_hid_guid = +GUID_INIT (0x3CDFF6F7 ,0x4267 ,0x4555 , +0xAD ,0x05 ,0xB3 ,0x0A ,0x3D ,0x89 ,0x38 ,0xDE ); + +acpi_handle handle =acpi_device_handle (adev); +union acpi_object *obj; +u16 addr; + + obj =acpi_evaluate_dsm_typed (handle, &i2c_hid_guid, +1 ,1 ,NULL ,ACPI_TYPE_INTEGER ); +if (!obj) { +acpi_handle_err (handle, +"Error _DSM call to get HID descriptor address failed\n" ); +return -ENODEV ; + } + + addr = obj->integer.value; +ACPI_FREE (obj); +return addr; +} + +#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1016/1424 HID: synchronize input before cleaning up a failed probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
[ Upstream commit 207853d46f7ef2e28042344a1468da8754c3ddbf ]
hid_device_io_start() allows reports to run concurrently with probe. If the probe subsequently fails, __hid_device_probe() releases driver resources and clears hdev->driver without first excluding those report callbacks.
For example, a report may enter hidraw_report_event() while the failure path frees the associated hidraw object, leading to a use-after-free when the report takes the object's list lock.
Stop input before performing failed-probe cleanup. This reacquires driver_input_lock and waits for any report callback already in progress.
--- drivers/hid/hid-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/hid/hid-core.c +2 -0
@@ -2701,6 +2701,8 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)*/ if (ret) { +if (hdev->io_started) +hid_device_io_stop (hdev);devres_release_group (&hdev->dev, hdev->devres_group_id);hid_close_report (hdev); hdev->driver =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1017/1424 HID: i2c-hid: Fold i2c_hid_execute_reset() into i2c_hid_hwreset()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
[ Upstream commit f023605d1de6f150d9266747a2630f029956041f ]
i2c_hid_hwreset() is the only caller of i2c_hid_execute_reset(), fold the latter into the former.
This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows.
No functional changes intended.
Stable-dep-of: 8da0f0951dee ("HID: i2c-hid: Fix "(null)" output when reading report descriptor fails")
--- drivers/hid/i2c-hid/i2c-hid-core.c | 73 ++++++++++++------------------ 1 file changed, 30 insertions(+), 43 deletions(-)
drivers/hid/i2c-hid/i2c-hid-core.c +30 -43
@@ -420,12 +420,23 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)return ret; } -static int i2c_hid_execute_reset (struct i2c_hid *ihid) +static int i2c_hid_hwreset (struct i2c_hid *ihid) {size_t length =0 ;int ret; -i2c_hid_dbg (ihid,"resetting...\n" ); +i2c_hid_dbg (ihid,"%s\n" , __func__); + +/* +* This prevents sending feature reports while the device is +* being reset. Otherwise we may lose the reset complete +* interrupt. +*/ +mutex_lock (&ihid->reset_lock); + + ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON ); +if (ret) + goto err_unlock;/* Prepare reset command. Command register goes first. */ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -438,59 +449,35 @@ static int i2c_hid_execute_reset(struct i2c_hid *ihid) ret =i2c_hid_xfer (ihid, ihid->cmdbuf, length,NULL ,0 );if (ret) { -dev_err (&ihid->client->dev,"failed to reset device.\n" ); - goto out; +dev_err (&ihid->client->dev, +"failed to reset device: %d\n" , ret); + goto err_clear_reset; } +i2c_hid_dbg (ihid,"%s: waiting...\n" , __func__); +if (ihid->quirks &I2C_HID_QUIRK_NO_IRQ_AFTER_RESET ) {msleep (100 ); - goto out; - } - -i2c_hid_dbg (ihid,"%s: waiting...\n" , __func__); -if (!wait_event_timeout (ihid->wait, - !test_bit (I2C_HID_RESET_PENDING , &ihid->flags), -msecs_to_jiffies (5000 ))) { +clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); + }else if (!wait_event_timeout (ihid->wait, + !test_bit (I2C_HID_RESET_PENDING , &ihid->flags), +msecs_to_jiffies (5000 ))) { ret = -ENODATA ; - goto out; + goto err_clear_reset; }i2c_hid_dbg (ihid,"%s: finished.\n" , __func__); -out: -clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); -return ret; -} - -static int i2c_hid_hwreset (struct i2c_hid *ihid) -{ -int ret; - -i2c_hid_dbg (ihid,"%s\n" , __func__); - -/* -* This prevents sending feature reports while the device is -* being reset. Otherwise we may lose the reset complete -* interrupt. -*/ -mutex_lock (&ihid->reset_lock); - - ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON ); -if (ret) - goto out_unlock; - - ret =i2c_hid_execute_reset (ihid); -if (ret) { -dev_err (&ihid->client->dev, -"failed to reset device: %d\n" , ret); -i2c_hid_set_power (ihid,I2C_HID_PWR_SLEEP ); - goto out_unlock; - } -/* At least some SIS devices need this after reset */ if (!(ihid->quirks &I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET )) ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON ); -out_unlock: +mutex_unlock (&ihid->reset_lock); +return ret; + +err_clear_reset: +clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); +i2c_hid_set_power (ihid,I2C_HID_PWR_SLEEP ); +err_unlock:mutex_unlock (&ihid->reset_lock);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1018/1424 HID: i2c-hid: Split i2c_hid_hwreset() in start() and finish() functions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
[ Upstream commit 96d3098db835d58649b73a5788898bd7672a319b ]
Split i2c_hid_hwreset() into:
i2c_hid_start_hwreset() which sends the PWR_ON and reset commands; and i2c_hid_finish_hwreset() which actually waits for the reset to complete.
This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows.
No functional changes intended.
Stable-dep-of: 8da0f0951dee ("HID: i2c-hid: Fix "(null)" output when reading report descriptor fails")
--- drivers/hid/i2c-hid/i2c-hid-core.c | 38 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-)
drivers/hid/i2c-hid/i2c-hid-core.c +28 -10
@@ -420,7 +420,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)return ret; } -static int i2c_hid_hwreset (struct i2c_hid *ihid) +static int i2c_hid_start_hwreset (struct i2c_hid *ihid) {size_t length =0 ;int ret;
@@ -432,11 +432,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid)* being reset. Otherwise we may lose the reset complete * interrupt. */ -mutex_lock (&ihid->reset_lock); +lockdep_assert_held (&ihid->reset_lock); ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON );if (ret) - goto err_unlock; +return ret;/* Prepare reset command. Command register goes first. */ *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -454,6 +454,18 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid) goto err_clear_reset; } +return 0 ; + +err_clear_reset: +clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); +i2c_hid_set_power (ihid,I2C_HID_PWR_SLEEP ); +return ret; +} + +static int i2c_hid_finish_hwreset (struct i2c_hid *ihid) +{ +int ret =0 ; +i2c_hid_dbg (ihid,"%s: waiting...\n" , __func__);if (ihid->quirks &I2C_HID_QUIRK_NO_IRQ_AFTER_RESET ) {
@@ -471,14 +483,11 @@ static int i2c_hid_hwreset(struct i2c_hid *ihid)if (!(ihid->quirks &I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET )) ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON ); -mutex_unlock (&ihid->reset_lock);return ret; err_clear_reset:clear_bit (I2C_HID_RESET_PENDING , &ihid->flags);i2c_hid_set_power (ihid,I2C_HID_PWR_SLEEP ); -err_unlock: -mutex_unlock (&ihid->reset_lock);return ret; }
@@ -722,7 +731,11 @@ static int i2c_hid_parse(struct hid_device *hid) }do { - ret =i2c_hid_hwreset (ihid); +mutex_lock (&ihid->reset_lock); + ret =i2c_hid_start_hwreset (ihid); +if (ret ==0 ) + ret =i2c_hid_finish_hwreset (ihid); +mutex_unlock (&ihid->reset_lock);if (ret)msleep (1000 ); }while (tries-- >0 && ret);
@@ -974,10 +987,15 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)* However some ALPS touchpads generate IRQ storm without reset, so * let's still reset them here. */ -if (ihid->quirks &I2C_HID_QUIRK_RESET_ON_RESUME ) - ret =i2c_hid_hwreset (ihid); -else +if (ihid->quirks &I2C_HID_QUIRK_RESET_ON_RESUME ) { +mutex_lock (&ihid->reset_lock); + ret =i2c_hid_start_hwreset (ihid); +if (ret ==0 ) + ret =i2c_hid_finish_hwreset (ihid); +mutex_unlock (&ihid->reset_lock); + }else { ret =i2c_hid_set_power (ihid,I2C_HID_PWR_ON ); + }if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1019/1424 HID: i2c-hid: Switch i2c_hid_parse() to goto style error handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
[ Upstream commit aa69d6974185e9f7a552ba982540a38e34f69690 ]
Switch i2c_hid_parse() to goto style error handling.
This is a preparation patch for removing the need for I2C_HID_QUIRK_NO_IRQ_AFTER_RESET by making i2c-hid behave more like Windows.
Note this changes the descriptor read error path to propagate the actual i2c_hid_read_register() error code (which is always negative) instead of hardcoding a -EIO return.
Stable-dep-of: 8da0f0951dee ("HID: i2c-hid: Fix "(null)" output when reading report descriptor fails")
--- drivers/hid/i2c-hid/i2c-hid-core.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
drivers/hid/i2c-hid/i2c-hid-core.c +6 -8
@@ -764,23 +764,21 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc, rsize);if (ret) {hid_err (hid,"reading report descriptor failed\n" ); -kfree (rdesc); -return -EIO ; + goto out; } }i2c_hid_dbg (ihid,"Report Descriptor: %*ph\n" , rsize, rdesc); ret =hid_parse_report (hid, rdesc, rsize); +if (ret) +dbg_hid ("parsing report descriptor failed\n" ); + +out:if (!use_override)kfree (rdesc); -if (ret) { -dbg_hid ("parsing report descriptor failed\n" ); -return ret; - } - -return 0 ; +return ret; }static int i2c_hid_start (struct hid_device *hid)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1020/1424 HID: i2c-hid: Move i2c_hid_finish_hwreset() to after reading the report-descriptor
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
[ Upstream commit af93a167eda90192563bce64c4bb989836afac1f ]
A recent bug made me look at Microsoft's i2c-hid docs again and I noticed the following:
"""
4. Issue a RESET (Host Initiated Reset) to the Device.
5. Retrieve report descriptor from the device.
Note: Steps 4 and 5 may be done in parallel to optimize for time on I²C. Since report descriptors are (a) static and (b) quite long, Windows 8 may issue a request for 5 while it is waiting for a response from the device on 4.
"""
Which made me think that maybe on some touchpads the reset ack is delayed till after the report descriptor is read ?
Testing a T-BAO Tbook Air 12.5 with a 0911:5288 (SIPODEV SP1064?) touchpad, for which the I2C_HID_QUIRK_NO_IRQ_AFTER_RESET quirk was first introduced, shows that reading the report descriptor before waiting for the reset helps with the missing reset IRQ. Now the reset does get acked properly, but the ack sometimes still does not happen unfortunately.
Still moving the wait for ack to after reading the report-descriptor, is probably a good idea, both to make i2c-hid's behavior closer to Windows as well as to speed up probing i2c-hid devices.
While at it drop the dbg_hid() for a malloc failure, malloc failures already get logged extensively by malloc itself.
Stable-dep-of: 8da0f0951dee ("HID: i2c-hid: Fix "(null)" output when reading report descriptor fails")
--- drivers/hid/i2c-hid/i2c-hid-core.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/hid/i2c-hid/i2c-hid-core.c +19 -10
@@ -716,11 +716,10 @@ static int i2c_hid_parse(struct hid_device *hid)struct i2c_client *client = hid->driver_data;struct i2c_hid *ihid =i2c_get_clientdata (client);struct i2c_hid_desc *hdesc = &ihid->hdesc; +char *rdesc =NULL , *use_override =NULL ;unsigned int rsize; -char *rdesc;int ret;int tries =3 ; -char *use_override;i2c_hid_dbg (ihid,"entering %s\n" , __func__);
@@ -730,18 +729,15 @@ static int i2c_hid_parse(struct hid_device *hid)return -EINVAL ; } +mutex_lock (&ihid->reset_lock);do { -mutex_lock (&ihid->reset_lock); ret =i2c_hid_start_hwreset (ihid); -if (ret ==0 ) - ret =i2c_hid_finish_hwreset (ihid); -mutex_unlock (&ihid->reset_lock);if (ret)msleep (1000 ); }while (tries-- >0 && ret);if (ret) -return ret; + goto abort_reset; use_override =i2c_hid_get_dmi_hid_report_desc_override (client->name, &rsize);
@@ -753,8 +749,8 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc =kzalloc (rsize,GFP_KERNEL );if (!rdesc) { -dbg_hid ("couldn't allocate rdesc memory\n" ); -return -ENOMEM ; + ret = -ENOMEM ; + goto abort_reset; }i2c_hid_dbg (ihid,"asking HID report descriptor\n" );
@@ -764,10 +760,23 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc, rsize);if (ret) {hid_err (hid,"reading report descriptor failed\n" ); - goto out; + goto abort_reset; } } +/* +* Windows directly reads the report-descriptor after sending reset +* and then waits for resets completion afterwards. Some touchpads +* actually wait for the report-descriptor to be read before signalling +* reset completion. +*/ + ret =i2c_hid_finish_hwreset (ihid); +abort_reset: +clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); +mutex_unlock (&ihid->reset_lock); +if (ret) + goto out; +i2c_hid_dbg (ihid,"Report Descriptor: %*ph\n" , rsize, rdesc); ret =hid_parse_report (hid, rdesc, rsize);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1021/1424 HID: i2c-hid: Revert to await reset ACK before reading report descriptor
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kenny Levinsen <[email protected]>
[ Upstream commit ea36bf1827462e4a52365bf8e3f7d1712c5d9600 ]
In af93a167eda9, i2c_hid_parse was changed to continue with reading the report descriptor before waiting for reset to be acknowledged.
This has lead to two regressions:
1. We fail to handle reset acknowledgment if it happens while reading the report descriptor. The transfer sets I2C_HID_READ_PENDING, which causes the IRQ handler to return without doing anything.
This affects both a Wacom touchscreen and a Sensel touchpad.
2. On a Sensel touchpad, reading the report descriptor this quickly after reset results in all zeroes or partial zeroes.
The issues were observed on the Lenovo Thinkpad Z16 Gen 2.
The change in question was made based on a Microsoft article[0] stating that Windows 8 *may* read the report descriptor in parallel with awaiting reset acknowledgment, intended as a slight reset performance optimization. Perhaps they only do this if reset is not completing quickly enough for their tastes?
As the code is not currently ready to read registers in parallel with a pending reset acknowledgment, and as reading quickly breaks the report descriptor on the Sensel touchpad, revert to waiting for reset acknowledgment before proceeding to read the report descriptor.
Stable-dep-of: 8da0f0951dee ("HID: i2c-hid: Fix "(null)" output when reading report descriptor fails")
--- drivers/hid/i2c-hid/i2c-hid-core.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-)
drivers/hid/i2c-hid/i2c-hid-core.c +8 -21
@@ -732,12 +732,15 @@ static int i2c_hid_parse(struct hid_device *hid)mutex_lock (&ihid->reset_lock);do { ret =i2c_hid_start_hwreset (ihid); -if (ret) +if (ret ==0 ) + ret =i2c_hid_finish_hwreset (ihid); +else msleep (1000 ); }while (tries-- >0 && ret); +mutex_unlock (&ihid->reset_lock);if (ret) - goto abort_reset; +return ret; use_override =i2c_hid_get_dmi_hid_report_desc_override (client->name, &rsize);
@@ -747,11 +750,8 @@ static int i2c_hid_parse(struct hid_device *hid)i2c_hid_dbg (ihid,"Using a HID report descriptor override\n" ); }else { rdesc =kzalloc (rsize,GFP_KERNEL ); - -if (!rdesc) { - ret = -ENOMEM ; - goto abort_reset; - } +if (!rdesc) +return -ENOMEM ;i2c_hid_dbg (ihid,"asking HID report descriptor\n" );
@@ -760,23 +760,10 @@ static int i2c_hid_parse(struct hid_device *hid) rdesc, rsize);if (ret) {hid_err (hid,"reading report descriptor failed\n" ); - goto abort_reset; + goto out; } } -/* -* Windows directly reads the report-descriptor after sending reset -* and then waits for resets completion afterwards. Some touchpads -* actually wait for the report-descriptor to be read before signalling -* reset completion. -*/ - ret =i2c_hid_finish_hwreset (ihid); -abort_reset: -clear_bit (I2C_HID_RESET_PENDING , &ihid->flags); -mutex_unlock (&ihid->reset_lock); -if (ret) - goto out; -i2c_hid_dbg (ihid,"Report Descriptor: %*ph\n" , rsize, rdesc); ret =hid_parse_report (hid, rdesc, rsize);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1022/1424 HID: i2c-hid: Fix "(null)" output when reading report descriptor fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ai Chao <[email protected]>
[ Upstream commit 8da0f0951deec9f0728ed2d9c54ded1c344b7542 ]
When i2c-hid fails to read the HID report descriptor during device initialization, the error message prints as:
hid (null): reading report descriptor failed
The HID device name is set in hid_add_device() after calling hdev->ll_driver->parse(), so when i2c_hid_parse() fails and calls hid_err(), the device name has not been set yet, resulting in "(null)" output.
Use dev_err(&client->dev, ...) instead of hid_err(hid, ...) because the I2C client device is fully initialized with a proper name, providing meaningful error messages for debugging.
Before: hid (null): reading report descriptor failed After: i2c_hid i2c-TPD0001:00: reading report descriptor failed
--- drivers/hid/i2c-hid/i2c-hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/i2c-hid/i2c-hid-core.c +1 -1
@@ -759,7 +759,7 @@ static int i2c_hid_parse(struct hid_device *hid) ihid->hdesc.wReportDescRegister, rdesc, rsize);if (ret) { -hid_err (hid,"reading report descriptor failed\n" ); +dev_err (&client->dev,"reading report descriptor failed\n" ); goto out; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1023/1424 HID: i2c-hid: goodix: Disable VDD on VDDIO enable failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Huang <[email protected]>
[ Upstream commit 8e2c560faea0220664169f7be4b498915ea1469f ]
If enabling VDDIO fails after VDD has been enabled, the power-up path returns without disabling VDD. This leaves the regulator enabled and its enable count unbalanced.
Disable VDD before returning the VDDIO error.
--- drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hid/i2c-hid/i2c-hid-of-goodix.c +3 -1
@@ -51,8 +51,10 @@ static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)return ret; ret =regulator_enable (ihid_goodix->vddio); -if (ret) +if (ret) { +regulator_disable (ihid_goodix->vdd);return ret; + }if (ihid_goodix->timings->post_power_delay_ms)msleep (ihid_goodix->timings->post_power_delay_ms);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1024/1424 HID: lg4ff: validate report length before fixed offsets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiancheng Huang <[email protected]>
[ Upstream commit be00988cce4ed44db1e61231d0ab71a64bab44cd ]
lg4ff_raw_event() rewrites fixed report offsets when combined pedals are enabled. It currently assumes that each product report contains every source and destination byte used by the rewrite.
Return without rewriting a short report before each product-specific access. Apply the same bound to the computed offset path.
--- drivers/hid/hid-lg4ff.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/hid/hid-lg4ff.c +8 -0
@@ -336,6 +336,8 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,if (entry->wdata.combine) {switch (entry->wdata.product_id) {case USB_DEVICE_ID_LOGITECH_WHEEL : +if (size <7 ) +return 0 ; rd[5 ] = rd[3 ]; rd[6 ] =0x7F ;return 1 ;
@@ -343,10 +345,14 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG :case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL :case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 : +if (size <6 ) +return 0 ; rd[4 ] = rd[3 ]; rd[5 ] =0x7F ;return 1 ;case USB_DEVICE_ID_LOGITECH_DFP_WHEEL : +if (size <7 ) +return 0 ; rd[5 ] = rd[4 ]; rd[6 ] =0x7F ;return 1 ;
@@ -366,6 +372,8 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report, }/* Compute a combined axis when wheel does not supply it */ +if (size <= offset +1 ) +return 0 ; rd[offset] = (0xFF + rd[offset] - rd[offset+1 ]) >>1 ; rd[offset+1 ] =0x7F ;return 1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1025/1424 perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit ab9c84d1cd59e6b3b73de34982a35a76e3a9b032 ]
thread_stack__br_sample() copies the wrap-around portion of the branch stack ring buffer with:
nr = min(ts->br_stack_pos, sz); memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
'nr' is correctly bounded to min(br_stack_pos, sz) but the memcpy uses the unbounded ts->br_stack_pos directly. When br_stack_pos exceeds the remaining destination space 'sz', this writes past the destination buffer.
Use 'nr' (the bounded value) in the memcpy size, matching the pattern of the first memcpy in the same function.
--- tools/perf/util/thread-stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/thread-stack.c +1 -1
@@ -642,7 +642,7 @@ void thread_stack__br_sample(struct thread *thread, int cpu, sz -= nr; be = &dst->entries[nr]; nr =min (ts->br_stack_pos, sz); -memcpy (be, &src->entries[0 ], bsz * ts->br_stack_pos); +memcpy (be, &src->entries[0 ], bsz * nr); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1026/1424 perf auxtrace: Fix queue grow overflow and old array leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 96fcc9ea5f18c083a1fa73da23afef7e953f7dca ]
auxtrace_queues__grow() has two bugs:
1. When idx is UINT_MAX, the caller passes new_nr_queues = idx + 1 = 0. The function skips growing (since any nr_queues >= 0), returns success, and the caller accesses queue_array[UINT_MAX] — an OOB heap write. Fix by rejecting new_nr_queues == 0 up front.
2. The function allocates a new queue_array via calloc and copies elements from the old array, but never frees the old array. Fix by saving the old pointer and freeing it after the copy.
--- tools/perf/util/auxtrace.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
tools/perf/util/auxtrace.c +10 -5
@@ -232,8 +232,12 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues, {unsigned int nr_queues = queues->nr_queues;struct auxtrace_queue *queue_array; +struct auxtrace_queue *old_array = queues->queue_array;unsigned int i; +if (!new_nr_queues) +return -EINVAL ; +if (!nr_queues) nr_queues =AUXTRACE_INIT_NR_QUEUES ;
@@ -248,16 +252,17 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,return -ENOMEM ;for (i =0 ; i < queues->nr_queues; i++) { -list_splice_tail (&queues->queue_array[i].head, +list_splice_tail (&old_array[i].head, &queue_array[i].head); - queue_array[i].tid = queues->queue_array[i].tid; - queue_array[i].cpu = queues->queue_array[i].cpu; - queue_array[i].set = queues->queue_array[i].set; - queue_array[i].priv = queues->queue_array[i].priv; + queue_array[i].tid = old_array[i].tid; + queue_array[i].cpu = old_array[i].cpu; + queue_array[i].set = old_array[i].set; + queue_array[i].priv = old_array[i].priv; } queues->nr_queues = nr_queues; queues->queue_array = queue_array; +free (old_array);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1027/1424 perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit c4362d5e1a5ed4ce2098798f655a636c4340fa20 ]
min_sz is set to sizeof(u64) * INTEL_PT_PER_CPU_MMAPS, but the code accesses auxtrace_info->priv[INTEL_PT_PER_CPU_MMAPS], which requires at least INTEL_PT_PER_CPU_MMAPS + 1 elements. A file with exactly min_sz bytes of priv data passes the size check but the access reads one u64 past the validated region.
Use (INTEL_PT_PER_CPU_MMAPS + 1) to ensure the highest accessed index is within bounds.
--- tools/perf/util/intel-pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/intel-pt.c +1 -1
@@ -4381,7 +4381,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event, struct perf_session *session) {struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; -size_t min_sz =sizeof (u64) *INTEL_PT_PER_CPU_MMAPS ; +size_t min_sz =sizeof (u64) * (INTEL_PT_PER_CPU_MMAPS +1 );struct intel_pt *pt;void *info_end;__u64 *info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1028/1424 perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit b9fb8225951ce27e62a2235a71f3ab01137aaec3 ]
Same pattern as the Intel PT fix: min_sz is set to sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE, but the code accesses auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE], which requires at least INTEL_BTS_SNAPSHOT_MODE + 1 elements.
Use (INTEL_BTS_SNAPSHOT_MODE + 1) to ensure the highest accessed index is within bounds.
--- tools/perf/util/intel-bts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/intel-bts.c +1 -1
@@ -858,7 +858,7 @@ int intel_bts_process_auxtrace_info(union perf_event *event, struct perf_session *session) {struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; -size_t min_sz =sizeof (u64) *INTEL_BTS_SNAPSHOT_MODE ; +size_t min_sz =sizeof (u64) * (INTEL_BTS_SNAPSHOT_MODE +1 );struct intel_bts *bts;int err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1029/1424 iio: light: tsl2772: fix ALS calibscale readback
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuanshen Cao <[email protected]>
[ Upstream commit ac75550ab5b5d73649bffea245c2075fd9249bd0 ]
The read_raw() implementation uses IIO_LIGHT to distinguish between the ambient light and proximity channels when handling IIO_CHAN_INFO_CALIBSCALE.
However, the ALS channel is registered as IIO_INTENSITY, while write_raw() correctly writes to IIO_INTENSITY. As a result, reading in_intensity0_calibscale incorrectly returns the proximity gain instead of the ALS gain.
This causes the following user-visible behavior:
- Writing in_intensity0_calibscale appears to have no effect because the readback reports the proximity gain.
- Writing in_proximity0_calibscale causes both in_proximity0_calibscale and in_intensity0_calibscale to report the same value.
Fix this by checking for IIO_INTENSITY in read_raw(), matching the channel definition and the existing write_raw() implementation.
--- drivers/iio/light/tsl2772.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/tsl2772.c +1 -1
@@ -1263,7 +1263,7 @@ static int tsl2772_read_raw(struct iio_dev *indio_dev, }break ;case IIO_CHAN_INFO_CALIBSCALE : -if (chan->type ==IIO_LIGHT ) +if (chan->type ==IIO_INTENSITY ) *val = tsl2772_als_gain[chip->settings.als_gain];else *val = tsl2772_prox_gain[chip->settings.prox_gain];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1030/1424 iio: light: isl29028: return zero in write_raw() on success
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Heon Jeon <[email protected]>
[ Upstream commit 55b75622829779223b9e32aa9600a8651d3e2df4 ]
isl29028_write_raw() returns the value of pm_runtime_put_autosuspend(), which is 1 if the device is already runtime suspended.
In that case write() on the sysfs attribute returns 1 instead of the number of bytes written. Make isl29028_write_raw() always return zero on success.
--- drivers/iio/light/isl29028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/isl29028.c +1 -1
@@ -414,7 +414,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,if (ret <0 )return ret; -return ret; +return 0 ; } static int isl29028_read_raw(struct iio_dev *indio_dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1031/1424 iio: light: tsl2583: return zero in write_raw() on success
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Heon Jeon <[email protected]>
[ Upstream commit 42e8791841e0677418a3ccc97fa5c22a1455f417 ]
tsl2583_write_raw() returns the value of pm_runtime_put_autosuspend(), which is 1 if the device is already runtime suspended.
In that case write() on the sysfs attribute returns 1 instead of the number of bytes written. Make tsl2583_write_raw() always return zero on success.
--- drivers/iio/light/tsl2583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/tsl2583.c +1 -1
@@ -800,7 +800,7 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,if (ret <0 )return ret; -return ret; +return 0 ; }static const struct iio_info tsl2583_info = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1032/1424 phonet: pep: do not write beyond optlen in getsockopt
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 77e5eb0e192aec6710c03ca8144582fd2af36ca4 ]
pep_getsockopt() clamps the reported length to the caller's buffer with min_t(), but then stores the value with put_user(val, (int __user *) optval), which always writes sizeof(int) bytes. A getsockopt() call with an optlen smaller than sizeof(int) thus reports the clamped length yet writes a full int, one to three bytes past the user buffer.
Write the value with copy_to_user() bounded by len, so at most optlen bytes are copied, matching the length reported back to userspace.
--- net/phonet/pep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/phonet/pep.c +1 -1
@@ -1116,7 +1116,7 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, len = min_t(unsigned int, sizeof(int), len);if (put_user (len, optlen))return -EFAULT ; -if (put_user (val, (int __user *) optval)) +if (copy_to_user (optval, &val, len))return -EFAULT ;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1033/1424 blk-cgroup: skip dying blkg in blkcg_activate_policy()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zheng Qixing <[email protected]>
[ Upstream commit 5e9220389920f33b6a804d50c548cd0cd1b04634 ]
When switching IO schedulers on a block device, blkcg_activate_policy() can race with concurrent blkcg deletion, leading to a use-after-free in rcu_accelerate_cbs.
T1: T2:
blkg_destroy
kill(&blkg->refcnt) // blkg->refcnt=1->0
blkg_release // call_rcu(__blkg_release)
...
blkg_free_workfn
->pd_free_fn(pd)elv_iosched_storeelevator_switch
...
iterate blkg listblkg_get(blkg) // blkg->refcnt=0->1
list_del_init(&blkg->q_node)
blkg_put(pinned_blkg) // blkg->refcnt=1->0blkg_release // call_rcu againrcu_accelerate_cbs // uaf
Fix this by checking hlist_unhashed(&blkg->blkcg_node) before getting a reference to the blkg. This is the same check used in blkg_destroy() to detect if a blkg has already been destroyed. If the blkg is already unhashed, skip processing it since it's being destroyed.
--- block/blk-cgroup.c | 2 ++ 1 file changed, 2 insertions(+)
block/blk-cgroup.c +2 -0
@@ -1586,6 +1586,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)if (blkg->pd[pol->plid])continue ; +if (hlist_unhashed (&blkg->blkcg_node)) +continue ;/* If prealloc matches, use it; otherwise try GFP_NOWAIT */ if (blkg == pinned_blkg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1034/1424 block/blk-stat: drain per-cpu callback stats over possible CPUs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 9d617828cfc4d9a4d385daa2cd61f9db0592c53f ]
blk_stat_timer_fn() sums and resets a callback's per-cpu buckets using for_each_online_cpu(). A CPU that goes offline with pending samples is skipped, so its samples are neither accumulated into the window nor cleared; they sit in the bucket until the CPU comes back online, at which point the stale values are flushed into whatever window is then running.
This silently corrupts the latency picture that consumers (notably writeback throttling via wbt, and blk-mq latency tracking) base decisions on around CPU hotplug: under-counting while the CPU is offline, then a burst of stale data on re-online.
--- block/blk-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/blk-stat.c +1 -1
@@ -86,7 +86,7 @@ static void blk_stat_timer_fn(struct timer_list *t)for (bucket =0 ; bucket < cb->buckets; bucket++)blk_rq_stat_init (&cb->stat[bucket]); -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct blk_rq_stat *cpu_stat; cpu_stat =per_cpu_ptr (cb->cpu_stat, cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1035/1424 block/blk-iocost: collect per-cpu latency stats over possible CPUs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 4e050c5b92c1600415b2cd452583e543036f3d73 ]
ioc_lat_stat() walks ioc->pcpu_stat with for_each_online_cpu() to compute missed-ppm and rq_wait deltas. An offlined CPU is skipped, so its delta is dropped from the period and its last_* watermark is not advanced; on re-online the next collection sees a delta spanning the whole offline interval, corrupting the latency/vrate picture.
--- block/blk-iocost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/blk-iocost.c +1 -1
@@ -1603,7 +1603,7 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_pu64 rq_wait_ns =0 ;int cpu, rw; -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct ioc_pcpu_stat *stat =per_cpu_ptr (ioc->pcpu_stat, cpu);u64 this_rq_wait_ns;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1036/1424 block/kyber-iosched: flush per-cpu latency buckets over possible CPUs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 482fc257de95ab181688e9d1dfcc6b6a58857b1e ]
kyber_timer_fn() sums the per-cpu latency histograms with for_each_online_cpu(). A CPU that goes offline mid-interval leaves its bucket un-flushed; the samples are lost from the current decision and re-appear (stale) when the CPU is onlined again.
--- block/kyber-iosched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/kyber-iosched.c +1 -1
@@ -282,7 +282,7 @@ static void kyber_timer_fn(struct timer_list *t)bool bad = false;/* Sum all of the per-cpu latency histograms. */ -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct kyber_cpu_latency *cpu_latency; cpu_latency =per_cpu_ptr (kqd->cpu_latency, cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1037/1424 ublk: check for ublk_unmap_io() returning 0
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Caleb Sander Mateos <[email protected]>
[ Upstream commit 24fd3706178f1ae5501fd1ff9036e170ed0665ba ]
If the userspace ublk server passes an unmapped address as the data buffer for a completed ublk read, ublk_unmap_io() will return 0 indicating no bytes could be copied. Currently, this will result in calling blk_update_request() with nr_bytes=0, which doesn't seem supported. Fail the I/O with BLK_STS_IOERR in this case instead.
--- drivers/block/ublk_drv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/block/ublk_drv.c +7 -1
@@ -1099,8 +1099,14 @@ static inline void __ublk_complete_rq(struct request *req)* * Re-read simply for this unlikely case. */ -if (unlikely (unmapped_bytes < io->res)) +if (unlikely (unmapped_bytes < io->res)) { +if (unlikely (!unmapped_bytes)) { + res =BLK_STS_IOERR ; + goto exit; + } + io->res = unmapped_bytes; + }/* * Run bio->bi_end_io() with softirqs disabled. If the final fput
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1038/1424 lib/string: fix memchr_inv() for large ranges
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
[ Upstream commit c04cffb8c51618538f0c05c478a931eb6e1a806b ]
memchr_inv() takes a size_t length but counts 8 byte words in an unsigned int. At 32GiB that count wraps, so the scan can quietly miss most of the range.
Use size_t for the word count.
--- lib/string.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/string.c +2 -1
@@ -844,7 +844,8 @@ void *memchr_inv(const void *start, int c, size_t bytes) {u8 value = c;u64 value64; -unsigned int words, prefix; +size_t words; +unsigned int prefix;if (bytes <=16 )return check_bytes8 (start, value, bytes);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1039/1424 pps: dont try to wait for negative timeouts in PPS_FETCH
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Calvin Owens <[email protected]>
[ Upstream commit 45217e98987a87ff2372386dbf82fd5325db28ea ]
If userspace passes a negative timeout to PPS_FETCH, it triggers a kernel splat from schedule_timeout():
schedule_timeout: wrong timeout value fffffffffff0bfb4
CPU: 17 UID: 0 PID: 4720 Comm: a.out Not tainted 7.1.0-rc5-x86-kvm-00150-g331d97e36b37 #1 PREEMPT_RT
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-20240910_120124-localhost 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x4b/0x70
schedule_timeout+0xb7/0xe0
pps_cdev_pps_fetch.isra.0+0x93/0x150
pps_cdev_ioctl+0x70/0x310
__x64_sys_ioctl+0x7b/0xc0
do_syscall_64+0xb6/0xfc0
entry_SYSCALL_64_after_hwframe+0x4b/0x53Here is a trivial reproducer that works with the PPS_CLIENT_KTIMER test device enabled in the kernel:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/pps.h>
#include <err.h>
int main() {
struct pps_fdata fdata;
int fd;
fd = open("/dev/pps0", O_RDWR);
if (fd == -1)
err(1, "Failed to open /dev/pps0");
fdata.timeout.sec = -1;
fdata.timeout.nsec = 0;
if (ioctl(fd, PPS_FETCH, &fdata))
err(2, "PPS_FETCH failed");
close(fd);
return 0;
}Sashiko imagines this to be some sort of security problem, which is obviously really silly. But I think it is still worth fixing, so buggy userspace code can't trigger the splat.
Silence the splat by using timespec64_to_jiffies(), which hard limits the timeout to LONG_MAX jiffies. To be safe, explicitly preserve the -ETIMEDOUT return value userspace sees today if it passes a negative timeout.
If you really squint, this is still a slight behavior change in that there are "denormalized" combinations of tv_sec and tv_nsec which used to work but will now return -ETIMEDOUT. I can't imagine anybody will care about that...
--- drivers/pps/pps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/pps/pps.c +8 -2
@@ -63,13 +63,19 @@ static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata) err =wait_event_interruptible (pps->queue, ev != pps->last_ev); else { +struct timespec64 ts;unsigned long ticks;dev_dbg (&pps->dev,"timeout %lld.%09d\n" , (long long ) fdata->timeout.sec, fdata->timeout.nsec); - ticks = fdata->timeout.sec *HZ ; - ticks += fdata->timeout.nsec / (NSEC_PER_SEC /HZ ); + +if (fdata->timeout.sec <0 ) +return -ETIMEDOUT ; + + ts.tv_sec = fdata->timeout.sec; + ts.tv_nsec = fdata->timeout.nsec; + ticks =timespec64_to_jiffies (&ts);if (ticks !=0 ) { err = wait_event_interruptible_timeout(
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1040/1424 pps: clients: gpio: Bypass edges direction check when not needed
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bastien Curutchet <[email protected]>
[ Upstream commit a01f6287c244f35eeec11ca932d09061181eed8c ]
In the IRQ handler, the GPIO's state is read to verify the direction of the edge that triggered the interruption before generating the PPS event. If a pulse is too short, the GPIO line can reach back its original state before this verification and the PPS event is lost.
This check is needed when info->capture_clear is set because it needs interruptions on both rising and falling edges. When info->capture_clear is not set, interruption is triggered by one edge only so this check can be omitted.
Add a warning if irq_handler is left without triggering any PPS event. Bypass the edge's direction verification when info->capture_clear is not set.
Stable-dep-of: b899e0279f90 ("pps-gpio: remove dead capture_clear code")
--- drivers/pps/clients/pps-gpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/pps/clients/pps-gpio.c +5 -1
@@ -52,7 +52,9 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) info = data; - rising_edge =gpiod_get_value (info->gpio_pin); +/* Small trick to bypass the check on edge's direction when capture_clear is unset */ + rising_edge = info->capture_clear ? +gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge;if ((rising_edge && !info->assert_falling_edge) || (!rising_edge && info->assert_falling_edge))pps_event (info->pps, &ts,PPS_CAPTUREASSERT , data);
@@ -60,6 +62,8 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) ((rising_edge && info->assert_falling_edge) || (!rising_edge && !info->assert_falling_edge)))pps_event (info->pps, &ts,PPS_CAPTURECLEAR , data); + else + dev_warn_ratelimited(&info->pps->dev, "IRQ did not trigger any PPS event\n");return IRQ_HANDLED ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1041/1424 pps: pps-gpio: split IRQ handler into hardirq timestamper + threaded handler
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Byczkowski <[email protected]>
[ Upstream commit 93781560b2fdd26fa8499d64db8a95a07e1dc902 ]
Split the pps-gpio interrupt handler into a primary (hardirq) handler that captures the PPS timestamp at interrupt entry, and a threaded handler that processes the event. This produces the same two-part handler structure on both PREEMPT_RT and non-RT kernels.
On non-RT kernels the threaded portion runs immediately after the primary, with no behavioral change compared to the previous single-handler implementation.
On PREEMPT_RT, where interrupt handlers are force-threaded by default, the previous single-handler implementation captured the timestamp inside the threaded portion, after IRQ-thread scheduling delay. With the split, the timestamp is captured in true hardirq context as it is on non-RT kernels, eliminating a significant source of PPS jitter on RT systems.
Stable-dep-of: b899e0279f90 ("pps-gpio: remove dead capture_clear code")
--- drivers/pps/clients/pps-gpio.c | 37 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-)
drivers/pps/clients/pps-gpio.c +25 -12
@@ -35,33 +35,44 @@ struct pps_gpio_device_data {bool capture_clear;unsigned int echo_active_ms;/* PPS echo active duration */ unsigned long echo_timeout;/* timer timeout value in jiffies */ +struct pps_event_time ts;/* timestamp captured in hardirq */ };/* * Report the PPS event */ -static irqreturn_t pps_gpio_irq_handler (int irq,void *data) +/* +* Primary hardirq handler -- runs in hardirq context even on PREEMPT_RT. +* Only captures the timestamp; all other work is deferred to the thread. +*/ +static irqreturn_t pps_gpio_irq_hardirq (int irq,void *data) { -const struct pps_gpio_device_data *info; -struct pps_event_time ts; -int rising_edge; +struct pps_gpio_device_data *info = data; + +pps_get_ts (&info->ts); -/* Get the time stamp first */ -pps_get_ts (&ts); +return IRQ_WAKE_THREAD ; +} - info = data; +/* +* Threaded handler -- processes the PPS event using the timestamp +* captured in hardirq context above. +*/ +static irqreturn_t pps_gpio_irq_thread (int irq,void *data) +{ +struct pps_gpio_device_data *info = data; +int rising_edge; -/* Small trick to bypass the check on edge's direction when capture_clear is unset */ rising_edge = info->capture_clear ?gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge;if ((rising_edge && !info->assert_falling_edge) || (!rising_edge && info->assert_falling_edge)) -pps_event (info->pps, &ts,PPS_CAPTUREASSERT , data); +pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data);else if (info->capture_clear && ((rising_edge && info->assert_falling_edge) || (!rising_edge && !info->assert_falling_edge))) -pps_event (info->pps, &ts,PPS_CAPTURECLEAR , data); +pps_event (info->pps, &info->ts,PPS_CAPTURECLEAR , data);else dev_warn_ratelimited (&info->pps->dev,"IRQ did not trigger any PPS event\n" );
@@ -210,8 +221,10 @@ static int pps_gpio_probe(struct platform_device *pdev) }/* register IRQ interrupt handler */ - ret =request_irq (data->irq, pps_gpio_irq_handler, -get_irqf_trigger_flags (data), data->info.name, data); + ret =request_threaded_irq (data->irq, + pps_gpio_irq_hardirq, pps_gpio_irq_thread, +get_irqf_trigger_flags (data) |IRQF_ONESHOT , + data->info.name, data);if (ret) {pps_unregister_source (data->pps);dev_err (dev,"failed to acquire IRQ %d\n" , data->irq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1042/1424 pps-gpio: remove dead capture_clear code
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Calvin Owens <[email protected]>
[ Upstream commit b899e0279f90c3ce4099d68b989dd27861cc5c4f ]
The capture_clear field is never set, and all code conditional on it being set has been unreachable since the platform data logic was removed from pps-gpio in ee89646619ba ("pps: clients: gpio: Get rid of legacy platform data").
I think the only logical thing to do here is to remove it all, since no in-tree code ever actually used it in the first place, and it has been completely dead code for over five years (since v5.13).
Sashiko asked some questions about the gpiod_get_value() call which caused me to look deeper and figure this out, but it did not actually notice capture_clear is never set.
--- drivers/pps/clients/pps-gpio.c | 37 ++++------------------------------ 1 file changed, 4 insertions(+), 33 deletions(-)
drivers/pps/clients/pps-gpio.c +4 -33
@@ -32,7 +32,6 @@ struct pps_gpio_device_data {struct gpio_desc *echo_pin;struct timer_list echo_timer;/* timer to reset echo active state */ bool assert_falling_edge; -bool capture_clear;unsigned int echo_active_ms;/* PPS echo active duration */ unsigned long echo_timeout;/* timer timeout value in jiffies */ struct pps_event_time ts;/* timestamp captured in hardirq */
@@ -62,19 +61,8 @@ static irqreturn_t pps_gpio_irq_hardirq(int irq, void *data)static irqreturn_t pps_gpio_irq_thread (int irq,void *data) {struct pps_gpio_device_data *info = data; -int rising_edge; - - rising_edge = info->capture_clear ? -gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge; -if ((rising_edge && !info->assert_falling_edge) || - (!rising_edge && info->assert_falling_edge)) -pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data); -else if (info->capture_clear && - ((rising_edge && info->assert_falling_edge) || - (!rising_edge && !info->assert_falling_edge))) -pps_event (info->pps, &info->ts,PPS_CAPTURECLEAR , data); -else -dev_warn_ratelimited (&info->pps->dev,"IRQ did not trigger any PPS event\n" ); + +pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data);return IRQ_HANDLED ; }
@@ -90,11 +78,6 @@ static void pps_gpio_echo(struct pps_device *pps, int event, void *data)if (pps->params.mode &PPS_ECHOASSERT )gpiod_set_value (info->echo_pin,1 );break ; - -case PPS_CAPTURECLEAR : -if (pps->params.mode &PPS_ECHOCLEAR ) -gpiod_set_value (info->echo_pin,1 ); -break ; }/* fire the timer */
@@ -156,15 +139,8 @@ static int pps_gpio_setup(struct device *dev)static unsigned long get_irqf_trigger_flags (const struct pps_gpio_device_data *data) { -unsigned long flags = data->assert_falling_edge ? -IRQF_TRIGGER_FALLING :IRQF_TRIGGER_RISING ; - -if (data->capture_clear) { - flags |= ((flags &IRQF_TRIGGER_RISING ) ? -IRQF_TRIGGER_FALLING :IRQF_TRIGGER_RISING ); - } - -return flags; +return data->assert_falling_edge ?IRQF_TRIGGER_FALLING : +IRQF_TRIGGER_RISING ; }static int pps_gpio_probe (struct platform_device *pdev)
@@ -197,9 +173,6 @@ static int pps_gpio_probe(struct platform_device *pdev)/* initialize PPS specific parts of the bookkeeping data structure. */ data->info.mode =PPS_CAPTUREASSERT |PPS_OFFSETASSERT |PPS_ECHOASSERT |PPS_CANWAIT |PPS_TSFMT_TSPEC ; -if (data->capture_clear) - data->info.mode |=PPS_CAPTURECLEAR |PPS_OFFSETCLEAR | -PPS_ECHOCLEAR ; data->info.owner =THIS_MODULE ;snprintf (data->info.name,PPS_MAX_NAME_LEN -1 ,"%s.%d" , pdev->name, pdev->id);
@@ -211,8 +184,6 @@ static int pps_gpio_probe(struct platform_device *pdev)/* register PPS source */ pps_default_params =PPS_CAPTUREASSERT |PPS_OFFSETASSERT ; -if (data->capture_clear) - pps_default_params |=PPS_CAPTURECLEAR |PPS_OFFSETCLEAR ; data->pps =pps_register_source (&data->info, pps_default_params);if (IS_ERR (data->pps)) { dev_err(dev, "failed to register IRQ %d as PPS source\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1043/1424 rapidio: clear mport->net when rio_add_net() fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit b74030fbf187b43c1f85b66a7082e9946511cb5d ]
rio_alloc_net() stores the newly allocated rio_net in mport->net before rio_scan_alloc_net() registers the device.
If rio_add_net() fails, rio_scan_alloc_net() drops the device reference with put_device(), which releases the rio_net through the device release callback. However, mport->net is left pointing at the freed object.
A later mport unregister path can then dereference the dangling mport->net pointer and may try to free the same rio_net again.
Clear mport->net in the rio_add_net() failure path, matching the cleanup done for the destID table allocation failure path.
--- drivers/rapidio/rio-scan.c | 1 + 1 file changed, 1 insertion(+)
drivers/rapidio/rio-scan.c +1 -0
@@ -874,6 +874,7 @@ static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport, net->dev.release = rio_scan_release_dev;if (rio_add_net (net)) {put_device (&net->dev); + mport->net =NULL ; net =NULL ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1044/1424 fat: release buffer head after rebuilding parent
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 83e98dbf19ab64e8528e101e20f8d50e1aaa68a8 ]
fat_scan_logstart() leaves the matching directory entry's buffer head in sinfo.bh for the caller to release, just like fat_scan().
fat_rebuild_parent() uses the directory entry to rebuild the parent inode for the nostale_ro NFS export path, but does not release sinfo.bh after a successful scan. Release it once fat_build_inode() has consumed the directory entry data.
--- fs/fat/nfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/fat/nfs.c +3 -1
@@ -250,8 +250,10 @@ struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart)MSDOS_I (dummy_grand_parent)->i_pos =-1 ; } -if (!fat_scan_logstart (dummy_grand_parent, clus_to_match, &sinfo)) +if (!fat_scan_logstart (dummy_grand_parent, clus_to_match, &sinfo)) { parent =fat_build_inode (sb, sinfo.de, sinfo.i_pos); +brelse (sinfo.bh); + }brelse (parent_bh);iput (dummy_grand_parent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1045/1424 drm/omap: dsi: Do not copy isr table
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andreas Kemnade <[email protected]>
[ Upstream commit 97c03b32b28a9f7f13f768f2b06e1eaafe850e66 ]
To be able to unregister stuff from isrs, the corresponding table was copied. Nobody seems to unregister stuff that way, so it does not help. But there are stack-allocated objects passed to these isrs giving chances of UAF of these objects if irqs are unregistered while they are handled, so better do not copy that table.
--- drivers/gpu/drm/omapdrm/dss/dsi.c | 7 +------ drivers/gpu/drm/omapdrm/dss/dsi.h | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-)
drivers/gpu/drm/omapdrm/dss/dsi.c +1 -6
@@ -455,15 +455,10 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)del_timer (&dsi->te_timer);#endif -/* make a copy and unlock, so that isrs can unregister -* themselves */ -memcpy (&dsi->isr_tables_copy, &dsi->isr_tables, -sizeof (dsi->isr_tables)); +dsi_handle_isrs (&dsi->isr_tables, irqstatus, vcstatus, ciostatus);spin_unlock (&dsi->irq_lock); -dsi_handle_isrs (&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus); -dsi_handle_irq_errors (dsi, irqstatus, vcstatus, ciostatus);dsi_collect_irq_stats (dsi, irqstatus, vcstatus, ciostatus);
drivers/gpu/drm/omapdrm/dss/dsi.h +0 -2
@@ -379,8 +379,6 @@ struct dsi_data {spinlock_t irq_lock;struct dsi_isr_tables isr_tables; -/* space for a copy used by the interrupt handler */ -struct dsi_isr_tables isr_tables_copy;int update_vc;#ifdef DSI_PERF_MEASURE
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1046/1424 remoteproc: Move resource table data structure to its own header
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 0590420c2f90de497d342c9a41a618f46f4d09ab ]
The resource table data structure has traditionally been associated with the remoteproc framework, where the resource table is included as a section within the remote processor firmware binary. However, it is also possible to obtain the resource table through other means—such as from a reserved memory region populated by the boot firmware, statically maintained driver data, or via a secure SMC call—when it is not embedded in the firmware.
There are multiple Qualcomm remote processors (e.g., Venus, Iris, GPU, etc.) in the upstream kernel that do not use the remoteproc framework to manage their lifecycle for various reasons.
When Linux is running at EL2, similar to the Qualcomm PAS driver (qcom_q6v5_pas.c), client drivers for subsystems like video and GPU may also want to use the resource table SMC call to retrieve and map resources before they are used by the remote processor.
In such cases, the resource table data structure is no longer tightly coupled with the remoteproc headers. Client drivers that do not use the remoteproc framework should still be able to parse the resource table obtained through alternative means. Therefore, there is a need to decouple the resource table definitions from the remoteproc headers.
Stable-dep-of: bb840ea69347 ("remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()")
--- include/linux/remoteproc.h | 269 +------------------------------- include/linux/rsc_table.h | 306 +++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 268 deletions(-) create mode 100644 include/linux/rsc_table.h
include/linux/remoteproc.h +1 -268
@@ -43,274 +43,7 @@#include <linux/completion.h> #include <linux/idr.h> #include <linux/of.h> - -/** -* struct resource_table - firmware resource table header -* @ver: version number -* @num: number of resource entries -* @reserved: reserved (must be zero) -* @offset: array of offsets pointing at the various resource entries -* -* A resource table is essentially a list of system resources required -* by the remote processor. It may also include configuration entries. -* If needed, the remote processor firmware should contain this table -* as a dedicated ".resource_table" ELF section. -* -* Some resources entries are mere announcements, where the host is informed -* of specific remoteproc configuration. Other entries require the host to -* do something (e.g. allocate a system resource). Sometimes a negotiation -* is expected, where the firmware requests a resource, and once allocated, -* the host should provide back its details (e.g. address of an allocated -* memory region). -* -* The header of the resource table, as expressed by this structure, -* contains a version number (should we need to change this format in the -* future), the number of available resource entries, and their offsets -* in the table. -* -* Immediately following this header are the resource entries themselves, -* each of which begins with a resource entry header (as described below). -*/ -struct resource_table { -u32 ver; -u32 num; -u32 reserved[2 ]; -u32 offset[]; -} __packed; - -/** -* struct fw_rsc_hdr - firmware resource entry header -* @type: resource type -* @data: resource data -* -* Every resource entry begins with a 'struct fw_rsc_hdr' header providing -* its @type. The content of the entry itself will immediately follow -* this header, and it should be parsed according to the resource type. -*/ -struct fw_rsc_hdr { -u32 type; -u8 data[]; -} __packed; - -/** -* enum fw_resource_type - types of resource entries -* -* @RSC_CARVEOUT: request for allocation of a physically contiguous -* memory region. -* @RSC_DEVMEM: request to iommu_map a memory-based peripheral. -* @RSC_TRACE: announces the availability of a trace buffer into which -* the remote processor will be writing logs. -* @RSC_VDEV: declare support for a virtio device, and serve as its -* virtio header. -* @RSC_LAST: just keep this one at the end of standard resources -* @RSC_VENDOR_START: start of the vendor specific resource types range -* @RSC_VENDOR_END: end of the vendor specific resource types range -* -* For more details regarding a specific resource type, please see its -* dedicated structure below. -* -* Please note that these values are used as indices to the rproc_handle_rsc -* lookup table, so please keep them sane. Moreover, @RSC_LAST is used to -* check the validity of an index before the lookup table is accessed, so -* please update it as needed. -*/ -enum fw_resource_type { -RSC_CARVEOUT =0 , -RSC_DEVMEM =1 , -RSC_TRACE =2 , -RSC_VDEV =3 , -RSC_LAST =4 , -RSC_VENDOR_START =128 , -RSC_VENDOR_END =512 , -}; - -#define FW_RSC_ADDR_ANY (-1) - -/** -* struct fw_rsc_carveout - physically contiguous memory request -* @da: device address -* @pa: physical address -* @len: length (in bytes) -* @flags: iommu protection flags -* @reserved: reserved (must be zero) -* @name: human-readable name of the requested memory region -* -* This resource entry requests the host to allocate a physically contiguous -* memory region. -* -* These request entries should precede other firmware resource entries, -* as other entries might request placing other data objects inside -* these memory regions (e.g. data/code segments, trace resource entries, ...). -* -* Allocating memory this way helps utilizing the reserved physical memory -* (e.g. CMA) more efficiently, and also minimizes the number of TLB entries -* needed to map it (in case @rproc is using an IOMMU). Reducing the TLB -* pressure is important; it may have a substantial impact on performance. -* -* If the firmware is compiled with static addresses, then @da should specify -* the expected device address of this memory region. If @da is set to -* FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then -* overwrite @da with the dynamically allocated address. -* -* We will always use @da to negotiate the device addresses, even if it -* isn't using an iommu. In that case, though, it will obviously contain -* physical addresses. -* -* Some remote processors needs to know the allocated physical address -* even if they do use an iommu. This is needed, e.g., if they control -* hardware accelerators which access the physical memory directly (this -* is the case with OMAP4 for instance). In that case, the host will -* overwrite @pa with the dynamically allocated physical address. -* Generally we don't want to expose physical addresses if we don't have to -* (remote processors are generally _not_ trusted), so we might want to -* change this to happen _only_ when explicitly required by the hardware. -* -* @flags is used to provide IOMMU protection flags, and @name should -* (optionally) contain a human readable name of this carveout region -* (mainly for debugging purposes). -*/ -struct fw_rsc_carveout { -u32 da; -u32 pa; -u32 len; -u32 flags; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_devmem - iommu mapping request -* @da: device address -* @pa: physical address -* @len: length (in bytes) -* @flags: iommu protection flags -* @reserved: reserved (must be zero) -* @name: human-readable name of the requested region to be mapped -* -* This resource entry requests the host to iommu map a physically contiguous -* memory region. This is needed in case the remote processor requires -* access to certain memory-based peripherals; _never_ use it to access -* regular memory. -* -* This is obviously only needed if the remote processor is accessing memory -* via an iommu. -* -* @da should specify the required device address, @pa should specify -* the physical address we want to map, @len should specify the size of -* the mapping and @flags is the IOMMU protection flags. As always, @name may -* (optionally) contain a human readable name of this mapping (mainly for -* debugging purposes). -* -* Note: at this point we just "trust" those devmem entries to contain valid -* physical addresses, but this isn't safe and will be changed: eventually we -* want remoteproc implementations to provide us ranges of physical addresses -* the firmware is allowed to request, and not allow firmwares to request -* access to physical addresses that are outside those ranges. -*/ -struct fw_rsc_devmem { -u32 da; -u32 pa; -u32 len; -u32 flags; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_trace - trace buffer declaration -* @da: device address -* @len: length (in bytes) -* @reserved: reserved (must be zero) -* @name: human-readable name of the trace buffer -* -* This resource entry provides the host information about a trace buffer -* into which the remote processor will write log messages. -* -* @da specifies the device address of the buffer, @len specifies -* its size, and @name may contain a human readable name of the trace buffer. -* -* After booting the remote processor, the trace buffers are exposed to the -* user via debugfs entries (called trace0, trace1, etc..). -*/ -struct fw_rsc_trace { -u32 da; -u32 len; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_vdev_vring - vring descriptor entry -* @da: device address -* @align: the alignment between the consumer and producer parts of the vring -* @num: num of buffers supported by this vring (must be power of two) -* @notifyid: a unique rproc-wide notify index for this vring. This notify -* index is used when kicking a remote processor, to let it know that this -* vring is triggered. -* @pa: physical address -* -* This descriptor is not a resource entry by itself; it is part of the -* vdev resource type (see below). -* -* Note that @da should either contain the device address where -* the remote processor is expecting the vring, or indicate that -* dynamically allocation of the vring's device address is supported. -*/ -struct fw_rsc_vdev_vring { -u32 da; -u32 align; -u32 num; -u32 notifyid; -u32 pa; -} __packed; - -/** -* struct fw_rsc_vdev - virtio device header -* @id: virtio device id (as in virtio_ids.h) -* @notifyid: a unique rproc-wide notify index for this vdev. This notify -* index is used when kicking a remote processor, to let it know that the -* status/features of this vdev have changes. -* @dfeatures: specifies the virtio device features supported by the firmware -* @gfeatures: a place holder used by the host to write back the -* negotiated features that are supported by both sides. -* @config_len: the size of the virtio config space of this vdev. The config -* space lies in the resource table immediate after this vdev header. -* @status: a place holder where the host will indicate its virtio progress. -* @num_of_vrings: indicates how many vrings are described in this vdev header -* @reserved: reserved (must be zero) -* @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. -* -* This resource is a virtio device header: it provides information about -* the vdev, and is then used by the host and its peer remote processors -* to negotiate and share certain virtio properties. -* -* By providing this resource entry, the firmware essentially asks remoteproc -* to statically allocate a vdev upon registration of the rproc (dynamic vdev -* allocation is not yet supported). -* -* Note: -* 1. unlike virtualization systems, the term 'host' here means -* the Linux side which is running remoteproc to control the remote -* processors. We use the name 'gfeatures' to comply with virtio's terms, -* though there isn't really any virtualized guest OS here: it's the host -* which is responsible for negotiating the final features. -* Yeah, it's a bit confusing. -* -* 2. immediately following this structure is the virtio config space for -* this vdev (which is specific to the vdev; for more info, read the virtio -* spec). The size of the config space is specified by @config_len. -*/ -struct fw_rsc_vdev { -u32 id; -u32 notifyid; -u32 dfeatures; -u32 gfeatures; -u32 config_len; -u8 status; -u8 num_of_vrings; -u8 reserved[2 ]; -struct fw_rsc_vdev_vring vring[]; -} __packed; +#include <linux/rsc_table.h> struct rproc ;
include/linux/rsc_table.h new file +306 -0
306 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1047/1424 remoteproc: use rsc_table_for_each_entry() in rproc_handle_resources()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 49abb5d6e1ac8169cdfc0c3aa4408e0d90ee5696 ]
Replace the open-coded resource table iteration loop in rproc_handle_resources() with the rsc_table_for_each_entry() helper.
The remoteproc-specific dispatch logic (vendor resource handling via rproc_handle_rsc(), RSC_LAST bounds check, handler table lookup) is moved into a local callback rproc_handle_rsc_entry(), keeping the iteration mechanics in one canonical place.
The callback receives the payload offset within the table so that handlers which write back into the resource table (e.g. rproc_handle_carveout() recording a dynamically allocated address via rsc_offset) continue to work correctly.
No functional change.
Stable-dep-of: bb840ea69347 ("remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()")
--- drivers/remoteproc/remoteproc_core.c | 81 +++++++++++++--------------- include/linux/rsc_table.h | 53 ++++++++++++++++++ 2 files changed, 91 insertions(+), 43 deletions(-)
drivers/remoteproc/remoteproc_core.c +38 -43
@@ -1015,60 +1015,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_VDEV] = rproc_handle_vdev, }; -/* handle firmware resource entries before booting the remote processor */ -static int rproc_handle_resources (struct rproc *rproc, -rproc_handle_resource_t handlers[RSC_LAST ]) +struct rproc_rsc_cb_data { +struct rproc *rproc; +rproc_handle_resource_t *handlers; +}; + +static int rproc_handle_rsc_entry (u32 type,void *rsc,int offset, +int avail,void *data) { +struct rproc_rsc_cb_data *d = data; +struct rproc *rproc = d->rproc;struct device *dev = &rproc->dev;rproc_handle_resource_t handler; -int ret =0 , i; - -if (!rproc->table_ptr) -return 0 ; +int ret; -for (i =0 ; i < rproc->table_ptr->num; i++) { -int offset = rproc->table_ptr->offset[i]; -struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; -int avail = rproc->table_sz - offset -sizeof (*hdr); -void *rsc = (void *)hdr +sizeof (*hdr); +dev_dbg (dev,"rsc: type %d\n" , type); -/* make sure table isn't truncated */ -if (avail <0 ) { -dev_err (dev,"rsc table is truncated\n" ); -return -EINVAL ; - } - -dev_dbg (dev,"rsc: type %d\n" , hdr->type); +if (type >=RSC_VENDOR_START && type <=RSC_VENDOR_END ) { + ret =rproc_handle_rsc (rproc, type, rsc, offset, avail); +if (ret ==RSC_HANDLED ) +return 0 ; +if (ret <0 ) +return ret; +dev_warn (dev,"unsupported vendor resource %d\n" , type); +return 0 ; + } -if (hdr->type >=RSC_VENDOR_START && - hdr->type <=RSC_VENDOR_END ) { - ret =rproc_handle_rsc (rproc, hdr->type, rsc, - offset +sizeof (*hdr), avail); -if (ret ==RSC_HANDLED ) -continue ; -else if (ret <0 ) -break ; +if (type >=RSC_LAST ) { +dev_warn (dev,"unsupported resource %d\n" , type); +return 0 ; + } -dev_warn (dev,"unsupported vendor resource %d\n" , - hdr->type); -continue ; - } + handler = d->handlers[type]; +if (!handler) +return 0 ; -if (hdr->type >=RSC_LAST ) { -dev_warn (dev,"unsupported resource %d\n" , hdr->type); -continue ; - } +return handler (rproc, rsc, offset, avail); +} - handler = handlers[hdr->type]; -if (!handler) -continue ; +/* handle firmware resource entries before booting the remote processor */ +static int rproc_handle_resources (struct rproc *rproc, +rproc_handle_resource_t handlers[RSC_LAST ]) +{ +struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers }; - ret =handler (rproc, rsc, offset +sizeof (*hdr), avail); -if (ret) -break ; - } +if (!rproc->table_ptr) +return 0 ; -return ret; +return rsc_table_for_each_entry (rproc->table_ptr, rproc->table_sz, + &rproc->dev, rproc_handle_rsc_entry, &d); }static int rproc_prepare_subdevices (struct rproc *rproc)
include/linux/rsc_table.h +53 -0
57 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1048/1424 remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit bb840ea69347aff7bde5a208e7b5b180669a7656 ]
table->offset[i] is a u32 from firmware, but was stored into a signed int. A crafted offset like 0xFFFFFFF0 becomes -16, placing hdr 16 bytes before the table buffer. The subsequent avail check was bypassed because the negative int was promoted to a large size_t in the expression "table_sz - offset - sizeof(*hdr)", yielding a large positive avail and letting the out-of-bounds hdr->type read proceed undetected.
Store the offset as u32 and validate it with unsigned comparisons before any pointer arithmetic.
--- include/linux/rsc_table.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
include/linux/rsc_table.h +11 -6
@@ -337,17 +337,22 @@ static inline int rsc_table_for_each_entry(struct resource_table *table,int i, ret;for (i =0 ; i < table->num; i++) { -int offset = table->offset[i]; -struct fw_rsc_hdr *hdr = (void *)table + offset; -int avail = table_sz - offset -sizeof (*hdr); -int rsc_offset = offset +sizeof (*hdr); -void *rsc = (void *)hdr +sizeof (*hdr); +u32 offset = table->offset[i]; +struct fw_rsc_hdr *hdr; +int avail, rsc_offset; +void *rsc; -if (avail <0 ) { +if (offset <sizeof (*table) || offset >= table_sz || + table_sz - offset <sizeof (*hdr)) {dev_err (dev,"rsc table is truncated\n" );return -EINVAL ; } + hdr = (void *)table + offset; + avail = table_sz - offset -sizeof (*hdr); + rsc_offset = offset +sizeof (*hdr); + rsc = (void *)hdr +sizeof (*hdr); + ret =cb (hdr->type, rsc, rsc_offset, avail, data);if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1049/1424 bpf, cgroup: Fix invalid storage access after __cgroup_bpf_attach failed
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 6655c409707ec8ce9ce0850ffe4fe02331fd4d9c ]
A potential invalid storage access issue can occur after replacing a cgroup bpf prog.
This occurs in the following scenario:
1. prog1 with storage is attached to a cgroup in multi-attach mode.
2. prog1 is replaced with prog2 using BPF_F_REPLACE in multi-attach mode, but fails midway (e.g. in bpf_trampoline_link_cgroup_shim or update_effective_progs).
3. A new prog3 is attached to the cgroup in multi-attach mode.
The reason is that __cgroup_bpf_attach overwrites pl->storage with the new storage prior to attachment completion. When attachment fails midway, the cleanup path calls bpf_cgroup_storages_free(new_storage) to free the newly allocated storage, but fails to restore pl->storage back to old_storage.
Consequently, the still-active prog1 holds invalid or dangling storage pointers, leading to an invalid memory access when prog1 executes and calls bpf_get_local_storage. Additionally, original pl->flags and cgrp->bpf.flags[atype] are left unrestored.
Fix this by saving old_pl_flags, old_storage, and old_flags prior to the update, and properly restoring all of them in the cleanup path on error.
--- kernel/bpf/cgroup.c | 8 ++++++++ 1 file changed, 8 insertions(+)
kernel/bpf/cgroup.c +8 -0
@@ -646,8 +646,10 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,struct bpf_prog *old_prog =NULL ;struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {};struct bpf_cgroup_storage *new_storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {}; +struct bpf_cgroup_storage *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {};struct bpf_prog *new_prog = prog ? : link->link.prog;enum cgroup_bpf_attach_type atype; +u32 old_flags, old_pl_flags;struct bpf_prog_list *pl;struct hlist_head *progs;int err;
@@ -693,6 +695,8 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,if (pl) { old_prog = pl->prog; + old_pl_flags = pl->flags; +bpf_cgroup_storages_assign (old_storage, pl->storage); }else {struct hlist_node *last =NULL ;
@@ -716,6 +720,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, pl->link = link; pl->flags = flags;bpf_cgroup_storages_assign (pl->storage, storage); + old_flags = cgrp->bpf.flags[atype]; cgrp->bpf.flags[atype] = saved_flags;if (type ==BPF_LSM_CGROUP ) {
@@ -746,12 +751,15 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,if (old_prog) { pl->prog = old_prog; pl->link =NULL ; + pl->flags = old_pl_flags; +bpf_cgroup_storages_assign (pl->storage, old_storage); }bpf_cgroup_storages_free (new_storage);if (!old_prog) {hlist_del (&pl->node);kfree (pl); } + cgrp->bpf.flags[atype] = old_flags;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1050/1424 selftests/mm/kugepaged: restore thp settings at exit
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit b6aab3384cafba151c53d3b5f7e1f8d073aadf03 ]
Previously, the saved thp settings would be restored upon a signal or at the natural end of the test suite. But there are some tests that directly call exit() upon failure. In this case, the thp settings were not being restored, which could then influence other tests.
Fix this by installing an atexit() handler to do the actual restore. The signal handler can now just call exit() and the atexit handler is invoked.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
tools/testing/selftests/mm/khugepaged.c +11 -6
@@ -374,18 +374,22 @@ static void pop_settings(void)write_settings (current_settings ()); } -static void restore_settings (int sig) +static void restore_settings_atexit (void ) {if (skip_settings_restore) - goto out; +return ;printf ("Restore THP and khugepaged settings..." );write_settings (&saved_settings);success ("OK" ); -if (sig) -exit (EXIT_FAILURE ); -out: -exit (exit_status); + + skip_settings_restore = true; +} + +static void restore_settings (int sig) +{ +/* exit() will invoke the restore_settings_atexit handler. */ +exit (sig ?EXIT_FAILURE : exit_status); }static void save_settings (void )
@@ -415,6 +419,7 @@ static void save_settings(void)success ("OK" ); +atexit (restore_settings_atexit);signal (SIGTERM , restore_settings);signal (SIGINT , restore_settings);signal (SIGHUP , restore_settings);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1051/1424 selftests/mm: factor out thp settings management
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 00679a183ac6d2584723cfc2a2c07c8285f802dc ]
The khugepaged test has a useful framework for save/restore/pop/push of all thp settings via the sysfs interface. This will be useful to explicitly control multi-size THP settings in other tests, so let's move it out of khugepaged and into its own thp_settings.[c|h] utility.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/Makefile | 4 +- tools/testing/selftests/mm/khugepaged.c | 346 ++-------------------- tools/testing/selftests/mm/thp_settings.c | 296 ++++++++++++++++++ tools/testing/selftests/mm/thp_settings.h | 71 +++++ 4 files changed, 391 insertions(+), 326 deletions(-) create mode 100644 tools/testing/selftests/mm/thp_settings.c create mode 100644 tools/testing/selftests/mm/thp_settings.h
tools/testing/selftests/mm/Makefile +2 -2
@@ -117,8 +117,8 @@ TEST_FILES += va_high_addr_switch.sh include ../lib.mk -$(TEST_GEN_PROGS): vm_util.c -$(TEST_GEN_FILES): vm_util.c +$(TEST_GEN_PROGS): vm_util.c thp_settings.c +$(TEST_GEN_FILES): vm_util.c thp_settings.c $(OUTPUT)/uffd-stress: uffd-common.c $(OUTPUT)/uffd-unit-tests: uffd-common.c
tools/testing/selftests/mm/khugepaged.c +22 -324
475 lines not on this page · raw message
tools/testing/selftests/mm/thp_settings.c new file +296 -0
296 lines not on this page · raw message
tools/testing/selftests/mm/thp_settings.h new file +71 -0
71 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1052/1424 selftests/mm: support multi-size THP interface in thp_settings
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 4f5070a5e40db2e9dbf5fff4ec678d6fbb338d5c ]
Save and restore the new per-size hugepage enabled setting, if available on the running kernel.
Since the number of per-size directories is not fixed, solve this as simply as possible by catering for a maximum number in the thp_settings struct (20). Each array index is the order. The value of THP_NEVER is changed to 0 so that all of these new settings default to THP_NEVER and the user only needs to fill in the ones they want to enable.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 3 ++ tools/testing/selftests/mm/thp_settings.c | 55 ++++++++++++++++++++++- tools/testing/selftests/mm/thp_settings.h | 11 ++++- 3 files changed, 67 insertions(+), 2 deletions(-)
tools/testing/selftests/mm/khugepaged.c +3 -0
@@ -1141,6 +1141,7 @@ static void parse_test_type(int argc, const char **argv)int main (int argc,const char **argv) { +int hpage_pmd_order;struct thp_settings default_settings = { .thp_enabled =THP_MADVISE , .thp_defrag =THP_DEFRAG_ALWAYS ,
@@ -1175,11 +1176,13 @@ int main(int argc, const char **argv)exit (EXIT_FAILURE ); } hpage_pmd_nr = hpage_pmd_size / page_size; + hpage_pmd_order =__builtin_ctz (hpage_pmd_nr); default_settings.khugepaged.max_ptes_none = hpage_pmd_nr -1 ; default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr /8 ; default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr /2 ; default_settings.khugepaged.pages_to_scan = hpage_pmd_nr *8 ; + default_settings.hugepages[hpage_pmd_order].enabled =THP_INHERIT ;save_settings ();thp_push_settings (&default_settings);
tools/testing/selftests/mm/thp_settings.c +54 -1
89 lines not on this page · raw message
tools/testing/selftests/mm/thp_settings.h +10 -1
@@ -7,9 +7,10 @@#include <stdint.h> enum thp_enabled { +THP_NEVER ,THP_ALWAYS , +THP_INHERIT ,THP_MADVISE , -THP_NEVER , };enum thp_defrag {
@@ -29,6 +30,12 @@ enum shmem_enabled { SHMEM_FORCE, }; +#define NR_ORDERS 20 + +struct hugepages_settings { +enum thp_enabled enabled; +}; +struct khugepaged_settings {bool defrag;unsigned int alloc_sleep_millisecs;
@@ -46,6 +53,7 @@ struct thp_settings {bool use_zero_page;struct khugepaged_settings khugepaged;unsigned long read_ahead_kb; +struct hugepages_settings hugepages[NR_ORDERS ]; };int read_file (const char *path,char *buf,size_t buflen);
@@ -67,5 +75,6 @@ void thp_restore_settings(void);void thp_save_settings (void );void thp_set_read_ahead_path (char *path); +unsigned long thp_supported_orders (void );#endif /* __THP_SETTINGS_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1053/1424 selftests/mm/khugepaged: enlighten for multi-size THP
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 9f0704eae8a4edc8dca9c8a297f798d505a4103a ]
The collapse_max_ptes_none test was previously failing when a THP size less than PMD-size had enabled="always". The root cause is because the test faults in 1 page less than the threshold it set for collapsing. But when THP is enabled always, we "over allocate" and therefore the threshold is passed, and collapse unexpectedly succeeds.
Solve this by enlightening khugepaged selftest. Add a command line option to pass in the desired THP size that should be used for all anonymous allocations. The harness will then explicitly configure a THP size as requested and modify the collapse_max_ptes_none test so that it faults in the threshold minus the number of pages in the configured THP size. If no command line option is provided, default to order 0, as per previous behaviour.
I chose to use an order in the command line interface, since this makes the interface agnostic of base page size, making it easier to invoke from run_vmtests.sh.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 48 +++++++++++++++++------ tools/testing/selftests/mm/run_vmtests.sh | 2 + 2 files changed, 39 insertions(+), 11 deletions(-)
tools/testing/selftests/mm/khugepaged.c +37 -11
@@ -28,6 +28,7 @@static unsigned long hpage_pmd_size;static unsigned long page_size;static int hpage_pmd_nr; +static int anon_order;#define PID_SMAPS "/proc/self/smaps"#define TEST_FILE "collapse_test_file"
@@ -607,6 +608,11 @@ static bool is_tmpfs(struct mem_ops *ops)return ops == &__file_ops && finfo.type ==VMA_SHMEM ; } +static bool is_anon (struct mem_ops *ops) +{ +return ops == &__anon_ops; +} +static void alloc_at_fault (void ) {struct thp_settings settings = *thp_current_settings ();
@@ -673,6 +679,7 @@ static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *oint max_ptes_none = hpage_pmd_nr /2 ;struct thp_settings settings = *thp_current_settings ();void *p; +int fault_nr_pages =is_anon (ops) ?1 << anon_order :1 ; settings.khugepaged.max_ptes_none = max_ptes_none;thp_push_settings (&settings);
@@ -686,10 +693,10 @@ static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *o goto skip; } - ops->fault (p,0 , (hpage_pmd_nr - max_ptes_none -1 ) * page_size); + ops->fault (p,0 , (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size); c->collapse ("Maybe collapse with max_ptes_none exceeded" , p,1 , ops, !c->enforce_pte_scan_limits); -validate_memory (p,0 , (hpage_pmd_nr - max_ptes_none -1 ) * page_size); +validate_memory (p,0 , (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size);if (c->enforce_pte_scan_limits) { ops->fault (p,0 , (hpage_pmd_nr - max_ptes_none) * page_size);
@@ -1076,7 +1083,7 @@ static void madvise_retracted_page_tables(struct collapse_context *c,static void usage (void ) { -fprintf (stderr,"\nUsage: ./khugepaged <test type> [dir]\n\n" ); +fprintf (stderr,"\nUsage: ./khugepaged [OPTIONS] <test type> [dir]\n\n" );fprintf (stderr,"\t<test type>\t: <context>:<mem_type>\n" );fprintf (stderr,"\t<context>\t: [all|khugepaged|madvise]\n" );fprintf (stderr,"\t<mem_type>\t: [all|anon|file|shmem]\n" );
@@ -1085,15 +1092,34 @@ static void usage(void)fprintf (stderr,"\tCONFIG_READ_ONLY_THP_FOR_FS=y\n" );fprintf (stderr,"\n\tif [dir] is a (sub)directory of a tmpfs mount, tmpfs must be\n" );fprintf (stderr,"\tmounted with huge=madvise option for khugepaged tests to work\n" ); +fprintf (stderr,"\n\tSupported Options:\n" ); +fprintf (stderr,"\t\t-h: This help message.\n" ); +fprintf (stderr,"\t\t-s: mTHP size, expressed as page order.\n" ); +fprintf (stderr,"\t\t Defaults to 0. Use this size for anon allocations.\n" );exit (1 ); } -static void parse_test_type (int argc,const char **argv) +static void parse_test_type (int argc,char **argv) { +int opt;char *buf;const char *token; -if (argc ==1 ) { +while ((opt =getopt (argc, argv,"s:h" )) !=-1 ) { +switch (opt) { +case 's' : + anon_order =atoi (optarg); +break ; +case 'h' : +default : +usage (); + } + } + + argv += optind; + argc -= optind; + +if (argc ==0 ) {/* Backwards compatibility */ khugepaged_context = &__khugepaged_context; madvise_context = &__madvise_context;
@@ -1101,7 +1127,7 @@ static void parse_test_type(int argc, const char **argv)return ; } - buf =strdup (argv[1 ]); + buf =strdup (argv[0 ]); token =strsep (&buf,":" );if (!strcmp (token,"all" )) {
@@ -1135,11 +1161,13 @@ static void parse_test_type(int argc, const char **argv)if (!file_ops)return ; -if (argc !=3 ) +if (argc !=2 )usage (); + +get_finfo (argv[1 ]); } -int main (int argc,const char **argv) +int main (int argc,char **argv) {int hpage_pmd_order;struct thp_settings default_settings = {
@@ -1164,9 +1192,6 @@ int main(int argc, const char **argv)parse_test_type (argc, argv); -if (file_ops) -get_finfo (argv[2 ]); -setbuf (stdout,NULL ); page_size =getpagesize ();
@@ -1183,6 +1208,7 @@ int main(int argc, const char **argv) default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr /2 ; default_settings.khugepaged.pages_to_scan = hpage_pmd_nr *8 ; default_settings.hugepages[hpage_pmd_order].enabled =THP_INHERIT ; + default_settings.hugepages[anon_order].enabled =THP_ALWAYS ;save_settings ();thp_push_settings (&default_settings);
tools/testing/selftests/mm/run_vmtests.sh +2 -0
@@ -377,6 +377,8 @@ CATEGORY="cow" run_test ./cow CATEGORY="thp" run_test ./khugepaged +CATEGORY="thp" run_test ./khugepaged -s 2 + CATEGORY="thp" run_test ./transhuge-stress -d 20 CATEGORY="thp" run_test ./split_huge_page_test
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1054/1424 selftests: mm: support shmem mTHP collapse testing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baolin Wang <[email protected]>
[ Upstream commit 2e6d88e9d455fae9c4ac95c893362258f9540dfa ]
Add shmem mTHP collpase testing. Similar to the anonymous page, users can use the '-s' parameter to specify the shmem mTHP size for testing.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 4 +- tools/testing/selftests/mm/thp_settings.c | 46 ++++++++++++++++++++--- tools/testing/selftests/mm/thp_settings.h | 9 ++++- 3 files changed, 51 insertions(+), 8 deletions(-)
tools/testing/selftests/mm/khugepaged.c +3 -1
@@ -1095,7 +1095,7 @@ static void usage(void)fprintf (stderr,"\n\tSupported Options:\n" );fprintf (stderr,"\t\t-h: This help message.\n" );fprintf (stderr,"\t\t-s: mTHP size, expressed as page order.\n" ); -fprintf (stderr,"\t\t Defaults to 0. Use this size for anon allocations.\n" ); +fprintf (stderr,"\t\t Defaults to 0. Use this size for anon or shmem allocations.\n" );exit (1 ); }
@@ -1209,6 +1209,8 @@ int main(int argc, char **argv) default_settings.khugepaged.pages_to_scan = hpage_pmd_nr *8 ; default_settings.hugepages[hpage_pmd_order].enabled =THP_INHERIT ; default_settings.hugepages[anon_order].enabled =THP_ALWAYS ; + default_settings.shmem_hugepages[hpage_pmd_order].enabled =SHMEM_INHERIT ; + default_settings.shmem_hugepages[anon_order].enabled =SHMEM_ALWAYS ;save_settings ();thp_push_settings (&default_settings);
tools/testing/selftests/mm/thp_settings.c +40 -6
94 lines not on this page · raw message
tools/testing/selftests/mm/thp_settings.h +8 -1
@@ -22,10 +22,11 @@ enum thp_defrag { };enum shmem_enabled { +SHMEM_NEVER ,SHMEM_ALWAYS ,SHMEM_WITHIN_SIZE ,SHMEM_ADVISE , -SHMEM_NEVER , +SHMEM_INHERIT ,SHMEM_DENY ,SHMEM_FORCE , };
@@ -46,6 +47,10 @@ struct khugepaged_settings {unsigned long pages_to_scan; }; +struct shmem_hugepages_settings { +enum shmem_enabled enabled; +}; +struct thp_settings {enum thp_enabled thp_enabled;enum thp_defrag thp_defrag;
@@ -54,6 +59,7 @@ struct thp_settings {struct khugepaged_settings khugepaged;unsigned long read_ahead_kb;struct hugepages_settings hugepages[NR_ORDERS ]; +struct shmem_hugepages_settings shmem_hugepages[NR_ORDERS ]; };int read_file (const char *path,char *buf,size_t buflen);
@@ -76,5 +82,6 @@ void thp_save_settings(void);void thp_set_read_ahead_path (char *path);unsigned long thp_supported_orders (void ); +unsigned long thp_shmem_supported_orders (void );#endif /* __THP_SETTINGS_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1055/1424 selftests/mm: add new test cases to the migration test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donet Tom <[email protected]>
[ Upstream commit 901083d8f5c55dc125834bbc5ac1720014e66758 ]
Added three new test cases to the migration tests:
1. Shared anon THP migration test
This test will mmap shared anon memory, madvise it to MADV_HUGEPAGE, then do migration entry testing. One thread will move pages back and forth between nodes whilst other threads try and access them.
2. Private anon hugetlb migration test
This test will mmap private anon hugetlb memory and then do the migration entry testing.
3. Shared anon hugetlb migration test
This test will mmap shared anon hugetlb memory and then do the migration entry testing.
Test results
============
# ./tools/testing/selftests/mm/migration TAP version 13 1..6 # Starting 6 tests from 1 test cases. # RUN migration.private_anon ... # OK migration.private_anon ok 1 migration.private_anon # RUN migration.shared_anon ... # OK migration.shared_anon ok 2 migration.shared_anon # RUN migration.private_anon_thp ... # OK migration.private_anon_thp ok 3 migration.private_anon_thp # RUN migration.shared_anon_thp ... # OK migration.shared_anon_thp ok 4 migration.shared_anon_thp # RUN migration.private_anon_htlb ... # OK migration.private_anon_htlb ok 5 migration.private_anon_htlb # RUN migration.shared_anon_htlb ... # OK migration.shared_anon_htlb ok 6 migration.shared_anon_htlb # PASSED: 6 / 6 tests passed. # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0 #
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/migration.c | 99 ++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
tools/testing/selftests/mm/migration.c +99 -0
@@ -200,4 +200,103 @@ TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)ASSERT_EQ (pthread_cancel (self->threads[i]),0 ); } +/* +* migration test with shared anon THP page +*/ + +TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME) +{ +pid_t pid; +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,2 *TWOMEG ,PROT_READ |PROT_WRITE , +MAP_SHARED |MAP_ANONYMOUS ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + + ptr = (uint64_t *)ALIGN ((uintptr_t ) ptr,TWOMEG ); +ASSERT_EQ (madvise (ptr,TWOMEG ,MADV_HUGEPAGE ),0 ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) { + pid =fork (); +if (!pid) { +prctl (PR_SET_PDEATHSIG ,SIGHUP ); +/* Parent may have died before prctl so check now. */ +if (getppid () ==1 ) +kill (getpid (),SIGHUP ); +access_mem (ptr); + }else { + self->pids[i] = pid; + } + } + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (kill (self->pids[i],SIGTERM ),0 ); +} + +/* +* migration test with private anon hugetlb page +*/ +TEST_F_TIMEOUT(migration, private_anon_htlb, 2*RUNTIME) +{ +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,TWOMEG ,PROT_READ |PROT_WRITE , +MAP_PRIVATE |MAP_ANONYMOUS |MAP_HUGETLB ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) +if (pthread_create (&self->threads[i],NULL , access_mem, ptr)) +perror ("Couldn't create thread" ); + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (pthread_cancel (self->threads[i]),0 ); +} + +/* +* migration test with shared anon hugetlb page +*/ +TEST_F_TIMEOUT(migration, shared_anon_htlb, 2*RUNTIME) +{ +pid_t pid; +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,TWOMEG ,PROT_READ |PROT_WRITE , +MAP_SHARED |MAP_ANONYMOUS |MAP_HUGETLB ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) { + pid =fork (); +if (!pid) { +prctl (PR_SET_PDEATHSIG ,SIGHUP ); +/* Parent may have died before prctl so check now. */ +if (getppid () ==1 ) +kill (getpid (),SIGHUP ); +access_mem (ptr); + }else { + self->pids[i] = pid; + } + } + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (kill (self->pids[i],SIGTERM ),0 ); +} +TEST_HARNESS_MAIN
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1056/1424 ksm_tests: skip hugepage test when Transparent Hugepages are disabled
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Wang <[email protected]>
[ Upstream commit fdc3bc3497946c6b416a17628907581657102e60 ]
Some systems (e.g. minimal or real-time kernels) may not enable Transparent Hugepages (THP), causing MADV_HUGEPAGE to return EINVAL. This patch introduces a runtime check using the existing THP sysfs interface and skips the hugepage merging test (-H) when THP is not available.
To avoid those failures:
# -----------------------------
# running ./ksm_tests -H -s 100 # ----------------------------- # ksm_tests: MADV_HUGEPAGE: Invalid argument # [FAIL] not ok 1 ksm_tests -H -s 100 # exit=2
# --------------------
# running ./khugepaged # -------------------- # Reading PMD pagesize failed# [FAIL] not ok 1 khugepaged # exit=1
# --------------------
# running ./soft-dirty # -------------------- # TAP version 13 # 1..15 # ok 1 Test test_simple # ok 2 Test test_vma_reuse dirty bit of allocated page # ok 3 Test test_vma_reuse dirty bit of reused address page # Bail out! Reading PMD pagesize failed# Planned tests != run tests (15 != 3) # # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 # [FAIL] not ok 1 soft-dirty # exit=1 # SUMMARY: PASS=0 SKIP=0 FAIL=1
# -------------------
# running ./migration # ------------------- # TAP version 13 # 1..3 # # Starting 3 tests from 1 test cases. # # RUN migration.private_anon ... # # OK migration.private_anon # ok 1 migration.private_anon # # RUN migration.shared_anon ... # # OK migration.shared_anon # ok 2 migration.shared_anon # # RUN migration.private_anon_thp ... # # migration.c:196:private_anon_thp:Expected madvise(ptr, TWOMEG, MADV_HUGEPAGE) (-1) == 0 (0) # # private_anon_thp: Test terminated by assertion # # FAIL migration.private_anon_thp # not ok 3 migration.private_anon_thp # # FAILED: 2 / 3 tests passed. # # Totals: pass:2 fail:1 xfail:0 xpass:0 skip:0 error:0 # [FAIL] not ok 1 migration # exit=1
It's true that CONFIG_TRANSPARENT_HUGEPAGE=y is explicitly enabled in tools/testing/selftests/mm/config, so ideally the runtime environment should also support THP.
However, in practice, we've found that on some systems:
- THP is disabled at boot time (transparent_hugepage=never)
- Or manually disabled via sysfs
- Or unavailable in RT kernels, containers, or minimal CI environments
In these cases, the test will fail with EINVAL on madvise(MADV_HUGEPAGE), even though the kernel config is correct.
To make the test suite more robust and avoid false negatives, this patch adds a runtime check for /sys/kernel/mm/transparent_hugepage/enabled.
If THP is not available, the hugepage test (-H) is skipped with a clear message.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 5 +++++ tools/testing/selftests/mm/ksm_tests.c | 6 ++++++ tools/testing/selftests/mm/migration.c | 8 ++++++++ tools/testing/selftests/mm/soft-dirty.c | 9 ++++++++- tools/testing/selftests/mm/thp_settings.c | 11 +++++++++++ tools/testing/selftests/mm/thp_settings.h | 2 ++ 6 files changed, 40 insertions(+), 1 deletion(-)
tools/testing/selftests/mm/khugepaged.c +5 -0
@@ -1190,6 +1190,11 @@ int main(int argc, char **argv) .read_ahead_kb = 0, }; +if (!thp_is_enabled ()) { +printf ("Transparent Hugepages not available\n" ); +return KSFT_SKIP ; + } +parse_test_type (argc, argv);setbuf (stdout,NULL );
tools/testing/selftests/mm/ksm_tests.c +6 -0
@@ -15,6 +15,7 @@#include "../kselftest.h" #include <include/vdso/time64.h> #include "vm_util.h" +#include "thp_settings.h" #define KSM_SYSFS_PATH "/sys/kernel/mm/ksm/"#define KSM_FP (s) (KSM_SYSFS_PATH s)
@@ -555,6 +556,11 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,unsigned long scan_time_ns;int pagemap_fd, n_normal_pages, n_huge_pages; +if (!thp_is_enabled ()) { +printf ("Transparent Hugepages not available\n" ); +return KSFT_SKIP ; + } + map_size *=MB ;size_t len = map_size;
tools/testing/selftests/mm/migration.c +8 -0
@@ -5,6 +5,8 @@*/ #include "../kselftest_harness.h" +#include "thp_settings.h" +#include <strings.h> #include <pthread.h> #include <numa.h>
@@ -181,6 +183,9 @@ TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)uint64_t *ptr;int i; +if (!thp_is_enabled ()) +SKIP (return,"Transparent Hugepages not available" ); +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 )SKIP (return,"Not enough threads or NUMA nodes available" );
@@ -210,6 +215,9 @@ TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME)uint64_t *ptr;int i; +if (!thp_is_enabled ()) +SKIP (return,"Transparent Hugepages not available" ); +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 )SKIP (return,"Not enough threads or NUMA nodes available" );
tools/testing/selftests/mm/soft-dirty.c +8 -1
@@ -6,8 +6,10 @@#include <stdint.h> #include <malloc.h> #include <sys/mman.h> +#include "../kselftest.h" #include "vm_util.h" +#include "thp_settings.h" #define PAGEMAP_FILE_PATH "/proc/self/pagemap"#define TEST_ITERATIONS 10000
@@ -78,8 +80,13 @@ static void test_hugepage(int pagemap_fd, int pagesize) {char *map;int i, ret; -size_t hpage_len =read_pmd_pagesize (); +if (!thp_is_enabled ()) { +ksft_test_result_skip ("Transparent Hugepages not available\n" ); +return ; + } + +size_t hpage_len =read_pmd_pagesize ();if (!hpage_len)ksft_exit_fail_msg ("Reading PMD pagesize failed" );
tools/testing/selftests/mm/thp_settings.c +11 -0
@@ -381,3 +381,14 @@ unsigned long thp_shmem_supported_orders(void) {return __thp_supported_orders (true); } + +bool thp_is_enabled (void ) +{ +if (access (THP_SYSFS ,F_OK ) !=0 ) +return false; + +int mode =thp_read_string ("enabled" , thp_enabled_strings); + +/* THP is considered enabled if it's either "always" or "madvise" */ +return mode ==1 || mode ==3 ; +}
tools/testing/selftests/mm/thp_settings.h +2 -0
@@ -84,4 +84,6 @@ void thp_set_read_ahead_path(char *path);unsigned long thp_supported_orders (void );unsigned long thp_shmem_supported_orders (void ); +bool thp_is_enabled (void ); +#endif /* __THP_SETTINGS_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1057/1424 selftests/mm: ksm_tests: use kselftest framework
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Rapoport (Microsoft) <[email protected]>
[ Upstream commit 4cc68d5f52de9614e2db70f43c52f012d1ebb5ad ]
Convert ksm_tests to use kselftest framework for reporting and tracking successful and failing runs.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/ksm_tests.c | 180 +++++++++++-------------- 1 file changed, 81 insertions(+), 99 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +81 -99
@@ -203,12 +203,12 @@ static void *allocate_memory(void *ptr, int prot, int mapping, char data, size_void *map_ptr =mmap (ptr, map_size,PROT_WRITE , mapping,-1 ,0 );if (!map_ptr) { -perror ("mmap" ); +ksft_perror ("mmap" );return NULL ; }memset (map_ptr, data, map_size);if (mprotect (map_ptr, map_size, prot)) { -perror ("mprotect" ); +ksft_perror ("mprotect" );munmap (map_ptr, map_size);return NULL ; }
@@ -229,11 +229,11 @@ static int ksm_do_scan(int scan_count, struct timespec start_time, int timeout)if (ksm_read_sysfs (KSM_FP ("full_scans" ), &cur_scan))return 1 ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &cur_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return 1 ; }if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { -printf ("Scan time limit exceeded\n" ); +ksft_print_msg ("Scan time limit exceeded\n" );return 1 ; } }
@@ -246,12 +246,12 @@ static int ksm_merge_pages(int merge_type, void *addr, size_t size, {if (merge_type ==KSM_MERGE_MADVISE ) {if (madvise (addr, size,MADV_MERGEABLE )) { -perror ("madvise" ); +ksft_perror ("madvise" );return 1 ; } }else if (merge_type ==KSM_MERGE_PRCTL ) {if (prctl (PR_SET_MEMORY_MERGE ,1 ,0 ,0 ,0 )) { -perror ("prctl" ); +ksft_perror ("prctl" );return 1 ; } }
@@ -270,7 +270,7 @@ static int ksm_unmerge_pages(void *addr, size_t size, struct timespec start_time, int timeout) { if (madvise(addr, size, MADV_UNMERGEABLE)) { -perror ("madvise" ); +ksft_perror ("madvise" );return 1 ; }return 0 ;
@@ -352,7 +352,7 @@ static int check_ksm_merge(int merge_type, int mapping, int prot,struct timespec start_time;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -366,7 +366,6 @@ static int check_ksm_merge(int merge_type, int mapping, int prot,/* verify that the right number of pages are merged */ if (assert_ksm_pages_count (page_count)) { -printf ("OK\n" );munmap (map_ptr, page_size * page_count);if (merge_type ==KSM_MERGE_PRCTL )prctl (PR_SET_MEMORY_MERGE ,0 ,0 ,0 ,0 );
@@ -374,7 +373,6 @@ static int check_ksm_merge(int merge_type, int mapping, int prot, } err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -386,7 +384,7 @@ static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout,int page_count =2 ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -408,13 +406,11 @@ static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout,/* check that unmerging was successful and 0 pages are currently merged */ if (assert_ksm_pages_count (0 )) { -printf ("OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_PASS ; } err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -426,7 +422,7 @@ static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, longstruct timespec start_time;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -453,12 +449,10 @@ static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, longelse if (!use_zero_pages && !assert_ksm_pages_count (page_count)) goto err_out; -printf ("OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -493,16 +487,16 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeoint first_node;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }if (numa_available () <0 ) { -perror ("NUMA support not enabled" ); +ksft_print_msg ("NUMA support not enabled\n" );return KSFT_SKIP ; }if (numa_num_configured_nodes () <=1 ) { -printf ("At least 2 NUMA nodes must be available\n" ); +ksft_print_msg ("At least 2 NUMA nodes must be available\n" );return KSFT_SKIP ; }if (ksm_write_sysfs (KSM_FP ("merge_across_nodes" ), merge_across_nodes))
@@ -513,7 +507,7 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo numa1_map_ptr =numa_alloc_onnode (page_size, first_node); numa2_map_ptr =numa_alloc_onnode (page_size,get_next_mem_node (first_node));if (!numa1_map_ptr || !numa2_map_ptr) { -perror ("numa_alloc_onnode" ); +ksft_perror ("numa_alloc_onnode" );return KSFT_FAIL ; }
@@ -538,13 +532,11 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeonuma_free (numa1_map_ptr, page_size);numa_free (numa2_map_ptr, page_size); -printf ("OK\n" );return KSFT_PASS ; err_out:numa_free (numa1_map_ptr, page_size);numa_free (numa2_map_ptr, page_size); -printf ("Not OK\n" );return KSFT_FAIL ; }
@@ -557,7 +549,7 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,int pagemap_fd, n_normal_pages, n_huge_pages;if (!thp_is_enabled ()) { -printf ("Transparent Hugepages not available\n" ); +ksft_print_msg ("Transparent Hugepages not available\n" );return KSFT_SKIP ; }
@@ -587,36 +579,35 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,else n_huge_pages++; } -printf ("Number of normal pages: %d\n" , n_normal_pages); -printf ("Number of huge pages: %d\n" , n_huge_pages); +ksft_print_msg ("Number of normal pages: %d\n" , n_normal_pages); +ksft_print_msg ("Number of huge pages: %d\n" , n_huge_pages);memset (map_ptr,'*' , len);if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr_orig, len +HPAGE_SIZE );return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr_orig, len +HPAGE_SIZE );return KSFT_FAIL ; }
@@ -634,30 +625,29 @@ static int ksm_merge_time(int merge_type, int mapping, int prot, int timeout, sireturn KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr, map_size);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, map_size);return KSFT_FAIL ; }
@@ -674,37 +664,36 @@ static int ksm_unmerge_time(int merge_type, int mapping, int prot, int timeout,if (!map_ptr)return KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_unmerge_pages (map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr, map_size);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, map_size);return KSFT_FAIL ; }
@@ -723,24 +712,24 @@ static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, sizereturn KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }for (size_t i =0 ; i < page_count -1 ; i = i +2 )memset (map_ptr + page_size * i,'-' ,1 );if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; } cow_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n\n" , (page_size * page_count) /MB ); -printf ("Not merged pages:\n" ); -printf ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n\n" , (page_size * page_count) /MB ); +ksft_print_msg ("Not merged pages:\n" ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , cow_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n\n" , ((page_size * (page_count /2 )) /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n\n" , ((page_size * (page_count /2 )) /MB ) / ((double )cow_time_ns /NSEC_PER_SEC ));/* Create 2000 pairs of duplicate pages */
@@ -752,30 +741,29 @@ static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, size goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }for (size_t i =0 ; i < page_count -1 ; i = i +2 )memset (map_ptr + page_size * i,'-' ,1 );if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } cow_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Merged pages:\n" ); -printf ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Merged pages:\n" ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , cow_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , ((page_size * (page_count /2 )) /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , ((page_size * (page_count /2 )) /MB ) / ((double )cow_time_ns /NSEC_PER_SEC ));munmap (map_ptr, page_size * page_count);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -793,6 +781,10 @@ int main(int argc, char *argv[])bool use_zero_pages =KSM_USE_ZERO_PAGES_DEFAULT ;bool merge_across_nodes =KSM_MERGE_ACROSS_NODES_DEFAULT ;long size_MB =0 ; +const char *test_descr ="KSM merging" ; + +ksft_print_header (); +ksft_set_plan (1 );while ((opt =getopt (argc, argv,"dha:p:l:z:m:s:t:MUZNPCHD" )) !=-1 ) {switch (opt) {
@@ -801,17 +793,13 @@ int main(int argc, char *argv[])break ;case 'p' : page_count =atol (optarg); -if (page_count <=0 ) { -printf ("The number of pages must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (page_count <=0 ) +ksft_exit_fail_msg ("The number of pages must be greater than 0\n" );break ;case 'l' : ksm_scan_limit_sec =atoi (optarg); -if (ksm_scan_limit_sec <=0 ) { -printf ("Timeout value must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (ksm_scan_limit_sec <=0 ) +ksft_exit_fail_msg ("Timeout value must be greater than 0\n" );break ;case 'h' :print_help ();
@@ -833,19 +821,15 @@ int main(int argc, char *argv[])break ;case 's' : size_MB =atoi (optarg); -if (size_MB <=0 ) { -printf ("Size must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (size_MB <=0 ) +ksft_exit_fail_msg ("Size must be greater than 0\n" );break ;case 't' : {int tmp =atoi (optarg); -if (tmp <0 || tmp >KSM_MERGE_LAST ) { -printf ("Invalid merge type\n" ); -return KSFT_FAIL ; - } +if (tmp <0 || tmp >KSM_MERGE_LAST ) +ksft_exit_fail_msg ("Invalid merge type\n" ); merge_type = tmp; }break ;
@@ -873,82 +857,80 @@ int main(int argc, char *argv[]) test_name =KSM_COW_TIME ;break ;default : -return KSFT_FAIL ; +ksft_exit_fail_msg ("Unknown option\n" ); } }if (prot ==0 ) prot =str_to_prot (KSM_PROT_STR_DEFAULT ); -if (access (KSM_SYSFS_PATH ,F_OK )) { -printf ("Config KSM not enabled\n" ); -return KSFT_SKIP ; - } +if (access (KSM_SYSFS_PATH ,F_OK )) +ksft_exit_skip ("Config KSM not enabled\n" ); -if (ksm_save_def (&ksm_sysfs_old)) { -printf ("Cannot save default tunables\n" ); -return KSFT_FAIL ; - } +if (ksm_save_def (&ksm_sysfs_old)) +ksft_exit_fail_msg ("Cannot save default tunables\n" );if (ksm_write_sysfs (KSM_FP ("run" ),2 ) ||ksm_write_sysfs (KSM_FP ("sleep_millisecs" ),0 ) ||numa_available () ?0 :ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 ) ||ksm_write_sysfs (KSM_FP ("pages_to_scan" ), page_count)) -return KSFT_FAIL ; +ksft_exit_fail_msg ("Cannot set up KSM tunables\n" );switch (test_name) {case CHECK_KSM_MERGE : + test_descr ="KSM merging" ; ret =check_ksm_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, page_count, ksm_scan_limit_sec, page_size);break ;case CHECK_KSM_UNMERGE : + test_descr ="KSM unmerging" ; ret =check_ksm_unmerge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, page_size);break ;case CHECK_KSM_ZERO_PAGE_MERGE : + test_descr ="KSM zero page merging" ; ret =check_ksm_zero_page_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, page_count, ksm_scan_limit_sec, use_zero_pages, page_size);break ;case CHECK_KSM_NUMA_MERGE : + test_descr ="KSM NUMA merging" ; ret =check_ksm_numa_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, merge_across_nodes, page_size);break ;case KSM_MERGE_TIME : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM merge time" ; ret =ksm_merge_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_MERGE_TIME_HUGE_PAGES : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM merge time with huge pages" ; ret =ksm_merge_hugepages_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_UNMERGE_TIME : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM unmerge time" ; ret =ksm_unmerge_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_COW_TIME : + test_descr ="KSM COW time" ; ret =ksm_cow_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, page_size);break ; } -if (ksm_restore (&ksm_sysfs_old)) { -printf ("Cannot restore default tunables\n" ); -return KSFT_FAIL ; - } +if (ksm_restore (&ksm_sysfs_old)) +ksft_print_msg ("Cannot restore default tunables\n" ); + +ksft_test_result_report (ret,"%s\n" , test_descr); -return ret; +ksft_finished (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1058/1424 selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 15828a150c5806869b7feb9e38ad2c0284fbf18a ]
The KSM NUMA merge test allocates identical pages on different NUMA nodes and verifies KSM behavior with merge_across_nodes enabled and disabled.
On systems with memoryless NUMA nodes, for example:
#numactl -H
available: 2 nodes (0,4)
.....
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 14825 MB
node 0 free: 1382 MB
node 4 cpus:
node 4 size: 0 MB
node 4 free: 0 MBthe test may attempt to allocate memory on a node without memory, causing numa_alloc_onnode() to fail and resulting in a spurious test failure.
The test currently checks numa_num_configured_nodes() to determine whether sufficient NUMA nodes are available. However, configured nodes do not necessarily have memory.
Reuse the existing get_first_mem_node() and get_next_mem_node() helpers to locate NUMA nodes that actually contain memory, and skip the test when fewer than two such nodes are available.
Before patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
mbind: Invalid argument
ok 1 KSM NUMA merging
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0 [PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
mbind: Invalid argument
not ok 1 KSM NUMA merging
Totals: pass:0 fail:1 xfail:0 xpass:0 skip:0 error:0 [FAIL]
not ok 2 ksm_tests -N -m 0 # exit=1
After patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
At least 2 NUMA nodes with memory must be available ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0 [PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
At least 2 NUMA nodes with memory must be available ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0 [PASS]
ok 2 ksm_tests -N -m 0
--- tools/testing/selftests/mm/ksm_tests.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +9 -7
@@ -468,9 +468,9 @@ static int get_next_mem_node(int node) mem_node = i % (max_node +1 ); node_size =numa_node_size (mem_node,NULL );if (node_size >0 ) -break ; +return mem_node; } -return mem_node; +return -ENODEV ; }static int get_first_mem_node (void )
@@ -483,8 +483,8 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo {void *numa1_map_ptr, *numa2_map_ptr;struct timespec start_time; +int first_node, second_node;int page_count =2 ; -int first_node;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) {ksft_perror ("clock_gettime" );
@@ -495,17 +495,19 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeoksft_print_msg ("NUMA support not enabled\n" );return KSFT_SKIP ; } -if (numa_num_configured_nodes () <=1 ) { -ksft_print_msg ("At least 2 NUMA nodes must be available\n" ); + first_node =get_first_mem_node (); + second_node =get_next_mem_node (first_node); + +if (second_node <0 ) { +ksft_print_msg ("At least 2 NUMA nodes with memory must be available\n" );return KSFT_SKIP ; }if (ksm_write_sysfs (KSM_FP ("merge_across_nodes" ), merge_across_nodes))return KSFT_FAIL ;/* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */ - first_node =get_first_mem_node (); numa1_map_ptr =numa_alloc_onnode (page_size, first_node); - numa2_map_ptr =numa_alloc_onnode (page_size,get_next_mem_node (first_node)); + numa2_map_ptr =numa_alloc_onnode (page_size, second_node);if (!numa1_map_ptr || !numa2_map_ptr) {ksft_perror ("numa_alloc_onnode" );return KSFT_FAIL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1059/1424 selftests/mm: fix ternary operator precedence in ksm_tests
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 4e1fbffb3333626682a011db7c4b4e9e40ba96d4 ]
The KSM selftest uses conditional expressions to skip accesses to merge_across_nodes on systems without NUMA support. However, the ternary operator is combined with logical OR without parentheses:
a || numa_available() ? 0 : b || c
Due to operator precedence rules, this is parsed as:
(a || numa_available()) ? 0 : (b || c)
instead of the intended:
a || (numa_available() ? 0 : b) || c
Add parentheses around the conditional expressions to ensure the correct evaluation order.
--- tools/testing/selftests/mm/ksm_tests.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +6 -6
@@ -316,8 +316,8 @@ static bool assert_ksm_pages_count(long dupl_page_count)static int ksm_save_def (struct ksm_sysfs *ksm_sysfs) { if (ksm_read_sysfs(KSM_FP("max_page_sharing"), &ksm_sysfs->max_page_sharing) || - numa_available() ? 0 : - ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes) || + (numa_available() ? 0 : + ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes)) || ksm_read_sysfs(KSM_FP("sleep_millisecs"), &ksm_sysfs->sleep_millisecs) || ksm_read_sysfs(KSM_FP("pages_to_scan"), &ksm_sysfs->pages_to_scan) || ksm_read_sysfs(KSM_FP("run"), &ksm_sysfs->run) ||
@@ -332,8 +332,8 @@ static int ksm_save_def(struct ksm_sysfs *ksm_sysfs)static int ksm_restore (struct ksm_sysfs *ksm_sysfs) { if (ksm_write_sysfs(KSM_FP("max_page_sharing"), ksm_sysfs->max_page_sharing) || - numa_available() ? 0 : - ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes) || + (numa_available() ? 0 : + ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes)) || ksm_write_sysfs(KSM_FP("pages_to_scan"), ksm_sysfs->pages_to_scan) || ksm_write_sysfs(KSM_FP("run"), ksm_sysfs->run) || ksm_write_sysfs(KSM_FP("sleep_millisecs"), ksm_sysfs->sleep_millisecs) ||
@@ -874,8 +874,8 @@ int main(int argc, char *argv[])if (ksm_write_sysfs (KSM_FP ("run" ),2 ) ||ksm_write_sysfs (KSM_FP ("sleep_millisecs" ),0 ) || -numa_available () ?0 : -ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 ) || + (numa_available () ?0 : +ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 )) ||ksm_write_sysfs (KSM_FP ("pages_to_scan" ), page_count))ksft_exit_fail_msg ("Cannot set up KSM tunables\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1060/1424 arm64: dts: qcom: sm7225-fairphone-fp4: Fix swapped USB QMP PHY vdda-phy/vdda-pll supplies
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit a3b3a060b696d964c769a7d9dc5835c79e4fe964 ]
The QMP PHY expects the vdda-phy supply to be around 0.88V and the vdda-pll supply to be 1.2V. But these two supplies are swapped for the USB QMP PHY on this board, feeding 1.2V to vdda-phy and 0.9V to vdda-pll.
Fix it by swapping the two supplies back.
--- arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +2 -2
@@ -710,8 +710,8 @@ &usb_1_hsphy { }; &usb_1_qmpphy { - vdda-phy-supply = <&vreg_l22a>; - vdda-pll-supply = <&vreg_l16a>; + vdda-phy-supply = <&vreg_l16a>; + vdda-pll-supply = <&vreg_l22a>; status = "okay"; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1061/1424 scripts/tags.sh: Prevent binary files appearing in cscope.files
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergei Litvin <[email protected]>
[ Upstream commit a9b93c34625a27bed5dc0f80ee2a359ceb955172 ]
When executing the command make COMPILED_SOURCE=1 cscope, the resulting cscope.files file contains filenames with the extensions *.rlib, *.rmeta, and *.so.
To fix this, modify the regular expression in the all_compiled_sources() function so that only files with the extensions *.h, *.c, *.S, and *.rs are accepted.
The issue has been introduced by commit 4f491bb6ea2a ("scripts/tags.sh:
collect compiled source precisely") which implemented the parsing of compiled sources from *.cmd files instead of using the "find" command.
--- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/tags.sh +1 -1
@@ -105,7 +105,7 @@ all_compiled_sources() { echo include/generated/autoconf.h find $ignore -name "*.cmd" -exec \ - grep -Poh '(?<=^ )\S+|(?<== )\S+[^\\](?=$)' {} \+ | + grep -Poh '(?<=^ )\S+\.([chS]|rs)(?=\s)|(?<== )\S+\.(?1)(?=$)' {} \+ | awk '!a[$0]++' } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) | sort -u
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1062/1424 modpost: prevent leak when early return no suffix .o in read_symbols()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Robertus Diawan Chris <[email protected]>
[ Upstream commit 9a5b76027ed91680e10f90111d9cba300f96d1ab ]
The allocation for elf info symsearch and hdr from parse_elf() haven't been released when return because of modname didn't have suffix ".o". And it seems like the suffix ".o" check did not depends on parse_elf() to succeed first. So, move the suffix ".o" check before checking parse_elf() result to prevent resource leak when the modname didn't have suffix ".o" and return early.
This is reported by Coverity Scan as "Resource leak".
--- scripts/mod/modpost.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
scripts/mod/modpost.c +3 -3
@@ -1632,14 +1632,14 @@ static void read_symbols(const char *modname)struct elf_info info = { };Elf_Sym *sym; -if (!parse_elf (&info, modname)) -return ; -if (!strends (modname,".o" )) {error ("%s: filename must be suffixed with .o\n" , modname);return ; } +if (!parse_elf (&info, modname)) +return ; +/* strip trailing .o */ mod =new_module (modname,strlen (modname) -strlen (".o" ));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1063/1424 RDMA/erdma: Hold CQ references when processing EQ events
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Xu <[email protected]>
[ Upstream commit 98df2aee1459ee1c62c70cbe9b370d2a532aea36 ]
EQ handlers look up CQs from dev->cq_xa and invoke CQ completion or error callbacks outside the xarray lock. erdma_destroy_cq() can erase the CQ from the xarray and free its queue buffer and doorbell record while a previously scheduled EQ handler is still using the CQ.
Add a CQ refcount and take a reference under the xarray lock with refcount_inc_not_zero(). Remove the CQ from the xarray before dropping the destroy-path reference, then wait for in-flight EQ users before releasing CQ resources.
--- drivers/infiniband/hw/erdma/erdma_eq.c | 6 ++++-- drivers/infiniband/hw/erdma/erdma_verbs.c | 12 +++++++++-- drivers/infiniband/hw/erdma/erdma_verbs.h | 25 +++++++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-)
drivers/infiniband/hw/erdma/erdma_eq.c +4 -2
@@ -52,7 +52,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)if (FIELD_GET (ERDMA_AEQE_HDR_TYPE_MASK ,le32_to_cpu (aeqe->hdr)) ==ERDMA_AE_TYPE_CQ_ERR ) { cqn =le32_to_cpu (aeqe->event_data0); - cq =find_cq_by_cqn (dev, cqn); + cq =erdma_cq_get_by_cqn (dev, cqn);if (!cq)continue ;
@@ -62,6 +62,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)if (cq->ibcq.event_handler) cq->ibcq.event_handler (&event, cq->ibcq.cq_context); +erdma_cq_put (cq); }else { qpn =le32_to_cpu (aeqe->event_data0); qp =find_qp_by_qpn (dev, qpn);
@@ -142,7 +143,7 @@ void erdma_ceq_completion_handler(struct erdma_eq_cb *ceq_cb) poll_cnt++; cqn =FIELD_GET (ERDMA_CEQE_HDR_CQN_MASK ,READ_ONCE (*ceqe)); - cq =find_cq_by_cqn (dev, cqn); + cq =erdma_cq_get_by_cqn (dev, cqn);if (!cq)continue ;
@@ -151,6 +152,7 @@ void erdma_ceq_completion_handler(struct erdma_eq_cb *ceq_cb)if (cq->ibcq.comp_handler) cq->ibcq.comp_handler (&cq->ibcq, cq->ibcq.cq_context); +erdma_cq_put (cq); }notify_eq (&ceq_cb->eq);
drivers/infiniband/hw/erdma/erdma_verbs.c +10 -2
@@ -1228,6 +1228,7 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)struct erdma_dev *dev =to_edev (ibcq->device);struct erdma_ucontext *ctx =rdma_udata_to_drv_context ( udata, struct erdma_ucontext, ibucontext); +unsigned long flags;int err;struct erdma_cmdq_destroy_cq_req req;
@@ -1239,6 +1240,13 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)if (err)return err; +xa_lock_irqsave (&dev->cq_xa, flags); +__xa_erase (&dev->cq_xa, cq->cqn); +xa_unlock_irqrestore (&dev->cq_xa, flags); + +erdma_cq_put (cq); +wait_for_completion (&cq->free); +if (rdma_is_kernel_res (&cq->ibcq.res)) { dma_free_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(cq->depth << CQE_SHIFT),
@@ -1248,8 +1256,6 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)put_mtt_entries (dev, &cq->user_cq.qbuf_mem); } -xa_erase (&dev->cq_xa, cq->cqn); -return 0 ; }
@@ -1658,6 +1664,8 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->ibcq.cqe = depth; cq->depth = depth; cq->assoc_eqn = attr->comp_vector +1 ; +refcount_set (&cq->refcount,1 ); +init_completion (&cq->free); ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq, XA_LIMIT(1, dev->attrs.max_cq - 1),
drivers/infiniband/hw/erdma/erdma_verbs.h +23 -2
@@ -7,6 +7,9 @@#ifndef __ERDMA_VERBS_H__#define __ERDMA_VERBS_H__ +#include <linux/completion.h> +#include <linux/refcount.h> +#include "erdma.h" /* RDMA Capability. */
@@ -261,6 +264,8 @@ struct erdma_cq {u32 depth;u32 assoc_eqn; +refcount_t refcount; +struct completion free;union {struct erdma_kcq_info kern_cq;
@@ -275,9 +280,25 @@ static inline struct erdma_qp *find_qp_by_qpn(struct erdma_dev *dev, int id)return (struct erdma_qp *)xa_load (&dev->qp_xa, id); } -static inline struct erdma_cq *find_cq_by_cqn (struct erdma_dev *dev,int id) +static inline struct erdma_cq *erdma_cq_get_by_cqn (struct erdma_dev *dev, +int id) +{ +struct erdma_cq *cq; +unsigned long flags; + +xa_lock_irqsave (&dev->cq_xa, flags); + cq =xa_load (&dev->cq_xa, id); +if (cq && !refcount_inc_not_zero (&cq->refcount)) + cq =NULL ; +xa_unlock_irqrestore (&dev->cq_xa, flags); + +return cq; +} + +static inline void erdma_cq_put (struct erdma_cq *cq) { -return (struct erdma_cq *)xa_load (&dev->cq_xa, id); +if (refcount_dec_and_test (&cq->refcount)) +complete (&cq->free); }void erdma_qp_get (struct erdma_qp *qp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1064/1424 RDMA/srp: fix heap information leak on a truncated SRP_CRED_REQ
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 961ac0f0c5e414abdd6b33fae84b311d9fde0bd0 ]
srp_recv_done() passes wc->byte_len to srp_process_rsp(). It passes nothing to srp_process_cred_req() and srp_process_aer_req(), which read fixed-size fields from the receive buffer without checking that those fields were received.
The buffer size is max_ti_iu_len, which comes from the login response and is not validated. A target that advertises 8 and then sends an 8-byte SRP_CRED_REQ makes the initiator read req->tag from beyond the end of the buffer. req->tag is copied into the SRP_CRED_RSP and sent back, so those bytes reach the target. SRP_AER_REQ behaves the same way and also reads req->lun.
The leak is 8 bytes per response. max_ti_iu_len also decides which slab cache the buffer comes from. With 8 the buffer is a kmalloc-8 object and the read is entirely outside it:
BUG: KASAN: slab-out-of-bounds in srp_recv_done+0x172b/0x1aa0 Read of size 8 at addr ffff888104714da8 by task kworker/u8:3/50 which belongs to the cache kmalloc-8 of size 8 The buggy address is located 0 bytes to the right of allocated 8-byte region [ffff888104714da0, ffff888104714da8)
Without KASAN the returned bytes are whatever is next in the slab. One run returned ".strtab".
rsp->data[3] in srp_process_rsp() has the same problem: only resp_data_len is checked before it is read.
Drop a request that is shorter than the structure being parsed, and check byte_len before the tsk_mgmt read.
--- drivers/infiniband/ulp/srp/ib_srp.c | 45 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +30 -15
@@ -1943,7 +1943,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp, ch->req_lim +=be32_to_cpu (rsp->req_lim_delta);if (rsp->tag == ch->tsk_mgmt_tag) { ch->tsk_mgmt_status =-1 ; -if (be32_to_cpu (rsp->resp_data_len) >=4 ) +if (be32_to_cpu (rsp->resp_data_len) >=4 && + byte_len >=sizeof (*rsp) +4 ) ch->tsk_mgmt_status = rsp->data[3 ];complete (&ch->tsk_mgmt_done); }else {
@@ -2043,13 +2044,20 @@ static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, }static void srp_process_cred_req (struct srp_rdma_ch *ch, -struct srp_cred_req *req) +struct srp_cred_req *req,u32 byte_len) { -struct srp_cred_rsp rsp = { - .opcode =SRP_CRED_RSP , - .tag = req->tag, - }; -s32 delta =be32_to_cpu (req->req_lim_delta); +struct srp_cred_rsp rsp = { .opcode =SRP_CRED_RSP }; +s32 delta; + +if (byte_len <sizeof (*req)) { +shost_printk (KERN_ERR , ch->target->scsi_host,PFX +"dropping truncated SRP_CRED_REQ (%u bytes received, %zu expected)\n" , + byte_len,sizeof (*req)); +return ; + } + + rsp.tag = req->tag; + delta =be32_to_cpu (req->req_lim_delta);if (srp_response_common (ch, delta, &rsp,sizeof (rsp))) shost_printk(KERN_ERR, ch->target->scsi_host, PFX
@@ -2057,14 +2065,21 @@ static void srp_process_cred_req(struct srp_rdma_ch *ch, }static void srp_process_aer_req (struct srp_rdma_ch *ch, -struct srp_aer_req *req) +struct srp_aer_req *req,u32 byte_len) {struct srp_target_port *target = ch->target; -struct srp_aer_rsp rsp = { - .opcode =SRP_AER_RSP , - .tag = req->tag, - }; -s32 delta =be32_to_cpu (req->req_lim_delta); +struct srp_aer_rsp rsp = { .opcode =SRP_AER_RSP }; +s32 delta; + +if (byte_len <sizeof (*req)) { +shost_printk (KERN_ERR , target->scsi_host,PFX +"dropping truncated SRP_AER_REQ (%u bytes received, %zu expected)\n" , + byte_len,sizeof (*req)); +return ; + } + + rsp.tag = req->tag; + delta =be32_to_cpu (req->req_lim_delta);shost_printk (KERN_ERR , target->scsi_host,PFX "ignoring AER for LUN %llu\n" ,scsilun_to_int (&req->lun));
@@ -2106,11 +2121,11 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)break ;case SRP_CRED_REQ : -srp_process_cred_req (ch, iu->buf); +srp_process_cred_req (ch, iu->buf, wc->byte_len);break ;case SRP_AER_REQ : -srp_process_aer_req (ch, iu->buf); +srp_process_aer_req (ch, iu->buf, wc->byte_len);break ;case SRP_T_LOGOUT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1065/1424 ARM: 9485/1: mm: acquire mmap write lock around show_pte() for user faults
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xie Yuanbin <[email protected]>
[ Upstream commit 1039bffd6ae9c75b42b7d148d6c1106134107b66 ]
When CONFIG_DEBUG_USER=y, and cmdline "user_debug=31" is set, a user fault may trigger show_pte() without any lock.
If another thread in the same process concurrently calls munmap(), the page table pages may be freed while show_pte() is still traversing them, causing a use-after-free in show_pte().
If CONFIG_ARM_LPAE=y, this may cause a kernel panic if the pages table of PMD are freed when show_pte() is running.
Acquire mmap_write_lock() around show_pte() for user faults to fix the contention.
For user faults, additionally restrict that show_pte() is called only when the addr is a user-space address (addr < TASK_SIZE). This is because the lock of tsk->mm only protects the virtual memory of user address space, furthermore, dumping the page tables of a kernel-space address for user faults is unnecessary and may have security implications.
Keep everything unchanged for kernel faults, because the kernel is already in the "oops" state, acquiring a lock may risk a deadlock.
--- arch/arm/mm/fault.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
arch/arm/mm/fault.c +14 -2
@@ -205,7 +205,11 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,pr_err ("8<--- cut here ---\n" );pr_err ("%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n" , tsk->comm, sig, addr, fsr); -show_pte (KERN_ERR , tsk->mm, addr); +if (likely (addr <TASK_SIZE )) { +mmap_write_lock (tsk->mm); +show_pte (KERN_ERR , tsk->mm, addr); +mmap_write_unlock (tsk->mm); + } show_regs(regs); }#endif
@@ -586,7 +590,15 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)pr_alert ("8<--- cut here ---\n" );pr_alert ("Unhandled fault: %s (0x%03x) at 0x%08lx\n" , inf->name, fsr, addr); -show_pte (KERN_ALERT , current->mm, addr); +if (likely (user_mode (regs))) { +if (addr <TASK_SIZE ) { +mmap_write_lock (current->mm); +show_pte (KERN_ALERT , current->mm, addr); +mmap_write_unlock (current->mm); + } + }else { +show_pte (KERN_ALERT , current->mm, addr); + }arm_notify_die ("" , regs, inf->sig, inf->code, (void __user *)addr, fsr,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1066/1424 ocfs2: synchronize heartbeat callbacks with o2net teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 3e326f3bf16506873777444608e8b715aab74a7a ]
Patch series "ocfs2: harden heartbeat teardown races".
This series fixes two OCFS2 heartbeat/o2net teardown races found by KASAN.
This patch (of 2):
Heartbeat callbacks stay registered while configfs local-node teardown enters o2net_stop_listening(). A node-down event can still run through o2net_disconnect_node() and o2net_set_nn_state() while teardown is destroying o2net_wq, so the later queue/flush operations can hit a dead workqueue. KASAN has caught this as a slab-use-after-free in __queue_work() with the call chain:
KASAN slab-use-after-free in __queue_work+0x56/0xa90
Read of size 4 Call trace: dump_stack_lvl+0x66/0xa0 print_report+0xce/0x630 __queue_work+0x56/0xa90 srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x19f/0x330 kasan_report+0xe0/0x110 __queue_delayed_work+0x58/0x1e0 queue_delayed_work_on+0xb4/0xc0 o2net_set_nn_state+0x467/0x840 o2net_disconnect_node+0x7b/0xe0 o2net_hb_node_down_cb+0x54/0x60 o2hb_run_event_list+0x236/0x2d0 o2hb_check_slot+0xad4/0xbc0 lock_release+0xc8/0x290 o2hb_check_slot+0x9ea/0xbc0 trace_hardirqs_on+0x18/0x130 o2hb_do_disk_heartbeat+0x646/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) __lock_acquire+0x466/0x2260 lockdep_hardirqs_on_prepare+0xea/0x1a0 ktime_get_with_offset+0xe9/0x230 o2hb_thread+0x14e/0x770 kthread+0x1ad/0x1f0 ret_from_fork+0x3c9/0x540 __switch_to+0x2e9/0x730 ret_from_fork_asm+0x1a/0x30 Allocated by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_noprof+0x292/0x760 __alloc_workqueue+0x736/0xc60 alloc_workqueue_noprof+0xb1/0x110 o2net_start_listening+0xe5/0x430 o2nm_node_local_store+0x184/0x310 configfs_write_iter+0x18a/0x210 vfs_write+0x469/0x810 ksys_write+0xd2/0x170 do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x313/0x590 rcu_core+0x4f4/0x1320 handle_softirqs+0x156/0x660
queue_delayed_work_ono2net_set_nn_stateo2net_disconnect_nodeo2net_hb_node_down_cbo2hb_run_event_list
Keep heartbeat callbacks registered so quorum state still tracks node state, but stop them from driving o2net reconnect/disconnect work once local teardown starts. Mark the transport offline before destroying o2net_wq, wait for any in-flight heartbeat callback to finish, and delay bring-up replay until the new local node is published through o2nm_this_node().
The replay also has to stay serialized with heartbeat callback delivery. Otherwise a live-node snapshot can be copied, a real hb_down callback can install -ENOTCONN for a peer, and the stale replay can call o2net_hb_node_up() for that same peer and queue reconnect work even though heartbeat is already down.
The buggy scenario involves two paths, with each column showing the order within that path:
local-node teardown: heartbeat node-down callback:
1. configfs local-off enters 1. o2hb_run_event_list() invokes
o2net_stop_listening(). o2net_hb_node_down_cb().
2. teardown heads for 2. the callback reaches
destroy_workqueue(o2net_wq). o2net_disconnect_node() and
o2net_set_nn_state().
3. teardown destroys and NULLs 3. the callback flushes or queues
o2net_wq. work through o2net_wq.
--- fs/ocfs2/cluster/heartbeat.c | 43 ++++++++++++++---- fs/ocfs2/cluster/heartbeat.h | 5 ++ fs/ocfs2/cluster/nodemanager.c | 4 ++ fs/ocfs2/cluster/tcp.c | 83 +++++++++++++++++++++++++++------- fs/ocfs2/cluster/tcp.h | 1 + 5 files changed, 109 insertions(+), 27 deletions(-)
fs/ocfs2/cluster/heartbeat.c +33 -10
@@ -1456,13 +1456,38 @@ void o2hb_init(void)o2hb_debug_init (); } -/* if we're already in a callback then we're already serialized by the sem */ -static void o2hb_fill_node_map_from_callback (unsigned long *map, -unsigned int bits) +static void __o2hb_fill_node_map (unsigned long *map,unsigned int bits) {bitmap_copy (map, o2hb_live_node_bitmap, bits); } +void o2hb_callback_read_lock (void ) +{ +down_read (&o2hb_callback_sem); +} + +void o2hb_callback_read_unlock (void ) +{ +up_read (&o2hb_callback_sem); +} + +void o2hb_synchronize_callbacks (void ) +{ +down_write (&o2hb_callback_sem); +up_write (&o2hb_callback_sem); +} + +/* +* Callers must already hold o2hb_callback_sem for read or write so the copy +* stays serialized with callback delivery. +*/ +void o2hb_fill_node_map_locked (unsigned long *map,unsigned int bits) +{ +spin_lock (&o2hb_live_lock); +__o2hb_fill_node_map (map, bits); +spin_unlock (&o2hb_live_lock); +} +/* * get a map of all nodes that are heartbeating in any regions */
@@ -1470,11 +1495,9 @@ void o2hb_fill_node_map(unsigned long *map, unsigned int bits) {/* callers want to serialize this map and callbacks so that they * can trust that they don't miss nodes coming to the party */ -down_read (&o2hb_callback_sem); -spin_lock (&o2hb_live_lock); -o2hb_fill_node_map_from_callback (map, bits); -spin_unlock (&o2hb_live_lock); -up_read (&o2hb_callback_sem); +o2hb_callback_read_lock (); +o2hb_fill_node_map_locked (map, bits); +o2hb_callback_read_unlock (); }EXPORT_SYMBOL_GPL (o2hb_fill_node_map);
@@ -2543,7 +2566,7 @@ int o2hb_check_node_heartbeating_no_sem(u8 node_num)unsigned long testing_map[BITS_TO_LONGS (O2NM_MAX_NODES )];spin_lock (&o2hb_live_lock); -o2hb_fill_node_map_from_callback (testing_map,O2NM_MAX_NODES ); +__o2hb_fill_node_map (testing_map,O2NM_MAX_NODES );spin_unlock (&o2hb_live_lock);if (!test_bit (node_num, testing_map)) { mlog(ML_HEARTBEAT,
@@ -2560,7 +2583,7 @@ int o2hb_check_node_heartbeating_from_callback(u8 node_num) {unsigned long testing_map[BITS_TO_LONGS (O2NM_MAX_NODES )]; -o2hb_fill_node_map_from_callback (testing_map,O2NM_MAX_NODES ); +o2hb_fill_node_map_locked (testing_map,O2NM_MAX_NODES );if (!test_bit (node_num, testing_map)) { mlog(ML_HEARTBEAT, "node (%u) does not have heartbeating enabled.\n",
fs/ocfs2/cluster/heartbeat.h +5 -0
@@ -58,6 +58,11 @@ int o2hb_register_callback(const char *region_uuid, struct o2hb_callback_func *hc);void o2hb_unregister_callback (const char *region_uuid,struct o2hb_callback_func *hc); +void o2hb_callback_read_lock (void ); +void o2hb_callback_read_unlock (void ); +void o2hb_synchronize_callbacks (void ); +void o2hb_fill_node_map_locked (unsigned long *map, +unsigned int bits);void o2hb_fill_node_map (unsigned long *map,unsigned int bits);void o2hb_exit (void );
fs/ocfs2/cluster/nodemanager.c +4 -0
@@ -325,6 +325,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,struct o2nm_node *node =to_o2nm_node (item);struct o2nm_cluster *cluster;unsigned long tmp; +bool starting = false;char *p = (char *)page;ssize_t ret;
@@ -361,6 +362,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, ret =o2net_start_listening (node);if (ret) goto out; + starting = true; } if (!tmp && cluster->cl_has_local &&
@@ -373,6 +375,8 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,if (node->nd_local) { cluster->cl_has_local = tmp; cluster->cl_local_node = node->nd_num; +if (starting) +o2net_complete_start_listening (node); } ret = count;
fs/ocfs2/cluster/tcp.c +66 -17
137 lines not on this page · raw message
fs/ocfs2/cluster/tcp.h +1 -0
@@ -96,6 +96,7 @@ struct o2nm_node;int o2net_register_hb_callbacks (void );void o2net_unregister_hb_callbacks (void );int o2net_start_listening (struct o2nm_node *node); +void o2net_complete_start_listening (struct o2nm_node *node);void o2net_stop_listening (struct o2nm_node *node);void o2net_disconnect_node (struct o2nm_node *node);int o2net_num_connected_peers (void );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1067/1424 drm/sun4i: vi scaler: Fix coefficient selection
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 5c31990b21f0b535732deb2b658b78b07464f56c ]
Currently, vertical coefficients are selected based on horizontal scaling, which is wrong. Additionally, chroma coefficients should be selected based on format subsampling.
Fix all that.
--- drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c +12 -6
@@ -891,20 +891,26 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base, lan3coefftab32_left[offset + i]);regmap_write (map,SUN8I_SCALER_VSU_YHCOEFF1 (base, i), lan3coefftab32_right[offset + i]); + } + offset =sun8i_vi_scaler_coef_index (vstep) * +SUN8I_VI_SCALER_COEFF_COUNT ; +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) +regmap_write (map,SUN8I_SCALER_VSU_YVCOEFF (base, i), + lan2coefftab32[offset + i]); + + offset =sun8i_vi_scaler_coef_index (hstep / format->hsub) * +SUN8I_VI_SCALER_COEFF_COUNT ; +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) {regmap_write (map,SUN8I_SCALER_VSU_CHCOEFF0 (base, i), ch_left[offset + i]);regmap_write (map,SUN8I_SCALER_VSU_CHCOEFF1 (base, i), ch_right[offset + i]); } - - offset =sun8i_vi_scaler_coef_index (hstep) * + offset =sun8i_vi_scaler_coef_index (vstep / format->vsub) *SUN8I_VI_SCALER_COEFF_COUNT ; -for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) { -regmap_write (map,SUN8I_SCALER_VSU_YVCOEFF (base, i), - lan2coefftab32[offset + i]); +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++)regmap_write (map,SUN8I_SCALER_VSU_CVCOEFF (base, i), cy[offset + i]); - } }void sun8i_vi_scaler_enable (struct sun8i_mixer *mixer,int layer,bool enable)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1068/1424 of: property: add missing kerneldoc for of_graph_get_endpoint_count()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 4c3b386c46065c0d26ae5503e73d6634f24e2d36 ]
of_graph_get_endpoint_count() doesn't have kerneldoc. Add it.
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/of/property.c +6 -0
@@ -813,6 +813,12 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) }EXPORT_SYMBOL (of_graph_get_remote_port); +/** +* of_graph_get_endpoint_count() - get the number of endpoints in a device node +* @np: parent device node containing ports and endpoints +* +* Return: count of endpoint of this device node +*/ int of_graph_get_endpoint_count (const struct device_node *np) {struct device_node *endpoint;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1069/1424 of: property: use unsigned int return on of_graph_get_endpoint_count()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 574849054d97cee5be78d6c149d84685647fe774 ]
Because of of_graph_get_endpoint_count() doesn't report error, just return count of endpoint, the return type should be unsigned. Tidyup it.
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 4 ++-- include/linux/of_graph.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/of/property.c +2 -2
@@ -819,10 +819,10 @@ EXPORT_SYMBOL(of_graph_get_remote_port);* * Return: count of endpoint of this device node */ -int of_graph_get_endpoint_count (const struct device_node *np) +unsigned int of_graph_get_endpoint_count (const struct device_node *np) {struct device_node *endpoint; -int num =0 ; +unsigned int num =0 ;for_each_endpoint_of_node (np, endpoint) num++;
include/linux/of_graph.h +2 -2
@@ -41,7 +41,7 @@ struct of_endpoint {bool of_graph_is_present (const struct device_node *node);int of_graph_parse_endpoint (const struct device_node *node,struct of_endpoint *endpoint); -int of_graph_get_endpoint_count (const struct device_node *np); +unsigned int of_graph_get_endpoint_count (const struct device_node *np);struct device_node *of_graph_get_port_by_id (struct device_node *node,u32 id);struct device_node *of_graph_get_next_endpoint (const struct device_node *parent,struct device_node *previous);
@@ -68,7 +68,7 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,return -ENOSYS ; } -static inline int of_graph_get_endpoint_count (const struct device_node *np) +static inline unsigned int of_graph_get_endpoint_count (const struct device_node *np) {return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1070/1424 of: property: add of_graph_get_next_port()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 02ac5f9d6caec96071103f7c62b5117526e47b64 ]
We have endpoint base functions
- of_graph_get_next_endpoint()
- of_graph_get_endpoint_count()
- for_each_endpoint_of_node()
Here, for_each_endpoint_of_node() loop finds each endpoints
ports {
port@0 {
(1) endpoint {...};
};
port@1 {
(2) endpoint {...};
};
...
};In above case, it finds endpoint as (1) -> (2) -> ...
Basically, user/driver knows which port is used for what, but not in all cases. For example on flexible/generic driver case, how many ports are used is not fixed.
For example Sound Generic Card driver which is very flexible/generic and used from many venders can't know how many ports are used, and used for what, because it depends on each vender SoC and/or its used board.
And more, the port can have multi endpoints. For example Generic Sound Card case, it supports many type of connection between CPU / Codec, and some of them uses multi endpoint in one port. see below.
ports {
(A) port@0 {
(1) endpoint@0 {...};
(2) endpoint@1 {...};
};
(B) port@1 {
(3) endpoint {...};
};
...
};Generic Sound Card want to handle each connection via "port" base instead of "endpoint" base. But, it is very difficult to handle each "port" via existing for_each_endpoint_of_node(). Because getting each "port" via of_get_parent() from each "endpoint" doesn't work. For example in above case, both (1) (2) endpoint has same "port" (= A).
Add "port" base functions.
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 54 ++++++++++++++++++++++++++++++++++++++++ include/linux/of_graph.h | 28 +++++++++++++++++++++ 2 files changed, 82 insertions(+)
drivers/of/property.c +54 -0
@@ -631,6 +631,43 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) }EXPORT_SYMBOL (of_graph_get_port_by_id); +/** +* of_graph_get_next_port() - get next port node. +* @parent: pointer to the parent device node, or parent ports node +* @prev: previous port node, or NULL to get first +* +* Parent device node can be used as @parent whether device node has ports node +* or not. It will work same as ports@0 node. +* +* Return: A 'port' node pointer with refcount incremented. Refcount +* of the passed @prev node is decremented. +*/ +struct device_node *of_graph_get_next_port (const struct device_node *parent, +struct device_node *prev) +{ +if (!parent) +return NULL ; + +if (!prev) { + struct device_node *node __free(device_node) = +of_get_child_by_name (parent,"ports" ); + +if (node) + parent = node; + +return of_get_child_by_name (parent,"port" ); + } + +do { + prev =of_get_next_child (parent, prev); +if (!prev) +break ; + }while (!of_node_name_eq (prev,"port" )); + +return prev; +} +EXPORT_SYMBOL (of_graph_get_next_port); +/** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node
@@ -831,6 +868,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) }EXPORT_SYMBOL (of_graph_get_endpoint_count); +/** +* of_graph_get_port_count() - get the number of port in a device or ports node +* @np: pointer to the device or ports node +* +* Return: count of port of this device or ports node +*/ +unsigned int of_graph_get_port_count (struct device_node *np) +{ +unsigned int num =0 ; + +for_each_of_graph_port (np, port) + num++; + +return num; +} +EXPORT_SYMBOL (of_graph_get_port_count); +/** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint
include/linux/of_graph.h +28 -0
@@ -11,6 +11,7 @@#ifndef __LINUX_OF_GRAPH_H#define __LINUX_OF_GRAPH_H +#include <linux/cleanup.h> #include <linux/types.h> #include <linux/errno.h>
@@ -37,14 +38,29 @@ struct of_endpoint {for (child =of_graph_get_next_endpoint (parent,NULL ); child !=NULL ; \ child =of_graph_get_next_endpoint (parent, child)) +/** +* for_each_of_graph_port - iterate over every port in a device or ports node +* @parent: parent device or ports node containing port +* @child: loop variable pointing to the current port node +* +* When breaking out of the loop, and continue to use the @child, you need to +* use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. + */ +#define for_each_of_graph_port (parent, child) \ + for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ + child != NULL; child = of_graph_get_next_port(parent, child)) +#ifdef CONFIG_OF bool of_graph_is_present (const struct device_node *node);int of_graph_parse_endpoint (const struct device_node *node,struct of_endpoint *endpoint);unsigned int of_graph_get_endpoint_count (const struct device_node *np); +unsigned int of_graph_get_port_count (struct device_node *np);struct device_node *of_graph_get_port_by_id (struct device_node *node,u32 id);struct device_node *of_graph_get_next_endpoint (const struct device_node *parent,struct device_node *previous); +struct device_node *of_graph_get_next_port (const struct device_node *parent, +struct device_node *port);struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg); struct device_node *of_graph_get_remote_endpoint(
@@ -73,6 +89,11 @@ static inline unsigned int of_graph_get_endpoint_count(const struct device_nodereturn 0 ; } +static inline unsigned int of_graph_get_port_count (struct device_node *np) +{ +return 0 ; +} +static inline struct device_node *of_graph_get_port_by_id (struct device_node *node,u32 id) {
@@ -86,6 +107,13 @@ static inline struct device_node *of_graph_get_next_endpoint(return NULL ; } +static inline struct device_node *of_graph_get_next_port ( +const struct device_node *parent, +struct device_node *previous) +{ +return NULL ; +} +static inline struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1071/1424 of: property: add of_graph_get_next_port_endpoint()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 58fe47d6ac7413172e1fa88324fb1b4c0eb2c0a2 ]
We already have of_graph_get_next_endpoint(), but it is not intuitive to use in some case.
(X) node {
(Y) ports {
(P0) port@0 { endpoint { remote-endpoint = ...; };};
(P10) port@1 { endpoint { remote-endpoint = ...; };
(P11) endpoint { remote-endpoint = ...; };};
(P2) port@2 { endpoint { remote-endpoint = ...; };};
};
};For example, if I want to handle port@1's 2 endpoints (= P10, P11), I want to use like below
P10 = of_graph_get_next_endpoint(port1, NULL); P11 = of_graph_get_next_endpoint(port1, P10);
But 1st one will be error, because of_graph_get_next_endpoint() requested 1st parameter is "node" (X) or "ports" (Y), not but "port". Below works well, but it will get P0
P0 = of_graph_get_next_endpoint(node, NULL); P0 = of_graph_get_next_endpoint(ports, NULL);
In other words, we can't handle P10/P11 directly via of_graph_get_next_endpoint().
There is another non intuitive behavior on of_graph_get_next_endpoint(). In case of if I could get P10 pointer for some way, and if I want to handle port@1 things by loop, I would like use it like below
/*
* "ep" is now P10, and handle port1 things here,
* but we don't know how many endpoints port1 have.
*
* Because "ep" is non NULL now, we can use port1
* as of_graph_get_next_endpoint(port1, xxx)
*/
do {
/* do something for port1 specific things here */
} while (ep = of_graph_get_next_endpoint(port1, ep))But it also not worked as I expected.
I expect it will be P10 -> P11 -> NULL,
but it will be P10 -> P11 -> P2, becauseof_graph_get_next_endpoint() will fetch "endpoint" beyond the "port". It is not useful for generic driver.
To handle endpoint more intuitive, create of_graph_get_next_port_endpoint()
of_graph_get_next_port_endpoint(port1, NULL); // P10 of_graph_get_next_port_endpoint(port1, P10); // P11 of_graph_get_next_port_endpoint(port1, P11); // NULL
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 27 +++++++++++++++++++++++++++ include/linux/of_graph.h | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+)
drivers/of/property.c +27 -0
@@ -668,6 +668,33 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent, }EXPORT_SYMBOL (of_graph_get_next_port); +/** +* of_graph_get_next_port_endpoint() - get next endpoint node in port. +* If it reached to end of the port, it will return NULL. +* @port: pointer to the target port node +* @prev: previous endpoint node, or NULL to get first +* +* Return: An 'endpoint' node pointer with refcount incremented. Refcount +* of the passed @prev node is decremented. +*/ +struct device_node *of_graph_get_next_port_endpoint (const struct device_node *port, +struct device_node *prev) +{ +while (1 ) { + prev =of_get_next_child (port, prev); +if (!prev) +break ; +if (WARN (!of_node_name_eq (prev,"endpoint" ), +"non endpoint node is used (%pOF)" , prev)) +continue ; + +break ; + } + +return prev; +} +EXPORT_SYMBOL (of_graph_get_next_port_endpoint); +/** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node
include/linux/of_graph.h +21 -0
@@ -50,6 +50,18 @@ struct of_endpoint { for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ child !=NULL ; child =of_graph_get_next_port (parent, child)) +/** +* for_each_of_graph_port_endpoint - iterate over every endpoint in a port node +* @parent: parent port node +* @child: loop variable pointing to the current endpoint node +* +* When breaking out of the loop, and continue to use the @child, you need to +* use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. + */ +#define for_each_of_graph_port_endpoint (parent, child) \ + for (struct device_node *child __free(device_node) = of_graph_get_next_port_endpoint(parent, NULL);\ + child != NULL; child = of_graph_get_next_port_endpoint(parent, child)) +#ifdef CONFIG_OF bool of_graph_is_present (const struct device_node *node); int of_graph_parse_endpoint(const struct device_node *node,
@@ -61,6 +73,8 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous);struct device_node *of_graph_get_next_port (const struct device_node *parent,struct device_node *port); +struct device_node *of_graph_get_next_port_endpoint (const struct device_node *port, +struct device_node *prev);struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg); struct device_node *of_graph_get_remote_endpoint(
@@ -114,6 +128,13 @@ static inline struct device_node *of_graph_get_next_port(return NULL ; } +static inline struct device_node *of_graph_get_next_port_endpoint ( +const struct device_node *parent, +struct device_node *previous) +{ +return NULL ; +} +static inline struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1072/1424 drm/sun4i: tcon: Set output mux for DSI and LVDS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 9c90199b39637ad94253c4fd8e7b1333ca1d3e0d ]
DSI and LVDS skip output mux setup, so TCON TOP cannot route the selected mixer. Configure them like other channel 0 outputs.
In practice this matters for D1, where channel 0 TCONs are fed through TCON TOP. The remaining set_mux implementations only handle TMDS and return an error for other encoder types, as before.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sun4i/sun4i_tcon.c +2 -0
@@ -717,9 +717,11 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,case DRM_MODE_ENCODER_DSI :/* DSI is tied to special case of CPU interface */ sun4i_tcon0_mode_set_cpu (tcon, encoder, mode); +sun4i_tcon_set_mux (tcon,0 , encoder);break ;case DRM_MODE_ENCODER_LVDS :sun4i_tcon0_mode_set_lvds (tcon, encoder, mode); +sun4i_tcon_set_mux (tcon,0 , encoder);break ;case DRM_MODE_ENCODER_NONE :sun4i_tcon0_mode_set_rgb (tcon, encoder, mode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1073/1424 drm/sun4i: tcon: Drop TCON TOP device reference
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 8208832a38ff3d2560eb8a77a9d7a2f17d8ebcdc ]
of_find_device_by_node() takes a device reference. Drop it after mux configuration succeeds.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
drivers/gpu/drm/sun4i/sun4i_tcon.c +9 -10
@@ -1409,7 +1409,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, {struct device_node *port, *remote;struct platform_device *pdev; -int id, ret; +int id, ret =0 ;/* find TCON TOP platform device and TCON id */
@@ -1432,21 +1432,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,if (IS_ENABLED (CONFIG_DRM_SUN8I_TCON_TOP ) && encoder->encoder_type ==DRM_MODE_ENCODER_TMDS ) { ret =sun8i_tcon_top_set_hdmi_src (&pdev->dev, id); -if (ret) { -put_device (&pdev->dev); -return ret; - } +if (ret) + goto out_put_device; }if (IS_ENABLED (CONFIG_DRM_SUN8I_TCON_TOP )) { ret =sun8i_tcon_top_de_config (&pdev->dev, tcon->id, id); -if (ret) { -put_device (&pdev->dev); -return ret; - } +if (ret) + goto out_put_device; } -return 0 ; +out_put_device: +put_device (&pdev->dev); + +return ret; }static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1074/1424 drm/sun4i: crtc: Propagate layer initialization error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 7061ff05ed4a3cf16e83f7e3ad09cbd212508a32 ]
sun4i_crtc_init() returns plain NULL when layer initialization fails, while all its other error paths return an error pointer. The only caller, sun4i_tcon_bind(), checks the result with IS_ERR() and happily continues with tcon->crtc set to NULL. sun4i_rgb_init() and sun4i_lvds_init() then dereference it in drm_crtc_mask(), which oopses.
Return the error pointer instead.
--- drivers/gpu/drm/sun4i/sun4i_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun4i_crtc.c +1 -1
@@ -208,7 +208,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, planes =sunxi_engine_layers_init (drm, engine);if (IS_ERR (planes)) {dev_err (drm->dev,"Couldn't create the planes\n" ); -return NULL ; +return ERR_CAST (planes); }/* find primary and cursor planes for drm_crtc_init_with_planes */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1075/1424 drm/sun4i: tcon: Drop remote endpoint reference
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 3f77e4072630e2301efdbe521e7fca10311043ec ]
sun4i_tcon_of_get_id_from_port() never drops the reference taken by of_graph_get_remote_endpoint(). The function is not only called during bind, but also on every mode set through sun8i_r40_tcon_tv_set_mux(), so the leak accumulates.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/sun4i/sun4i_tcon.c +1 -0
@@ -972,6 +972,7 @@ static int sun4i_tcon_of_get_id_from_port(struct device_node *port)continue ; ret =of_property_read_u32 (remote,"reg" , ®); +of_node_put (remote);if (ret)continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1076/1424 drm/sun4i: dw-hdmi: Drop TCON TOP port reference
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit d2a242e5688a17b79c89cd966cd31820c5096d80 ]
When the HDMI controller is fed by TCON TOP, the port node used to enumerate the possible CRTCs is never released.
--- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +2 -0
@@ -83,6 +83,8 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm,of_node_put (remote_port); } } + +of_node_put (port); }else { crtcs =drm_of_find_possible_crtcs (drm, node); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1077/1424 drm/sun4i: hdmi-phy: Fix H6 8-bit MPLL config at 594 MHz
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 0ba6deddaae74f0539c0303bfb5f860adbe1a68b ]
The 8-bit entry of the last MPLL row (594 MHz) doesn't lock reliably on H6. 4K@60 RGB/YUV444, which is the mode that reaches this entry, doesn't come up.
Align the value with the vendor driver. Other entries are left alone, they are used by lower pixel clocks which work fine.
Tested with 4K@60 on a LG TV.
--- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +1 -1
@@ -91,7 +91,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { }, }, { 594000000, { - { 0x1a40, 0x0003 }, + { 0x1a7c, 0x0003 }, { 0x3b4c, 0x0003 }, { 0x5a64, 0x0003 }, },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1078/1424 cpufreq: imx6q: fix devres accumulation across driver rebind
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 22c23c72c3b21fa3ec3db5070dfc0582794e0ef9 ]
imx6_soc_volt is allocated with devm_kcalloc(cpu_dev, ...), where cpu_dev is the CPU device from get_cpu_device(0). That device is never unbound, so its devres list is never released, and imx6q_cpufreq_remove() does not free the array either. Every probe therefore adds an allocation that stays for the lifetime of the system.
Allocate against the platform device instead. Its devres is released when the driver is unbound, which is exactly the lifetime the array wants:imx6q_set_target() reads it, and nothing may reach that after cpufreq_unregister_driver().
That makes the array actually go away on unbind, so also clear the file-scope pointer in remove and on the failed-probe path, rather than leave it pointing at memory devres is about to release.
Tested by rebinding the driver on qemu's mcimx6ul-evk.
--- drivers/cpufreq/imx6q-cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/cpufreq/imx6q-cpufreq.c +3 -1
@@ -416,7 +416,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) }/* Make imx6_soc_volt array's size same as arm opp number */ - imx6_soc_volt =devm_kcalloc (cpu_dev, num,sizeof (*imx6_soc_volt), + imx6_soc_volt =devm_kcalloc (&pdev->dev, num,sizeof (*imx6_soc_volt),GFP_KERNEL );if (imx6_soc_volt ==NULL ) { ret = -ENOMEM ;
@@ -501,6 +501,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)return 0 ; free_freq_table: + imx6_soc_volt =NULL ;dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table); out_free_opp:dev_pm_opp_of_remove_table (cpu_dev);
@@ -522,6 +523,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)static void imx6q_cpufreq_remove (struct platform_device *pdev) {cpufreq_unregister_driver (&imx6q_cpufreq_driver); + imx6_soc_volt =NULL ;dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table);dev_pm_opp_of_remove_table (cpu_dev);regulator_put (arm_reg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1079/1424 cpufreq: imx6q: fix out-of-bounds write when probed more than once
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 8c3afcf27fa4582c1ab912503dc8a4ebb8dc0f82 ]
imx6_soc_volt is allocated fresh on every probe, sized to the number of ARM OPPs:
imx6_soc_volt = devm_kcalloc(cpu_dev, num, sizeof(*imx6_soc_volt), GFP_KERNEL);
but it is filled through soc_opp_count, which has static storage and is never reset. A second bind after an unbind keeps indexing from where the first one stopped, and writes past the end of the new array.
Unbinding and rebinding the driver on qemu's mcimx6ul-evk, under KASAN:
BUG: KASAN: slab-out-of-bounds in imx6q_cpufreq_probe+0x3b0/0xa34 Write of size 4 at addr c5e90480 by task binder/73 imx6q_cpufreq_probe from platform_probe+0x88/0xe4 platform_probe from really_probe+0x108/0x384 bind_store from kernfs_fop_write_iter+0x1b4/0x28c
The write lands one u32 past the end of the allocation.
soc_opp_count is only read a few lines below the loop that fills it, so it never needed static storage. Make it a local.
--- drivers/cpufreq/imx6q-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/imx6q-cpufreq.c +1 -1
@@ -53,7 +53,6 @@ static unsigned int max_freq;static unsigned int transition_latency;static u32 *imx6_soc_volt; -static u32 soc_opp_count;static int imx6q_set_target (struct cpufreq_policy *policy,unsigned int index) {
@@ -346,6 +345,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)const struct property *prop;const __be32 *val;u32 nr, i, j; +u32 soc_opp_count =0 ; cpu_dev =get_cpu_device (0 );if (!cpu_dev) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1080/1424 IB/isert: delay the final Login Response until the session is registered
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 464f5afa92d071a226f88424803b0fcf88093ede ]
isert_put_login_tx() puts the final Login Response on the wire before __transport_register_session(), which iscsi_post_login_handler() reaches only after iscsi_target_do_login() returns. An initiator that issues a SCSI command as soon as it sees that response can have it executed against an se_session whose se_tpg is still NULL, and the ib-comp-wq worker oopses on the NULL dereference.
Oops: general protection fault, probably for non-canonical address 0xdffffc000000000f: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000078-0x000000000000007f] CPU: 0 UID: 0 PID: 178 Comm: kworker/0:1H Not tainted 7.2.0-rc5-V2CTL-gf5098b6bae76 #10 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: ib-comp-wq ib_cq_poll_work RIP: 0010:target_submit+0xbe/0x390 Code: fa 48 c1 ea 03 80 3c 02 00 0f 85 89 02 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 64 24 18 49 8d 7c 24 78 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 5a 02 00 00 48 8d 7b 78 4d 8b 6c 24 78 48 b8 00 RSP: 0018:ffff8881058cfa78 EFLAGS: 00010206 RAX: dffffc0000000000 RBX: ffff88810c78c6f0 RCX: ffffffff964bb363 RDX: 000000000000000f RSI: 00000000fffffe00 RDI: 0000000000000078 RBP: 1ffff11020b19f52 R08: 0000000000000001 R09: ffffed1020b19f52 R10: 0000000000000003 R11: ffff88810596c000 R12: 0000000000000000 R13: ffff88810c61b000 R14: ffff88810c6a3400 R15: ffff88810c61b044 FS: 0000000000000000(0000) GS:ffff8881822b2000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1f1b83c000 CR3: 000000006fe72001 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: <TASK> ? __pfx__raw_spin_lock_bh+0x10/0x10 ? __pfx_target_submit+0x10/0x10 ? mutex_lock+0x81/0xe0 ? __pfx_mutex_lock+0x10/0x10 ? iscsit_execute_cmd+0x650/0x850 iscsit_sequence_cmd+0x186/0x3d0 iscsit_process_scsi_cmd+0x87/0x300 isert_recv_done+0x1002/0x2390 ? __pfx_isert_recv_done+0x10/0x10 ? rxe_poll_cq+0x253/0x3d0 ? finish_task_switch.isra.0+0x1dc/0xa70 __ib_process_cq+0xe1/0x390 ib_cq_poll_work+0x46/0x150 process_one_work+0x633/0x1030 ? assign_work+0x11d/0x370 worker_thread+0x45b/0xd10 ? __pfx_worker_thread+0x10/0x10 ? __pfx_worker_thread+0x10/0x10 kthread+0x2c6/0x3b0 ? recalc_sigpending+0x15c/0x1e0 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x36e/0x5a0 ? __pfx_ret_from_fork+0x10/0x10 ? __switch_to+0x572/0xdd0 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]---
Delay the final Login Response instead. isert_get_rx_pdu() runs from iscsi_target_rx_thread() after conn->rx_login_comp, completed by iscsi_post_login_handler() after __transport_register_session(); iscsi-TCP and cxgbit already take PDUs from that thread, isert alone does not. The buffers are still posted first, so the initiator's first command does not meet an empty receive queue and nothing depends on RNR flow control, and the header and payload live in isert_conn, not in the struct iscsi_login that iscsi_target_nego_release() frees first.
Over rxe, 400 login cycles per run, the oops appeared in 10 of 20 unpatched runs and in none of 20 runs with this patch. An initiator that never waits is handled by the next patch.
Not tested: iWARP, discovery sessions over iSER, and real HCAs.
--- drivers/infiniband/ulp/isert/ib_isert.c | 20 ++++++++++++++++++-- drivers/infiniband/ulp/isert/ib_isert.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-)
drivers/infiniband/ulp/isert/ib_isert.c +18 -2
@@ -59,6 +59,8 @@ static void isert_recv_done(struct ib_cq *cq, struct ib_wc *wc);static void isert_send_done (struct ib_cq *cq,struct ib_wc *wc);static void isert_login_recv_done (struct ib_cq *cq,struct ib_wc *wc);static void isert_login_send_done (struct ib_cq *cq,struct ib_wc *wc); +static void isert_unmap_tx_desc (struct iser_tx_desc *tx_desc, +struct ib_device *ib_dev);static int isert_sg_tablesize_set (const char *val,const struct kernel_param *kp) {
@@ -501,6 +503,8 @@ isert_connect_release(struct isert_conn *isert_conn)if (isert_conn->qp)isert_destroy_qp (isert_conn); +isert_unmap_tx_desc (&isert_conn->login_tx_desc, device->ib_device); +if (isert_conn->login_desc)isert_free_login_buf (isert_conn);
@@ -961,14 +965,17 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,mutex_lock (&isert_conn->mutex); isert_conn->state =ISER_CONN_FULL_FEATURE ;mutex_unlock (&isert_conn->mutex); - goto post_send; + +/* Sent from isert_get_rx_pdu() after registration. */ + isert_conn->login_rsp_pending = true; +return 0 ; } ret =isert_login_post_recv (isert_conn);if (ret)return ret; } -post_send: + ret =isert_login_post_send (isert_conn, tx_desc);if (ret)return ret;
@@ -2628,8 +2635,17 @@ static void isert_free_conn(struct iscsit_conn *conn)static void isert_get_rx_pdu (struct iscsit_conn *conn) { +struct isert_conn *isert_conn = conn->context;struct completion comp; +/* The session is registered by now; see isert_put_login_tx(). */ +if (isert_conn->login_rsp_pending) { + isert_conn->login_rsp_pending = false; +if (isert_login_post_send (isert_conn, + &isert_conn->login_tx_desc)) +return ; + } +init_completion (&comp);wait_for_completion_interruptible (&comp);
drivers/infiniband/ulp/isert/ib_isert.h +1 -0
@@ -178,6 +178,7 @@ struct isert_conn {struct completion login_comp;struct completion login_req_comp;struct iser_tx_desc login_tx_desc; +bool login_rsp_pending;struct rdma_cm_id *cm_id;struct ib_qp *qp;struct ib_cq *cq;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1081/1424 IB/isert: post the full-feature receive buffers after session registration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 5247dde9daac7e107853b6fea043f7f47be033f7 ]
isert_put_login_tx() posts the full-feature receive buffers before __transport_register_session() runs, so an initiator that does not wait for the final Login Response can still have a SCSI command executed against an se_session whose se_tpg is NULL - the same oops as the previous patch, at target_submit+0xbe.
Post them from isert_get_rx_pdu(), which the previous patch already uses to send that response, and post them before that send: the receive queue is filled at the moment the initiator is told it may use it. Allocating there keeps the existing property that a memory allocation failure cannot happen once the final Login Response is on the wire.
The receive queue is already empty between the final Login Request and isert_post_recvm(); this moves the second point later, from a median of 92 us to 172 us over 1200 logins. Only an initiator that sends before it has been told to can reach that window, and on IB and RoCE its send is retried there until the buffers appear - isert_rdma_accept() asks for rnr_retry_count = 7. iWARP has no RNR flow control, so there the same send terminates the connection instead.
Measured over rxe, 400 login cycles per run, with an initiator that does not wait: an instrumented build counted no entries to isert_recv_done() before the buffers are posted in 10 runs, where that initiator oopsed 8 of 10 unpatched runs and 5 of 10 with only the previous patch.
Not tested: iWARP, discovery sessions over iSER, and real HCAs.
--- drivers/infiniband/ulp/isert/ib_isert.c | 41 ++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-)
drivers/infiniband/ulp/isert/ib_isert.c +20 -21
@@ -952,21 +952,7 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login, }if (!login->login_failed) {if (login->login_complete) { - ret =isert_alloc_rx_descriptors (isert_conn); -if (ret) -return ret; - - ret =isert_post_recvm (isert_conn, -ISERT_QP_MAX_RECV_DTOS ); -if (ret) -return ret; - -/* Now we are in FULL_FEATURE phase */ -mutex_lock (&isert_conn->mutex); - isert_conn->state =ISER_CONN_FULL_FEATURE ; -mutex_unlock (&isert_conn->mutex); - -/* Sent from isert_get_rx_pdu() after registration. */ +/* Posted and sent from isert_get_rx_pdu(). */ isert_conn->login_rsp_pending = true;return 0 ; }
@@ -2638,13 +2624,26 @@ static void isert_get_rx_pdu(struct iscsit_conn *conn)struct isert_conn *isert_conn = conn->context;struct completion comp; +/* The login timeout timer can fail the login after isert_put_login_tx(). */ +if (!isert_conn->login_rsp_pending) +return ; + + isert_conn->login_rsp_pending = false; +/* The session is registered by now; see isert_put_login_tx(). */ -if (isert_conn->login_rsp_pending) { - isert_conn->login_rsp_pending = false; -if (isert_login_post_send (isert_conn, - &isert_conn->login_tx_desc)) -return ; - } +if (isert_alloc_rx_descriptors (isert_conn)) +return ; + +if (isert_post_recvm (isert_conn,ISERT_QP_MAX_RECV_DTOS )) +return ; + +/* Now we are in FULL_FEATURE phase */ +mutex_lock (&isert_conn->mutex); + isert_conn->state =ISER_CONN_FULL_FEATURE ; +mutex_unlock (&isert_conn->mutex); + +if (isert_login_post_send (isert_conn, &isert_conn->login_tx_desc)) +return ;init_completion (&comp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1082/1424 RDMA/siw: Introduce siw_free_cm_id
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoqing Jiang <[email protected]>
[ Upstream commit 08456d4db73bbb3fcaa0d63252ea2399c65297a4 ]
Factor out a helper to simplify code.
Stable-dep-of: a93949718259 ("RDMA/siw: Fix use-after-free in siw_accept()")
--- drivers/infiniband/sw/siw/siw_cm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
drivers/infiniband/sw/siw/siw_cm.c +14 -16
@@ -364,6 +364,15 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,return id->event_handler (id, &event); } +static void siw_free_cm_id (struct siw_cep *cep) +{ +if (!cep->cm_id) +return ; + + cep->cm_id->rem_ref (cep->cm_id); + cep->cm_id =NULL ; +} +/* * siw_qp_cm_drop() *
@@ -416,8 +425,7 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule)default :break ; } - cep->cm_id->rem_ref (cep->cm_id); - cep->cm_id =NULL ; +siw_free_cm_id (cep);siw_cep_put (cep); } cep->state =SIW_EPSTATE_CLOSED ;
@@ -1175,8 +1183,7 @@ static void siw_cm_work_handler(struct work_struct *w) cep->sock =NULL ; }if (cep->cm_id) { - cep->cm_id->rem_ref (cep->cm_id); - cep->cm_id =NULL ; +siw_free_cm_id (cep);siw_cep_put (cep); } }
@@ -1709,10 +1716,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state =SIW_EPSTATE_CLOSED ; -if (cep->cm_id) { - cep->cm_id->rem_ref (id); - cep->cm_id =NULL ; - } +siw_free_cm_id (cep);if (qp->cep) {siw_cep_put (cep); qp->cep =NULL ;
@@ -1890,10 +1894,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)if (cep) {siw_cep_set_inuse (cep); -if (cep->cm_id) { - cep->cm_id->rem_ref (cep->cm_id); - cep->cm_id =NULL ; - } +siw_free_cm_id (cep); cep->sock =NULL ;siw_socket_disassoc (s); cep->state =SIW_EPSTATE_CLOSED ;
@@ -1923,10 +1924,7 @@ static void siw_drop_listeners(struct iw_cm_id *id)siw_cep_set_inuse (cep); -if (cep->cm_id) { - cep->cm_id->rem_ref (cep->cm_id); - cep->cm_id =NULL ; - } +siw_free_cm_id (cep);if (cep->sock) {siw_socket_disassoc (cep->sock);sock_release (cep->sock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1083/1424 RDMA/siw: Fix use-after-free in siw_accept()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
[ Upstream commit a9394971825933074032794a5feee5211509c774 ]
siw_accept() looks up the QP supplied by userspace. If that QP is already in RTS, the function jumps to error cleanup before associating the incoming CEP with it.
The cleanup tests whether qp->cep is non-NULL and assumes the current call installed the association. However, qp->cep can point to the CEP of an existing connection. The cleanup then drops a reference from the incoming cep, not qp->cep. Once the incoming endpoint loses its remaining references, this can free it before the subsequent cep->qp store, causing a use-after-free. It also clears the existing QP association.
Only release the association reference when qp->cep is the incoming CEP. This preserves an existing association and avoids accessing the freed endpoint.
--- drivers/infiniband/sw/siw/siw_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/sw/siw/siw_cm.c +1 -1
@@ -1717,7 +1717,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state =SIW_EPSTATE_CLOSED ;siw_free_cm_id (cep); -if (qp->cep) { +if (qp->cep == cep) {siw_cep_put (cep); qp->cep =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1084/1424 RDMA/erdma: restrict the driver to little-endian systems
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit a12d9145145b21c50531afb6e3f711b1f34e1465 ]
The eRDMA device interface requires explicit byte ordering, but several DMA-visible values that should be little-endian remain native-endian. Command request payloads are copied verbatim, data-path SQE headers are written without cpu_to_le64(), and kernel doorbell records are assigned plain u64 values. The command completion path also reads a little-endian SQE header without conversion.
These paths are byte-swapped on big-endian kernels and can break command processing during probe. Since complete big-endian support requires converting every device-visible structure, depend on !CPU_BIG_ENDIAN.
--- drivers/infiniband/hw/erdma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/erdma/Kconfig +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config INFINIBAND_ERDMA tristate "Alibaba Elastic RDMA Adapter (ERDMA) support" - depends on PCI_MSI && 64BIT + depends on PCI_MSI && 64BIT && !CPU_BIG_ENDIAN depends on INFINIBAND_ADDR_TRANS depends on INFINIBAND_USER_ACCESS help
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1085/1424 wifi: mac80211: skip default WMM setup for AP_VLAN links
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 4d8cfff012aaa971d50b01823b1015c1073c3ff6 ]
AP_VLAN interfaces are never passed to the driver, so setting default WMM parameters on their links trips the check-sdata-in-driver warning in drv_conf_tx(), as well as in the BSS_CHANGED_QOS link info notification. Skip it, matching the existing AP_VLAN handling in this function.
--- net/mac80211/link.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/mac80211/link.c +2 -1
@@ -255,7 +255,8 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, link = links[link_id];ieee80211_link_init (sdata, link_id, &link->data, &link->conf);ieee80211_link_setup (&link->data); -ieee80211_set_wmm_default (&link->data, true, non_sta); +if (sdata->vif.type !=NL80211_IFTYPE_AP_VLAN ) +ieee80211_set_wmm_default (&link->data, true, non_sta); }if (new_links ==0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1086/1424 arm64: hibernate: mask DAIF before restoring hibernated kernel
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ada Couprie Diaz <[email protected]>
[ Upstream commit 684bde100117931f4c51c644a95f42f2dab041bc ]
The arm64 hibernate code manages the exception masking in an unsound way, leading to potential crashes and/or warnings during resume.
When a hibernation image is saved in swsusp_arch_suspend(), all DAIF exceptions are masked (by virtue of local_daif_save()), and the suspended image is saved assuming that all DAIF exceptions will remain masked when the image is restored.
When a hibernation image is resumed by swsusp_arch_resume(), only interrupts are masked (by virtue of local_irq_disable() in resume_target_kernel()). When pseudo-NMI is enabled the DAIF.IF bits will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be clear.
This means that there are two problems:
(1) It is possible to take Debug, SError, or pseudo-NMI exceptions during the resume process. This is unsafe, as during the resume process both the old ane new kernels will tranisently be in an inconsistent state, and swsusp_arch_suspend_exit() won't retain an executable mapping of any exception vectors.
Any exception taken here will be fatal and silent.
(2) When re-entering the resumed kernel, some DAIF bits will be clear unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions to be taken for a short period while the resumed kernel is not yet in a consistent state.
This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
Avoid these issues by masking all DAIF exceptions during resume.
--- arch/arm64/kernel/hibernate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/arm64/kernel/hibernate.c +12 -0
@@ -459,9 +459,21 @@ int __nocfi swsusp_arch_resume(void)if (el2_reset_needed ())__hyp_set_vectors (el2_vectors); +/* +* It is necessary to mask all DAIF exceptions here as: +* +* - The copy of swsusp_arch_suspend_exit() in the hibernation +* text cannot handle taking any exceptions. +* +* - The suspended kernel masked all DAIF exceptions in +* swsusp_arch_resume(), and expects to be re-entered in the +* same state : with all DAIF exceptions masked. +*/ +local_daif_save ();hibernate_exit (virt_to_phys (tmp_pg_dir), resume_hdr.ttbr1_el1, resume_hdr.reenter_kernel, restore_pblist, resume_hdr.__hyp_stub_vectors,virt_to_phys (zero_page)); +unreachable ();return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1087/1424 arm64: hibernate: Restore DAIF state on error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Murzin <[email protected]>
[ Upstream commit 541549827889d0380fd73f8aacb5de6ef7a5a1ac ]
Sashiko AI has reported that if swsusp_mte_save_tags() for some reason fails we return from swsusp_arch_suspend() with DAIF being masked - that is not what we'd expect. Restore the saved DAIF state before returning from the error path.
--- arch/arm64/kernel/hibernate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm64/kernel/hibernate.c +3 -1
@@ -342,8 +342,10 @@ int swsusp_arch_suspend(void)crash_prepare_suspend (); ret =swsusp_mte_save_tags (); -if (ret) +if (ret) { +local_daif_restore (flags);return ret; + } sleep_cpu =smp_processor_id (); ret =swsusp_save ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1088/1424 mfd: rave-sp: validate received frame payload lengths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 0be718b5451bd83865d6e2a8d750ca7886c4772a ]
A received RAVE-SP frame contains protocol data followed by a variant-specific one- or two-byte checksum. rave_sp_receive_frame() derives a checksum pointer before proving that the frame contains the checksum, then passes the checksum-inclusive length to handlers that index the command, acknowledgment ID and event-data bytes or derive a reply payload length.
Name those protocol field offsets, prove the checksum extent before deriving the protocol-data length, pass only that data length to the handlers, and require the complete event or reply prefix before consuming it.
--- drivers/mfd/rave-sp.c | 64 +++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 20 deletions(-)
drivers/mfd/rave-sp.c +44 -20
@@ -63,6 +63,12 @@#define RAVE_SP_TX_BUFFER_SIZE \ (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) +enum rave_sp_frame_offset { +RAVE_SP_FRAME_CODE_OFFSET , +RAVE_SP_FRAME_ACK_ID_OFFSET , +RAVE_SP_FRAME_DATA_OFFSET , +}; +/** * enum rave_sp_deframer_state - Possible state for de-framer *
@@ -352,7 +358,7 @@ int rave_sp_exec(struct rave_sp *sp,int command, ret =0 ;u8 ackid; - command = sp->variant->cmd.translate (data[0 ]); + command = sp->variant->cmd.translate (data[RAVE_SP_FRAME_CODE_OFFSET ]);if (command <0 )return command;
@@ -366,8 +372,8 @@ int rave_sp_exec(struct rave_sp *sp, sp->reply = &reply;mutex_unlock (&sp->reply_lock); - data[0 ] = command; - data[1 ] = ackid; + data[RAVE_SP_FRAME_CODE_OFFSET ] = command; + data[RAVE_SP_FRAME_ACK_ID_OFFSET ] = ackid;rave_sp_write (sp, data, data_size);
@@ -388,16 +394,23 @@ EXPORT_SYMBOL_GPL(rave_sp_exec);static void rave_sp_receive_event (struct rave_sp *sp,const unsigned char *data,size_t length) { -u8 cmd[] = { - [0 ] =rave_sp_reply_code (data[0 ]), - [1 ] = data[1 ], - }; +unsigned long action; +u8 cmd[RAVE_SP_FRAME_DATA_OFFSET ]; + +if (length <RAVE_SP_FRAME_DATA_OFFSET +1 ) { +dev_warn (&sp->serdev->dev,"Dropping short event frame\n" ); +return ; + } + + cmd[RAVE_SP_FRAME_CODE_OFFSET ] = +rave_sp_reply_code (data[RAVE_SP_FRAME_CODE_OFFSET ]); + cmd[RAVE_SP_FRAME_ACK_ID_OFFSET ] = data[RAVE_SP_FRAME_ACK_ID_OFFSET ];rave_sp_write (sp, cmd,sizeof (cmd)); -blocking_notifier_call_chain (&sp->event_notifier_list, -rave_sp_action_pack (data[0 ], data[2 ]), -NULL ); + action =rave_sp_action_pack (data[RAVE_SP_FRAME_CODE_OFFSET ], + data[RAVE_SP_FRAME_DATA_OFFSET ]); +blocking_notifier_call_chain (&sp->event_notifier_list, action,NULL ); } static void rave_sp_receive_reply(struct rave_sp *sp,
@@ -405,27 +418,35 @@ static void rave_sp_receive_reply(struct rave_sp *sp, {struct device *dev = &sp->serdev->dev;struct rave_sp_reply *reply; -const size_t payload_length = length -2 ; +size_t payload_length; + +if (length <RAVE_SP_FRAME_DATA_OFFSET ) { +dev_warn (dev,"Dropping short reply frame\n" ); +return ; + } + payload_length = length -RAVE_SP_FRAME_DATA_OFFSET ;mutex_lock (&sp->reply_lock); reply = sp->reply;if (reply) { -if (reply->code == data[0 ] && reply->ackid == data[1 ] && +if (reply->code == data[RAVE_SP_FRAME_CODE_OFFSET ] && + reply->ackid == data[RAVE_SP_FRAME_ACK_ID_OFFSET ] && payload_length >= reply->length) {/* * We are relying on memcpy(dst, src, 0) to be a no-op * when handling commands that have a no-payload reply */ -memcpy (reply->data, &data[2 ], reply->length); +memcpy (reply->data, &data[RAVE_SP_FRAME_DATA_OFFSET ], + reply->length);complete (&reply->received); sp->reply =NULL ; }else {dev_err (dev,"Ignoring incorrect reply\n" );dev_dbg (dev,"Code: expected = 0x%08x received = 0x%08x\n" , - reply->code, data[0 ]); + reply->code, data[RAVE_SP_FRAME_CODE_OFFSET ]);dev_dbg (dev,"ACK ID: expected = 0x%08x received = 0x%08x\n" , - reply->ackid, data[1 ]); + reply->ackid, data[RAVE_SP_FRAME_ACK_ID_OFFSET ]);dev_dbg (dev,"Length: expected = %zu received = %zu\n" , reply->length, payload_length); }
@@ -439,10 +460,10 @@ static void rave_sp_receive_frame(struct rave_sp *sp, size_t length) {const size_t checksum_length = sp->variant->checksum->length; -const size_t payload_length = length - checksum_length; -const u8 *crc_reported = &data[payload_length];struct device *dev = &sp->serdev->dev;u8 crc_calculated[RAVE_SP_CHECKSUM_SIZE ]; +const u8 *crc_reported; +size_t payload_length;if (unlikely (checksum_length >sizeof (crc_calculated))) {dev_warn (dev,"Checksum too long, dropping\n" );
@@ -457,6 +478,9 @@ static void rave_sp_receive_frame(struct rave_sp *sp,return ; } + payload_length = length - checksum_length; + crc_reported = &data[payload_length]; + sp->variant->checksum->subroutine (data, payload_length, crc_calculated);
@@ -465,10 +489,10 @@ static void rave_sp_receive_frame(struct rave_sp *sp,return ; } -if (rave_sp_id_is_event (data[0 ])) -rave_sp_receive_event (sp, data, length); +if (rave_sp_id_is_event (data[RAVE_SP_FRAME_CODE_OFFSET ])) +rave_sp_receive_event (sp, data, payload_length);else -rave_sp_receive_reply (sp, data, length); +rave_sp_receive_reply (sp, data, payload_length); } static int rave_sp_receive_buf(struct serdev_device *serdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1089/1424 mfd: iqs62x: Reject zero-length firmware records
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 08ea045e0b82cbcadb7a2efc43a23561489a00f2 ]
struct iqs62x_fw_rec includes the first data byte in its fixed-size header, so the parser advances by len - 1 bytes after that header. A zero len makes the size_t cursor update move back by one byte, so the next record overlaps the current record instead of following a valid declared extent.
Reject zero-length records and express the remaining-size check without an offset addition.
--- drivers/mfd/iqs62x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mfd/iqs62x.c +1 -1
@@ -237,7 +237,7 @@ static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x, fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos); pos +=sizeof (*fw_rec); -if (pos + fw_rec->len -1 > fw->size) { +if (!fw_rec->len || fw_rec->len -1 > fw->size - pos) { ret = -EINVAL ;break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1090/1424 drm/amdgpu/gfx6: Fixup emit_cntxcntl()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 1edb323406aaf05739804d2faa2561f2d43bcd09 ]
Set bits on dword 2 like GFX7-8 except load_global_uconfig which doesn't exist on GFX6.
Emit VS_PARTIAL_FLUSH before VGT_FLUSH like GFX7-8.
For reference see old PAL which explains the bit fields in this register and that load_global_uconfig doesn't exist on GFX6 and also see gfx_v7_ring_emit_cntxcntl() for the GFX7 code which this commit follows.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +21 -7
@@ -1860,11 +1860,13 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)return r; } -static void gfx_v6_0_ring_emit_vgt_flush (struct amdgpu_ring *ring) +static void gfx_v6_0_ring_emit_event_write (struct amdgpu_ring *ring, +uint32_t event_type, +uint32_t event_index) {amdgpu_ring_write (ring,PACKET3 (PACKET3_EVENT_WRITE ,0 )); -amdgpu_ring_write (ring,EVENT_TYPE (VGT_FLUSH ) | -EVENT_INDEX (0 )); +amdgpu_ring_write (ring,EVENT_TYPE (event_type) | +EVENT_INDEX (event_index)); } static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
@@ -3001,10 +3003,22 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)static void gfx_v6_ring_emit_cntxcntl (struct amdgpu_ring *ring,uint32_t flags) { -if (flags &AMDGPU_HAVE_CTX_SWITCH ) -gfx_v6_0_ring_emit_vgt_flush (ring); +u32 dw2 =0x80000000 ;/* set load_enable otherwise this package is just NOPs */ + +if (flags &AMDGPU_HAVE_CTX_SWITCH ) { +gfx_v6_0_ring_emit_event_write (ring,VS_PARTIAL_FLUSH ,4 ); +gfx_v6_0_ring_emit_event_write (ring,VGT_FLUSH ,0 ); + +/* set load_global_config (load_global_uconfig doesn't exist on GFX6) */ + dw2 |=0x1 ; +/* set load_cs_sh_regs */ + dw2 |=0x01000000 ; +/* set load_per_context_state & load_gfx_sh_regs */ + dw2 |=0x10002 ; + } +amdgpu_ring_write (ring,PACKET3 (PACKET3_CONTEXT_CONTROL ,1 )); -amdgpu_ring_write (ring,0x80000000 ); +amdgpu_ring_write (ring, dw2);amdgpu_ring_write (ring,0 ); }
@@ -3538,7 +3552,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ 7 +4 +/* gfx_v6_0_ring_emit_pipeline_sync */ SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +6 +/* gfx_v6_0_ring_emit_vm_flush */ -3 +2 +/* gfx_v6_ring_emit_cntxcntl including vgt flush */ +3 +2 +2 +/* gfx_v6_ring_emit_cntxcntl including VGT flush */ 5, /* SURFACE_SYNC */ .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1091/1424 ext4: fix spurious message about orphan cleanup on RO fs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
[ Upstream commit 5aa98f874c013bcce9bb84ffded2f0ef886e4e33 ]
When orphan_file feature is enabled, ext4_orphan_cleanup() was always walking through the orphan file looking for orphan inodes. This is mostly harmless but for read-only filesystem it results in spurious "orphan cleanup on readonly fs" message and in other cornercases it could result in similar somewhat misleading messages. Skip orphan cleanup if the orphan file is empty to avoid confusing messages.
--- fs/ext4/orphan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/orphan.c +1 -1
@@ -388,7 +388,7 @@ void ext4_orphan_cleanup(struct super_block *sb, struct ext4_super_block *es)struct ext4_orphan_info *oi = &EXT4_SB (sb)->s_orphan_info;int inodes_per_ob =ext4_inodes_per_orphan_block (sb); -if (!es->s_last_orphan && !oi->of_blocks) { +if (!es->s_last_orphan &&ext4_orphan_file_empty (sb)) {ext4_debug ("no orphan inodes to clean up\n" );return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1092/1424 arm64: dts: ti: k3-am64: Fix MDIO clock reference for ICSSG0 node
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Meghana Malladi <[email protected]>
[ Upstream commit 197df050a10fe216971b45a79f07195c86a02236 ]
MDIO clock index changed from 62:3 to 81:0 to match proper clock definition in the SoC device tree. Clock Id 81:0 belongs to ICSSG0 core clock, where as 62 belongs to EQEP2 device.
See: https://software-dl.ti.com/tisci/esd/latest/5_soc_doc/am64x/clocks.html
--- arch/arm64/boot/dts/ti/k3-am64-main.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/ti/k3-am64-main.dtsi +1 -1
@@ -1316,7 +1316,7 @@ tx_pru0_1: txpru@c000 { icssg0_mdio: mdio@32400 { compatible = "ti,davinci_mdio"; reg = <0x32400 0x100>; - clocks = <&k3_clks 62 3>; + clocks = <&k3_clks 81 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <0>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1093/1424 phy: sunplus: fix error handling in sp_uphy_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 8b2683bc4cc18c581b7cd24f227cbe61abca7f4d ]
Fix the error paths of sp_uphy_init() to undo exactly what each stage
did: return directly if clk_prepare_enable() fails, release only the clock if reset_control_deassert() fails, and jump to err_reset if update_disc_vol() fails so the clock and reset are not leaked.
--- drivers/phy/sunplus/phy-sunplus-usb2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/phy/sunplus/phy-sunplus-usb2.c +3 -3
@@ -116,11 +116,11 @@ static int sp_uphy_init(struct phy *phy) ret =clk_prepare_enable (usbphy->phy_clk);if (ret) - goto err_clk; +return ret; ret =reset_control_deassert (usbphy->rstc);if (ret) - goto err_reset; + goto err_clk;/* Default value modification */ writel (HIGH_MASK_BITS |0x4002 , usbphy->moon4_regs +UPHY_CONTROL0 );
@@ -129,7 +129,7 @@ static int sp_uphy_init(struct phy *phy)/* disconnect voltage */ ret =update_disc_vol (usbphy);if (ret <0 ) -return ret; + goto err_reset;/* board uphy 0 internal register modification for tid certification */ val =readl (usbphy->phy_regs +CONFIG9 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1094/1424 phy: rockchip: phy-rockchip-inno-csidphy: fix rk1808 hsfreq table
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerald Loacker <[email protected]>
[ Upstream commit 4fae43e33a7c10951fbdc6baf409d51bd66aaefb ]
The rk1808 hsfreq table capped at 2499 Mbps, preventing a data rate of exactly 2500 Mbps. Extend the final entry to 2500 Mbps to support this rate.
This is essential for RK3588 reusing this array and fully supporting rates up to 2500 Mbps.
--- drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +1 -1
@@ -157,7 +157,7 @@ static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges[] = { { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e}, { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e}, {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37}, - {2199, 0x3c}, {2399, 0x41}, {2499, 0x46} + {2199, 0x3c}, {2399, 0x41}, {2500, 0x46} }; static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1095/1424 perf trace-event: Fix buffer overflow in read_string()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanushree Shah <[email protected]>
[ Upstream commit 1121a7af1833f8b5723f1e32685b461614353d5d ]
read_string() writes into buf[BUFSIZ] one byte at a time without checking 'size' against the buffer bound before each write. A string longer than BUFSIZ in the input overflows the stack buffer.
Add a bounds check before each write to prevent overflow. On overflow the function returns NULL, matching its other error paths.
--- tools/perf/util/trace-event-read.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/trace-event-read.c +5 -0
@@ -127,6 +127,11 @@ static char *read_string(void) } } +if (size >= (int )sizeof (buf) -1 ) { +pr_debug ("string too long (max %zu bytes)" ,sizeof (buf) -1 ); + goto out; + } + buf[size++] = c;if (!c)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1096/1424 drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 7aac4242a11991d530eee3e141d6e445d5f11c22 ]
Implement the emit_switch_buffer() function instead of emitting them duing emit_ib, emit_pipeline_sync and emit_vm_flush.
Note that it isn't necessary to emit these in both emit_pipeline_sync() and emit_vm_flush() because amdgpu_vm_flush() already calls these when calling either of those functions.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 38 ++++++++++----------------- 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +14 -24
@@ -1905,12 +1905,6 @@ static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,unsigned vmid =AMDGPU_JOB_GET_VMID (job);u32 header, control =0 ; -/* insert SWITCH_BUFFER packet before first IB in the ring frame */ -if (flags &AMDGPU_HAVE_CTX_SWITCH ) { -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); - } -if (ib->flags &AMDGPU_IB_FLAG_CE ) header =PACKET3 (PACKET3_INDIRECT_BUFFER_CONST ,2 );else
@@ -2345,14 +2339,6 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)amdgpu_ring_write (ring, seq);amdgpu_ring_write (ring,0xffffffff );amdgpu_ring_write (ring,4 );/* poll interval */ - -if (usepfp) { -/* synce CE with ME to prevent CE fetch CEIB before context switch done */ -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); - } } static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
@@ -2376,12 +2362,6 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,/* sync PFP to ME, otherwise we might get invalid PFP reads */ amdgpu_ring_write (ring,PACKET3 (PACKET3_PFP_SYNC_ME ,0 ));amdgpu_ring_write (ring,0x0 ); - -/* synce CE with ME to prevent CE fetch CEIB before context switch done */ -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); } }
@@ -3001,6 +2981,12 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)return clock; } +static void gfx_v6_0_ring_emit_sb (struct amdgpu_ring *ring) +{ +amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); +amdgpu_ring_write (ring,0 ); +} +static void gfx_v6_ring_emit_cntxcntl (struct amdgpu_ring *ring,uint32_t flags) {u32 dw2 =0x80000000 ;/* set load_enable otherwise this package is just NOPs */
@@ -3550,11 +3536,12 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { .emit_frame_size =5 +5 +/* hdp flush / invalidate */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ -7 +4 +/* gfx_v6_0_ring_emit_pipeline_sync */ -SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +6 +/* gfx_v6_0_ring_emit_vm_flush */ +7 +/* gfx_v6_0_ring_emit_pipeline_sync */ +SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +2 +/* gfx_v6_0_ring_emit_vm_flush */ +3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 3 +2 +2 +/* gfx_v6_ring_emit_cntxcntl including VGT flush */ 5, /* SURFACE_SYNC */ - .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ + .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3562,6 +3549,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .emit_switch_buffer = gfx_v6_0_ring_emit_sb, .emit_cntxcntl = gfx_v6_ring_emit_cntxcntl, .emit_wreg = gfx_v6_0_ring_emit_wreg, .emit_mem_sync = gfx_v6_0_emit_mem_sync,
@@ -3579,8 +3567,9 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {7 +/* gfx_v6_0_ring_emit_pipeline_sync */ SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +/* gfx_v6_0_ring_emit_vm_flush */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ +3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 5, /* SURFACE_SYNC */ - .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ + .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3588,6 +3577,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .emit_switch_buffer = gfx_v6_0_ring_emit_sb, .emit_wreg = gfx_v6_0_ring_emit_wreg, .emit_mem_sync = gfx_v6_0_emit_mem_sync, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1097/1424 drm/amdgpu/gfx6: Use PFP on the compute queues too
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 60f20946cd318518ddc2c0da12103c666b2b9564 ]
On GFX6, the compute rings use the same CP path as the graphics ring. The only difference is that they don't support draw commands. (As opposed to GFX7 and newer which have a separate command parser that is called MEC for compute queues.)
This means that we have to take into consideration that the PFP also exists on compute queues on GFX6:
Use PFP for register writes on both graphics and compute queues.
In the pipeline sync, use the PFP to wait for the previous fence (and not the ME) to prevent the PFP from starting to execute the next submission while the ME is still in the previous submission.
After a VM flush, emit PFP_SYNC_ME on compute queues as well.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +4 -4
@@ -2326,7 +2326,7 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)static void gfx_v6_0_ring_emit_pipeline_sync (struct amdgpu_ring *ring) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;uint32_t seq = ring->fence_drv.sync_seq;uint64_t addr = ring->fence_drv.gpu_addr;
@@ -2344,7 +2344,7 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)static void gfx_v6_0_ring_emit_vm_flush (struct amdgpu_ring *ring,unsigned vmid,uint64_t pd_addr) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;amdgpu_gmc_emit_flush_gpu_tlb (ring, vmid, pd_addr);
@@ -2368,7 +2368,7 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,static void gfx_v6_0_ring_emit_wreg (struct amdgpu_ring *ring,uint32_t reg,uint32_t val) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
@@ -3565,7 +3565,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { .emit_frame_size =5 +5 +/* hdp flush / invalidate */ 7 +/* gfx_v6_0_ring_emit_pipeline_sync */ -SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +/* gfx_v6_0_ring_emit_vm_flush */ +SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +2 +/* gfx_v6_0_ring_emit_vm_flush */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ 3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 5, /* SURFACE_SYNC */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1098/1424 scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manish Rangankar <[email protected]>
[ Upstream commit 5cbc49d5c4cd20c18041e86958103045216d2190 ]
qla2x00_sysfs_read_vpd() called ha->isp_ops->read_optrom() a second time after releasing optrom_mutex. The repeated read is redundant and, unlike the first, runs without optrom_mutex held, exposing flash access to concurrent optrom operations. Drop the duplicate call.
--- drivers/scsi/qla2xxx/qla_attr.c | 1 - 1 file changed, 1 deletion(-)
drivers/scsi/qla2xxx/qla_attr.c +0 -1
@@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, ha->isp_ops->read_optrom (vha, ha->vpd, faddr, ha->vpd_size);mutex_unlock (&ha->optrom_mutex); - ha->isp_ops->read_optrom (vha, ha->vpd, faddr, ha->vpd_size); skip:return memory_read_from_buffer (buf, count, &off, ha->vpd, ha->vpd_size); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1099/1424 firmware_loader: do not queue completed sysfs fallback requests
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit b48373c901951fad1a26bd7c33ad91172b3945b5 ]
fw_load_sysfs_fallback() calls device_add() before adding the fw_priv to pending_fw_head. device_add() publishes the fallback loading interface, so a userspace helper which discovers the device by scanning sysfs can write 0 to the loading attribute and complete the request before it is queued as pending.
In that interleaving firmware_loading_store() calls fw_state_done() while pending_list still points to itself, so it cannot remove an entry from pending_fw_head. The subsequent unconditional list_add() then queues an already-completed fw_priv. Once the request is released, pending_fw_head can retain a pointer to freed memory and the next fallback request can fault while validating the list.
Only in-flight fallback requests need suspend or reboot abort handling. If the request is already DONE after device_add(), return success from the fallback path without sending another uevent, waiting again, or queueing it as pending. This preserves the invariant that pending_fw_head contains only active fallback requests.
--- drivers/base/firmware_loader/fallback.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/base/firmware_loader/fallback.c +10 -0
@@ -91,6 +91,16 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout) retval = -EINTR ; goto out; } + +/* +* device_add() exposes the loading interface before pending_list is +* linked into pending_fw_head, so fw_state_done() may run first. +*/ +if (fw_state_is_done (fw_priv)) { +mutex_unlock (&fw_lock); + goto out; + } +list_add (&fw_priv->pending_list, &pending_fw_head);mutex_unlock (&fw_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1100/1424 pinctrl: rockchip: Reset the pin count when recalculating SoC data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Simon Glass <[email protected]>
[ Upstream commit 5b695c191cc85f0fd62eec885b55d01468dc9f2c ]
rockchip_pinctrl_get_soc_data() mutates the static per-SoC data. The iomux and drive offsets are recalculated idempotently, since a rerun anchors at the values calculated before, but the total pin count only
accumulates: each run adds every bank's pins again. When the probe is deferred and runs a second time, nr_pins doubles and every bank's pin_base shifts, so later pin lookups resolve to the wrong bank and the wrong registers.
Reset the pin count at the start of the calculation, so that a rerun produces the same values.
This is verified on a Luckfox Pico Mini B (RV1103, with the pending RV1106 series applied) by forcing the probe to defer once: without this patch the second probe calculates nr_pins=304 instead of 152 and no GPIO bank comes up; with it the recalculation matches the first run and all banks work.
--- drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/pinctrl/pinctrl-rockchip.c +10 -0
@@ -3240,6 +3240,16 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( pmu_offs = ctrl->pmu_mux_offset; drv_pmu_offs = ctrl->pmu_drv_offset; drv_grf_offs = ctrl->grf_drv_offset; + +/* +* This function mutates the static per-SoC data. Most of it is +* idempotent: recalculated iomux and drv offsets anchor at the +* values calculated by a previous run. The pin count is not, so +* reset it here; otherwise it accumulates when the probe runs +* again after a probe deferral, shifting every bank's pin_base. +*/ + ctrl->nr_pins =0 ; + bank = ctrl->pin_banks;for (i =0 ; i < ctrl->nr_banks; ++i, ++bank) {int bank_pins =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1101/1424 hugetlbfs: release subpool on fill_super failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 308ab73e97c87bd0e142b11758faab7f88d82854 ]
hugetlbfs_fill_super() allocates a hugepage subpool when size or min_size mount options are specified. hugepage_new_subpool() may also reserve huge pages for min_size.
If root dentry creation fails after the subpool is created, the failure path frees the subpool with kfree(). This bypasses hugepage_put_subpool() and can leave min_size reservations charged.
Use hugepage_put_subpool() on the failure path, matching the normal put_super path.
--- fs/hugetlbfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/hugetlbfs/inode.c +2 -1
@@ -1553,7 +1553,8 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out_free;return 0 ; out_free: -kfree (sbinfo->spool); +if (sbinfo->spool) +hugepage_put_subpool (sbinfo->spool);kfree (sbinfo);return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1102/1424 soc: fsl: qe: check platform_driver_register() in qe_ic_of_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
[ Upstream commit fbdba2a67fa7c0e7570bcbf9f28b782d6100270d ]
qe_ic_of_init() ignored the return value of platform_driver_register() and always returned success. Propagate the error to the initcall.
--- drivers/soc/fsl/qe/qe_ic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/soc/fsl/qe/qe_ic.c +1 -2
@@ -481,7 +481,6 @@ static struct platform_driver qe_ic_driver =static int __init qe_ic_of_init (void ) { -platform_driver_register (&qe_ic_driver); -return 0 ; +return platform_driver_register (&qe_ic_driver); }subsys_initcall (qe_ic_of_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1103/1424 phy: qcom-sgmii-eth: relax order of .power_on() vs .set_mode*()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
[ Upstream commit ebe8b48b88ad012cf6067226e184e9173b7ea9d6 ]
Allow any order of the .power_on() and .set_mode*() methods as per the recent discussion. This means phy_power_on() with this SerDes will now restore the previous setup without requiring a subsequent phy_set_mode*() call.
Stable-dep-of: 4f81684a1d10 ("phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads")
--- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +13 -1
@@ -346,8 +346,17 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy)static int qcom_dwmac_sgmii_phy_power_on (struct phy *phy) {struct qcom_dwmac_sgmii_phy_data *data =phy_get_drvdata (phy); +int ret; -return clk_prepare_enable (data->refclk); + ret =clk_prepare_enable (data->refclk); +if (ret <0 ) +return ret; + + ret =qcom_dwmac_sgmii_phy_calibrate (phy); +if (ret <0 ) +clk_disable_unprepare (data->refclk); + +return ret; }static int qcom_dwmac_sgmii_phy_power_off (struct phy *phy)
@@ -372,6 +381,9 @@ static int qcom_dwmac_sgmii_phy_set_speed(struct phy *phy, int speed)if (speed != data->speed) data->speed = speed; +if (phy->power_count ==0 ) +return 0 ; +return qcom_dwmac_sgmii_phy_calibrate (phy); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1104/1424 phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohd Ayaan Anwar <[email protected]>
[ Upstream commit 4f81684a1d1018d7d0e5579f08d95e7701279358 ]
The SerDes PHY has two voltage supply rails, vdda-0p9 and vdda-1p2, that must both be enabled for calibration to succeed. Without them:
qcom-dwmac-sgmii-phy 8909000.phy: QSERDES_COM_C_READY_STATUS timed-out qcom-ethqos 23040000.ethernet eth0: __stmmac_open: Serdes powerup failed
The driver relied solely on the PHY framework's implicit enable of 'phy-supply', which only voted for a single rail and set no current load. Use devm_regulator_bulk_get_const() to acquire both supplies and set the peak current loads (46 mA for vdda-0p9, 15 mA for vdda-1p2) as required by the hardware.
--- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 37 ++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-)
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +33 -4
@@ -10,6 +10,7 @@#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #define QSERDES_QMP_PLL 0x0#define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 (QSERDES_QMP_PLL + 0x1ac)
@@ -104,7 +105,15 @@#define QSERDES_PCS_SGMIIPHY_READY BIT(7)#define QSERDES_COM_C_PLL_LOCKED BIT(1) +static const struct regulator_bulk_data qcom_dwmac_sgmii_phy_vregs[] = { + { .supply ="vdda-0p9" , .init_load_uA =46000 }, + { .supply ="vdda-1p2" , .init_load_uA =15000 }, +}; + +#define QCOM_SGMII_NUM_SUPPLIES ARRAY_SIZE(qcom_dwmac_sgmii_phy_vregs) +struct qcom_dwmac_sgmii_phy_data { +struct regulator_bulk_data *vregs;struct regmap *regmap;struct clk *refclk;int speed;
@@ -348,13 +357,24 @@ static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy)struct qcom_dwmac_sgmii_phy_data *data =phy_get_drvdata (phy);int ret; - ret =clk_prepare_enable (data->refclk); -if (ret <0 ) + ret =regulator_bulk_enable (QCOM_SGMII_NUM_SUPPLIES , data->vregs); +if (ret)return ret; + ret =clk_prepare_enable (data->refclk); +if (ret) + goto err_disable_regulators; + ret =qcom_dwmac_sgmii_phy_calibrate (phy); -if (ret <0 ) -clk_disable_unprepare (data->refclk); +if (ret) + goto err_disable_clk; + +return 0 ; + +err_disable_clk: +clk_disable_unprepare (data->refclk); +err_disable_regulators: +regulator_bulk_disable (QCOM_SGMII_NUM_SUPPLIES , data->vregs);return ret; }
@@ -371,6 +391,8 @@ static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy)clk_disable_unprepare (data->refclk); +regulator_bulk_disable (QCOM_SGMII_NUM_SUPPLIES , data->vregs); +return 0 ; }
@@ -410,6 +432,7 @@ static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev)struct phy_provider *provider;void __iomem *base;struct phy *phy; +int ret; data =devm_kzalloc (dev,sizeof (*data),GFP_KERNEL );if (!data)
@@ -434,6 +457,12 @@ static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev)if (IS_ERR (data->refclk))return PTR_ERR (data->refclk); + ret =devm_regulator_bulk_get_const (dev,QCOM_SGMII_NUM_SUPPLIES , + qcom_dwmac_sgmii_phy_vregs, + &data->vregs); +if (ret) +return ret; + provider =devm_of_phy_provider_register (dev, of_phy_simple_xlate);if (IS_ERR (provider))return PTR_ERR (provider);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1105/1424 phy: qcom: qmp-usb-legacy: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit 8e3687f7e18fe84372e86875709d56c37e7525a8 ]
There is a small window where the runtime suspend callback may run after pm_runtime_enable() and before pm_runtime_forbid(). In this case, a crash occurs because runtime suspend/resume dereferences qmp->phy pointer, which is not yet initialized:
`if (!qmp->phy->init_count) {`This can also happen if user re-enables runtime-pm via the sysfs attribute before qmp phy is initialized.
Similarly to other qcom phy drivers, introduce a qmp->phy_initialized variable that can be used to avoid relying on the possibly uninitialized phy pointer.
--- drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +10 -2
@@ -563,6 +563,8 @@ struct qmp_usb {enum phy_mode mode; +bool phy_initialized; +struct phy *phy;struct clk_fixed_rate pipe_clk_fixed;
@@ -928,6 +930,7 @@ static int qmp_usb_legacy_power_off(struct phy *phy)static int qmp_usb_legacy_enable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; ret =qmp_usb_legacy_init (phy);
@@ -937,14 +940,19 @@ static int qmp_usb_legacy_enable(struct phy *phy) ret =qmp_usb_legacy_power_on (phy);if (ret)qmp_usb_legacy_exit (phy); +else + qmp->phy_initialized = true;return ret; }static int qmp_usb_legacy_disable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; + qmp->phy_initialized = false; + ret =qmp_usb_legacy_power_off (phy);if (ret)return ret;
@@ -1021,7 +1029,7 @@ static int __maybe_unused qmp_usb_legacy_runtime_suspend(struct device *dev)dev_vdbg (dev,"Suspending QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
@@ -1042,7 +1050,7 @@ static int __maybe_unused qmp_usb_legacy_runtime_resume(struct device *dev)dev_vdbg (dev,"Resuming QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1106/1424 phy: qcom: snps-femto-v2: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit c271a6926ea7d3c9566b033d63fd4e8c488dc860 ]
Runtime PM must be enabled before creating the PHY, since phy_create() only enables runtime PM on the PHY device if it is already enabled on this parent device. However, the runtime PM callbacks dereference the hsphy instance, which is not yet ready, leaving a window where a suspend callback may trigger a NULL pointer dereference.
Take a runtime PM usage reference with pm_runtime_get_noresume() before enabling runtime PM and release it once the PHY has been created, so that no runtime suspend can run before the PHY is ready. This also prevents a short window where an unnecessary runtime suspend can occur.
Use the devres-managed version to ensure PM runtime is symmetrically disabled during driver removal for proper cleanup.
--- drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +20 -6
@@ -599,8 +599,18 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)return dev_err_probe (dev, ret,"failed to get regulator supplies\n" ); +/* +* Enable runtime PM before creating the PHY, phy_create() only enables +* it on the PHY device if already enabled on the parent. Hold a usage +* reference so callbacks cannot run before the PHY is ready. +*/ +pm_runtime_get_noresume (dev);pm_runtime_set_active (dev); -pm_runtime_enable (dev); + ret =devm_pm_runtime_enable (dev); +if (ret) { +pm_runtime_put_noidle (dev); +return ret; + }/* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs.
@@ -611,6 +621,7 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)if (IS_ERR (generic_phy)) { ret =PTR_ERR (generic_phy);dev_err (dev,"failed to create phy, %d\n" , ret); +pm_runtime_put_noidle (dev);return ret; } hsphy->phy = generic_phy;
@@ -620,12 +631,15 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)qcom_snps_hsphy_read_override_param_seq (dev); phy_provider =devm_of_phy_provider_register (dev, of_phy_simple_xlate); -if (!IS_ERR (phy_provider)) -dev_dbg (dev,"Registered Qcom-SNPS HS phy\n" ); -else -pm_runtime_disable (dev); +if (IS_ERR (phy_provider)) { +pm_runtime_put_noidle (dev); +return PTR_ERR (phy_provider); + } -return PTR_ERR_OR_ZERO (phy_provider); +dev_dbg (dev,"Registered Qcom-SNPS HS phy\n" ); +pm_runtime_put (dev); + +return 0 ; }static struct platform_driver qcom_snps_hsphy_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1107/1424 phy: qcom: qmp-usb: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit 142c5593379273264474f31d5956b1a0065cd576 ]
There is a small window where the runtime suspend callback may run after pm_runtime_enable() and before pm_runtime_forbid(). In this case, a crash occurs because runtime suspend/resume dereferences qmp->phy pointer, which is not yet initialized:
`if (!qmp->phy->init_count) {`This can also happen if user re-enables runtime-pm via the sysfs attribute before qmp phy is initialized.
Similarly to other qcom phy drivers, introduce a qmp->phy_initialized variable that can be used to avoid relying on the possibly uninitialized phy pointer.
--- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-usb.c +10 -2
@@ -1219,6 +1219,8 @@ struct qmp_usb {enum phy_mode mode; +bool phy_initialized; +struct phy *phy;struct clk_fixed_rate pipe_clk_fixed;
@@ -1788,6 +1790,7 @@ static int qmp_usb_power_off(struct phy *phy)static int qmp_usb_enable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; ret =qmp_usb_init (phy);
@@ -1797,14 +1800,19 @@ static int qmp_usb_enable(struct phy *phy) ret =qmp_usb_power_on (phy);if (ret)qmp_usb_exit (phy); +else + qmp->phy_initialized = true;return ret; }static int qmp_usb_disable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; + qmp->phy_initialized = false; + ret =qmp_usb_power_off (phy);if (ret)return ret;
@@ -1881,7 +1889,7 @@ static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)dev_vdbg (dev,"Suspending QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
@@ -1902,7 +1910,7 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)dev_vdbg (dev,"Resuming QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1108/1424 md/raid5: round bitmap stripes with sector division
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 17ea021ae74987d6064c8195c4922fa025753892 ]
raid5_bitmap_sector_map() aligns the array range to full RAID5 stripe widths before converting it to component sectors. That width is chunk_sectors multiplied by the number of data disks, and it is not always a power of two.
Reproduce with a 4-disk RAID5, 1024-sector chunks, and three data disks. The full-stripe width is 3072 sectors. For a one-sector write at array sector 3072, correct rounding gives array range [3072, 6144), which maps to component range [1024, 2048). The old round_down()/round_up() logic instead gives [1024, 4096), which maps to [0, 1024).
Use sector_div() based arithmetic so the rounded range is aligned to the actual RAID5 stripe width.
The deterministic mapper test now reports the fixed component range as [1024, 2048), while the old mask-based range was [0, 1024).
--- drivers/md/raid5.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/md/raid5.c +9 -4
@@ -5971,8 +5971,11 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->chunk_sectors * (conf->raid_disks - conf->max_degraded); - start =round_down (start, sectors_per_chunk); - end =round_up (end, sectors_per_chunk); +sector_div (start, sectors_per_chunk); + start *= sectors_per_chunk; +if (sector_div (end, sectors_per_chunk)) + end++; + end *= sectors_per_chunk; start =raid5_compute_sector (conf, start,0 , &dd_idx,NULL ); end =raid5_compute_sector (conf, end,0 , &dd_idx,NULL );
@@ -5990,8 +5993,10 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->prev_chunk_sectors * (conf->previous_raid_disks - conf->max_degraded); - prev_start =round_down (prev_start, sectors_per_chunk); - prev_end =round_down (prev_end, sectors_per_chunk); +sector_div (prev_start, sectors_per_chunk); + prev_start *= sectors_per_chunk; +sector_div (prev_end, sectors_per_chunk); + prev_end *= sectors_per_chunk; prev_start =raid5_compute_sector (conf, prev_start,1 , &dd_idx,NULL ); prev_end =raid5_compute_sector (conf, prev_end,1 , &dd_idx,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1109/1424 md: avoid stale clone I/O accounting timestamps
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 45102fc8330525d35675b1c193242bba101df5ee ]
md_clone_bio() always allocates the clone from mddev->io_clone_set, even when queue I/O stats are disabled. In that case it does not call bio_start_io_acct(), but it also left md_io_clone->start_time untouched.
The clone private data comes from a mempool and can contain data from a previous user. md_end_clone_io() checks start_time to decide whether it needs to call bio_end_io_acct(), so a stale non-zero value can make the completion path end accounting that was never started for this bio.
Set start_time to 0 in the no-stats branch. This keeps the end path tied to whether bio_start_io_acct() actually ran.
--- drivers/md/md.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/md/md.c +2 -0
@@ -8771,6 +8771,8 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio) md_io_clone->mddev = mddev;if (blk_queue_io_stat (bdev->bd_disk->queue)) md_io_clone->start_time =bio_start_io_acct (*bio); +else + md_io_clone->start_time =0 ;if (bio_data_dir (*bio) ==WRITE && mddev->bitmap) { md_io_clone->offset = (*bio)->bi_iter.bi_sector;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1110/1424 md/raid1: dont set array_frozen in raid1_takeover()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bruce Johnston <[email protected]>
[ Upstream commit dc386aa0ac0a3ec06c9a3ea9b064b073fb72a916 ]
raid1_takeover() sets conf->array_frozen = 1 on the newly-allocated r1conf and nothing ever clears it, so every I/O to the array stalls permanently once _wait_barrier() sees it stuck at 1.
This used to be harmless: level_store() called mddev_resume() right after pers->run(), which called raid1_quiesce(mddev, 0) and cleared array_frozen back to 0 regardless of what raid1_takeover() set. Commit b39f35ebe86d ("md: don't quiesce in mddev_suspend()") removed that quiesce(mddev, 0) call, so the pre-set now sticks.
setup_conf() already zero-initializes the new r1conf via kzalloc, so just don't set array_frozen here.
Same class of bug as commit 892da88d1cd9 ("md/raid10: fix a 'conf->barrier' leakage in raid10_takeover()"), also triggered by b39f35ebe86d.
--- drivers/md/raid1.c | 2 -- 1 file changed, 2 deletions(-)
drivers/md/raid1.c +0 -2
@@ -3357,8 +3357,6 @@ static void *raid1_takeover(struct mddev *mddev) mddev->new_chunk_sectors =0 ; conf =setup_conf (mddev);if (!IS_ERR (conf)) { -/* Array must appear to be quiesced */ - conf->array_frozen =1 ;mddev_clear_unsupported_flags (mddev,UNSUPPORTED_MDDEV_FLAGS ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1111/1424 coresight: etm4x: fix wrong check of etm4x_sspcicrn_present()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 0e1cd4270b42a257c139165622091e1e8c7104a7 ]
According to Embedded Trace Macrocell Architecture Specification ETMv4.0 to ETM4.6 [0], TRCSSPCICR<n> is present only if all of the following are true:
- TRCIDR4.NUMSSCC > n.
- TRCIDR4.NUMPC > 0b0000.
- TRCSSCSR<n>.PC == 0b1.
Comment for etm4x_sspcicrn_present() is align with the specification. However, the check should use drvdata->nr_pe_cmp to check TRCIDR4.NUMPC not nr_pe.
--- drivers/hwtracing/coresight/coresight-etm4x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +1 -1
@@ -87,7 +87,7 @@ static int etm4_probe_cpu(unsigned int cpu);static inline bool etm4x_sspcicrn_present (struct etmv4_drvdata *drvdata,int n) {return (n < drvdata->nr_ss_cmp) && - drvdata->nr_pe && + drvdata->nr_pe_cmp && (drvdata->config.ss_status[n] & TRCSSCSRn_PC); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1112/1424 coresight: Change syncfreq to be a u8
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 10d4dbdc8fbce586b17be07b8138e025381453dd ]
TRCSYNCPR.PERIOD is the only functional part of TRCSYNCPR and it only has 5 valid bits so it can be stored in a u8.
Stable-dep-of: 1674d9bff807 ("coresight: etm4x: fix underflow for usage of (nrseqstate - 1)")
--- drivers/hwtracing/coresight/coresight-etm4x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x.h +1 -1
@@ -825,7 +825,6 @@ struct etmv4_config {u32 eventctrl1;u32 stall_ctrl;u32 ts_ctrl; -u32 syncfreq;u32 ccctlr;u32 bb_ctrl;u32 vinst_ctrl;
@@ -833,6 +832,7 @@ struct etmv4_config {u32 vissctlr;u32 vipcssctlr;u8 seq_idx; +u8 syncfreq;u32 seq_ctrl[ETM_MAX_SEQ_STATES ];u32 seq_rst;u32 seq_state;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1113/1424 coresight: etm4x: fix underflow for usage of (nrseqstate - 1)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 1674d9bff8073bdee5dbc200f56fc3caa28d0566 ]
According to IHI006H Embedded Trace Macrocell Architecture Specification[0], TRCSEQEVR<n> is implemented only when TRCIDR5.NUMSEQSTATE is 0b100, in which case n ranges from 0 to 2; otherwise, TRCIDR5.NUMSEQSTATE is 0b000.
IOW, the number of usage in the initialisation or setting TRCSEQEVR<n> with drvdata->nrseqstate - 1 in the loop could make underflow issue when TRCIDR5.NUMSEQSTATE is 0b000.
Therefore, introduce nr_seq_ctrls field and untie it from nrseqstate. As part of this introduce ETM_MAX_SEQ_TRANSITIONS macro and apply nr_seq_ctrls and above macro to TRCSEQEVR<n> relevant fields setup.
--- drivers/hwtracing/coresight/coresight-etm4x-cfg.c | 2 +- drivers/hwtracing/coresight/coresight-etm4x-core.c | 9 ++++++--- drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 6 ++++-- drivers/hwtracing/coresight/coresight-etm4x.h | 7 +++++-- 4 files changed, 16 insertions(+), 8 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +1 -1
@@ -76,7 +76,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata, }else if ((offset &GENMASK (11 ,4 )) ==TRCSEQEVRn (0 )) {/* sequencer state control registers */ idx = (offset &GENMASK (3 ,0 )) /4 ; -if (idx <ETM_MAX_SEQ_STATES ) { +if (idx <ETM_MAX_SEQ_TRANSITIONS ) { reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx]; err =0 ; }
drivers/hwtracing/coresight/coresight-etm4x-core.c +6 -3
@@ -527,7 +527,8 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)etm4x_relaxed_write32 (csa, config->vissctlr,TRCVISSCTLR );if (drvdata->nr_pe_cmp)etm4x_relaxed_write32 (csa, config->vipcssctlr,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) + +for (i =0 ; i < drvdata->nr_seq_ctrls; i++)etm4x_relaxed_write32 (csa, config->seq_ctrl[i],TRCSEQEVRn (i));if (drvdata->nrseqstate) {etm4x_relaxed_write32 (csa, config->seq_rst,TRCSEQRSTEVR );
@@ -1376,6 +1377,8 @@ static void etm4_init_arch_data(void *info) drvdata->lpoverride = (etmidr5 &TRCIDR5_LPOVERRIDE ) && (!drvdata->skip_power_up);/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */ drvdata->nrseqstate =FIELD_GET (TRCIDR5_NUMSEQSTATE_MASK , etmidr5); +if (drvdata->nrseqstate) + drvdata->nr_seq_ctrls =ETM_MAX_SEQ_TRANSITIONS ;/* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr =FIELD_GET (TRCIDR5_NUMCNTR_MASK , etmidr5);etm4_cs_lock (drvdata, csa);
@@ -1785,7 +1788,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)if (drvdata->nr_pe_cmp) state->trcvipcssctlr =etm4x_read32 (csa,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++) state->trcseqevr[i] =etm4x_read32 (csa,TRCSEQEVRn (i));if (drvdata->nrseqstate) {
@@ -1919,7 +1922,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)if (drvdata->nr_pe_cmp)etm4x_relaxed_write32 (csa, state->trcvipcssctlr,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++)etm4x_relaxed_write32 (csa, state->trcseqevr[i],TRCSEQEVRn (i));if (drvdata->nrseqstate) {
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +4 -2
@@ -221,7 +221,7 @@ static ssize_t reset_store(struct device *dev, config->vipcssctlr =0x0 ;/* Disable seq events */ -for (i =0 ; i < drvdata->nrseqstate-1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++) config->seq_ctrl[i] =0x0 ; config->seq_rst =0x0 ; config->seq_state =0x0 ;
@@ -1393,9 +1393,11 @@ static ssize_t seq_idx_store(struct device *dev,struct etmv4_drvdata *drvdata =dev_get_drvdata (dev->parent);struct etmv4_config *config = &drvdata->config; +if (!drvdata->nr_seq_ctrls) +return -ENOTSUPP ;if (kstrtoul (buf,16 , &val))return -EINVAL ; -if (val >= drvdata->nrseqstate -1 ) +if (val >= drvdata->nr_seq_ctrls)return -EINVAL ;/*
drivers/hwtracing/coresight/coresight-etm4x.h +5 -2
@@ -570,6 +570,7 @@#define ETM_MAX_NR_PE 8#define ETMv4_MAX_CNTR 4#define ETM_MAX_SEQ_STATES 4 +#define ETM_MAX_SEQ_TRANSITIONS 3#define ETM_MAX_EXT_INP_SEL 4#define ETM_MAX_EXT_INP 256#define ETM_MAX_EXT_OUT 4
@@ -833,7 +834,7 @@ struct etmv4_config {u32 vipcssctlr;u8 seq_idx;u8 syncfreq; -u32 seq_ctrl[ETM_MAX_SEQ_STATES ]; +u32 seq_ctrl[ETM_MAX_SEQ_TRANSITIONS ];u32 seq_rst;u32 seq_state;u8 cntr_idx;
@@ -885,7 +886,7 @@ struct etmv4_save_state {u32 trcvissctlr;u32 trcvipcssctlr; -u32 trcseqevr[ETM_MAX_SEQ_STATES ]; +u32 trcseqevr[ETM_MAX_SEQ_TRANSITIONS ];u32 trcseqrstevr;u32 trcseqstr;u32 trcextinselr;
@@ -938,6 +939,7 @@ struct etmv4_save_state {* @numcidc: Number of contextID comparators. * @numvmidc: Number of VMID comparators. * @nrseqstate: The number of sequencer states that are implemented. +* @nr_seq_ctrls: The number of sequence state transition control registers. * @nr_event: Indicates how many events the trace unit support. * @nr_resource:The number of resource selection pairs available for tracing. * @nr_ss_cmp: Number of single-shot comparator controls that are available.
@@ -1005,6 +1007,7 @@ struct etmv4_drvdata {u8 numextinsel;u8 numvmidc;u8 nrseqstate; +u8 nr_seq_ctrls;u8 nr_event;u8 nr_resource;u8 nr_ss_cmp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1114/1424 coresight: etm4x: fix leaked trace id
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 467e5862ccb0eed907002f4c6d3badfe34360940 ]
If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(), the trace ID may be leaked because it is not released.
To address this, call etm4_release_trace_id() when etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config().
--- drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +3 -1
@@ -848,8 +848,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)cscfg_config_sysfs_get_active_cfg (&cfg_hash, &preset);if (cfg_hash) { ret =cscfg_csdev_enable_active_config (csdev, cfg_hash, preset); -if (ret) +if (ret) { +etm4_release_trace_id (drvdata);return ret; + } }spin_lock (&drvdata->spinlock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1115/1424 regulator: qcom-rpmh: Fix PMIC5 BOB bypass mode handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kamal Wadhwa <[email protected]>
[ Upstream commit abd14bebb87e0fa2749371272c8b31d6ee5f0a36 ]
Currently, when rpmh_regulator_set_mode_bypass() helper function is called to set bypass mode, it sends PMIC4's BOB bypass mode value for even if its a PMIC5 BOB.
To fix this, introduce new hw_data parameterpmic_bypass_mode to store bypass mode value. Use it to send correct PMIC bypass mode value that corresponds to PMIC4/5 BOB regulators from the helper function.
--- drivers/regulator/qcom-rpmh-regulator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/regulator/qcom-rpmh-regulator.c +5 -1
@@ -75,6 +75,7 @@ enum rpmh_regulator_type {* @hpm_min_load_uA: Minimum load current in microamps that requires * high power mode (HPM) operation. This is used * for LDO hardware type regulators only. +* @pmic_bypass_mode: The PMIC bypass mode value. * @pmic_mode_map: Array indexed by regulator framework mode * containing PMIC hardware modes. Must be large * enough to index all framework modes supported
@@ -88,6 +89,7 @@ struct rpmh_vreg_hw_data {const struct linear_range voltage_range;int n_voltages;int hpm_min_load_uA; +int pmic_bypass_mode;const int *pmic_mode_map;unsigned int (*of_map_mode)(unsigned int mode); };
@@ -274,7 +276,7 @@ static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,return pmic_mode;if (bypassed) - cmd.data =PMIC4_BOB_MODE_PASS ; + cmd.data = vreg->hw_data->pmic_bypass_mode;else cmd.data = pmic_mode;
@@ -663,6 +665,7 @@ static const struct rpmh_vreg_hw_data pmic4_bob = { .ops = &rpmh_regulator_vrm_bypass_ops, .voltage_range = REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000), .n_voltages = 84, + .pmic_bypass_mode = PMIC4_BOB_MODE_PASS, .pmic_mode_map = pmic_mode_map_pmic4_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, };
@@ -800,6 +803,7 @@ static const struct rpmh_vreg_hw_data pmic5_bob = { .ops = &rpmh_regulator_vrm_bypass_ops, .voltage_range = REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000), .n_voltages = 32, + .pmic_bypass_mode = PMIC5_BOB_MODE_PASS, .pmic_mode_map = pmic_mode_map_pmic5_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1116/1424 ACPI: video: Release PCI device reference after lookup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 3d7ed9b8ef47b8bcae1fc3e12f7590a217862a89 ]
video_detect_portege_r100() uses pci_get_device() only as a boolean check for the Trident CyberBlade XP4m32 device. pci_get_device() takes a reference on a matching PCI device, but the callback returns without releasing it.
Drop the reference after selecting the vendor backlight quirk so the PCI device can be released normally.
--- drivers/acpi/video_detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/acpi/video_detect.c +3 -1
@@ -135,8 +135,10 @@ static int video_detect_portege_r100(const struct dmi_system_id *d)struct pci_dev *dev;/* Search for Trident CyberBlade XP4m32 to confirm Portégé R100 */ dev =pci_get_device (PCI_VENDOR_ID_TRIDENT ,0x2100 ,NULL ); -if (dev) +if (dev) { acpi_backlight_dmi = acpi_backlight_vendor; +pci_dev_put (dev); + }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1117/1424 sched/fair: Check CPU capacity before comparing group types during load balance
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Neri <[email protected]>
[ Upstream commit 50b101f6e586b4417d060a976fd831cd87e86e2b ]
update_sd_pick_busiest() may incorrectly select a fully_busy group as the busiest group when its per-CPU capacity exceeds that of the destination CPU. This happens because the type of busiest group is initialized to group_has_spare and allows the fully_busy group to win the type comparison.
update_sd_pick_busiest() should not choose a candidate scheduling group with at most one runnable task if its per-CPU capacity is greater than that of the destination CPU. Such a check already exists, but it is done too
late: after the type comparison, preventing a subsequent fully_busy group of equal per-CPU capacity from being correctly selected.
Move this check to occur before comparing group types.
--- kernel/sched/fair.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
kernel/sched/fair.c +11 -11
@@ -10056,6 +10056,17 @@ static bool update_sd_pick_busiest(struct lb_env *env, sds->local_stat.group_type != group_has_spare))return false; +/* +* Candidate sg has no more than one task per CPU and has higher +* per-CPU capacity. Migrating tasks to less capable CPUs may harm +* throughput. Maximize throughput, power/energy consequences are not +* considered. +*/ +if ((env->sd->flags &SD_ASYM_CPUCAPACITY ) && + (sgs->group_type <= group_fully_busy) && + (capacity_greater (sg->sgc->min_capacity,capacity_of (env->dst_cpu)))) +return false; +if (sgs->group_type > busiest->group_type)return true;
@@ -10163,17 +10174,6 @@ static bool update_sd_pick_busiest(struct lb_env *env,break ; } -/* -* Candidate sg has no more than one task per CPU and has higher -* per-CPU capacity. Migrating tasks to less capable CPUs may harm -* throughput. Maximize throughput, power/energy consequences are not -* considered. -*/ -if ((env->sd->flags &SD_ASYM_CPUCAPACITY ) && - (sgs->group_type <= group_fully_busy) && - (capacity_greater (sg->sgc->min_capacity,capacity_of (env->dst_cpu)))) -return false; -return true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1118/1424 Bluetooth: btqca: Fix qca_set_bdaddr() waiting for wrong HCI event
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit cf81f0a3db2a5c34ee6e4ea379c631fab6d13e01 ]
qca_set_bdaddr() waits for HCI_EV_VENDOR when sending EDL_WRITE_BD_ADDR_OPCODE (0xFC14), but the controller responds with Command Complete event as confirmed by btmon on WCN7850:
< HCI Command: Vendor (0x3f|0x0014) plen 6 #3 [hci0]
11 22 33 44 55 66
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #4 [hci0]
Vendor (0x3f|0x0014) ncmd 1
Status: Success (0x00)Fix by passing 0 as the event parameter to __hci_cmd_sync_ev() to wait for the command complete event instead.
--- drivers/bluetooth/btqca.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/bluetooth/btqca.c +1 -2
@@ -1018,8 +1018,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)baswap (&bdaddr_swapped, bdaddr); skb =__hci_cmd_sync_ev (hdev,EDL_WRITE_BD_ADDR_OPCODE ,6 , - &bdaddr_swapped,HCI_EV_VENDOR , -HCI_INIT_TIMEOUT ); + &bdaddr_swapped,0 ,HCI_INIT_TIMEOUT );if (IS_ERR (skb)) { err =PTR_ERR (skb);bt_dev_err (hdev,"QCA Change address cmd failed (%d)" , err);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1119/1424 Bluetooth: btusb: Fix BD_ADDR byte order in btusb_set_bdaddr_wcn6855()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit d0b15d812688d3f0f3fe1c4426e12814d0c294dc ]
btusb_set_bdaddr_wcn6855() sends the address without swapping byte order for VSC 0xFC14, but the command expects the address in reversed byte order compared to other HCI commands like HCI_Create_Connection, resulting in a wrong BD_ADDR being set.
btmon log on WCN6855 shows VSC 0xFC14 is sent with swapped bytes 11 22 33 44 55 66, and Read BD ADDR returns the expected address 11:22:33:44:55:66:
< HCI Command: Vendor (0x3f|0x0014) plen 6 #3 [hci0]
11 22 33 44 55 66
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #4 [hci0]
Vendor (0x3f|0x0014) ncmd 1
Status: Success (0x00)< HCI Command: Read BD ADDR (0x04|0x0009) plen 0 #11 [hci0]
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 10 #12 [hci0]
Read BD ADDR (0x04|0x0009) ncmd 1
Status: Success (0x00)
Address: 11:22:33:44:55:66 (OUI 11-22-33)Fix by swapping the input address before issuing the command.
--- drivers/bluetooth/btusb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/bluetooth/btusb.c +5 -4
@@ -2876,14 +2876,15 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,static int btusb_set_bdaddr_wcn6855 (struct hci_dev *hdev,const bdaddr_t *bdaddr) { +bdaddr_t bdaddr_swapped;struct sk_buff *skb; -u8 buf[6 ];long ret; -memcpy (buf, bdaddr,sizeof (bdaddr_t)); +baswap (&bdaddr_swapped, bdaddr); - skb =__hci_cmd_sync_ev (hdev,0xfc14 ,sizeof (buf), buf, -HCI_EV_CMD_COMPLETE ,HCI_INIT_TIMEOUT ); + skb =__hci_cmd_sync_ev (hdev,0xfc14 ,sizeof (bdaddr_swapped), + &bdaddr_swapped,HCI_EV_CMD_COMPLETE , +HCI_INIT_TIMEOUT );if (IS_ERR (skb)) { ret =PTR_ERR (skb);bt_dev_err (hdev,"Change address command failed (%ld)" , ret);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1120/1424 Bluetooth: btusb: refactor endpoint lookup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 5c31aaa05624b54dc18c9e313bcee5a88c025593 ]
Use the common USB helper for looking up bulk and interrupt endpoints instead of open coding.
Stable-dep-of: 33c6a8d01889 ("Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices")
--- drivers/bluetooth/btusb.c | 51 ++++++--------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-)
drivers/bluetooth/btusb.c +8 -43
@@ -3495,31 +3495,14 @@ static inline int __set_diag_interface(struct hci_dev *hdev) {struct btusb_data *data =hci_get_drvdata (hdev);struct usb_interface *intf = data->diag; -int i; +int ret;if (!data->diag)return -ENODEV ; - data->diag_tx_ep =NULL ; - data->diag_rx_ep =NULL ; - -for (i =0 ; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { -struct usb_endpoint_descriptor *ep_desc; - - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - -if (!data->diag_tx_ep &&usb_endpoint_is_bulk_out (ep_desc)) { - data->diag_tx_ep = ep_desc; -continue ; - } - -if (!data->diag_rx_ep &&usb_endpoint_is_bulk_in (ep_desc)) { - data->diag_rx_ep = ep_desc; -continue ; - } - } - -if (!data->diag_tx_ep || !data->diag_rx_ep) { + ret =usb_find_common_endpoints (intf->cur_altsetting, &data->diag_rx_ep, + &data->diag_tx_ep,NULL ,NULL ); +if (ret) {bt_dev_err (hdev,"invalid diagnostic descriptors" );return -ENODEV ; }
@@ -3720,12 +3703,11 @@ static const struct file_operations force_poll_sync_fops = {static int btusb_probe (struct usb_interface *intf,const struct usb_device_id *id) { -struct usb_endpoint_descriptor *ep_desc;struct gpio_desc *reset_gpio;struct btusb_data *data;struct hci_dev *hdev;unsigned ifnum_base; -int i, err, priv_size; +int err, priv_size;BT_DBG ("intf %p id %p" , intf, id);
@@ -3762,26 +3744,9 @@ static int btusb_probe(struct usb_interface *intf,if (!data)return -ENOMEM ; -for (i =0 ; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - -if (!data->intr_ep &&usb_endpoint_is_int_in (ep_desc)) { - data->intr_ep = ep_desc; -continue ; - } - -if (!data->bulk_tx_ep &&usb_endpoint_is_bulk_out (ep_desc)) { - data->bulk_tx_ep = ep_desc; -continue ; - } - -if (!data->bulk_rx_ep &&usb_endpoint_is_bulk_in (ep_desc)) { - data->bulk_rx_ep = ep_desc; -continue ; - } - } - -if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { + err =usb_find_common_endpoints (intf->cur_altsetting, &data->bulk_rx_ep, + &data->bulk_tx_ep, &data->intr_ep,NULL ); +if (err) {kfree (data);return -ENODEV ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1121/1424 Bluetooth: btusb: Record matched usb_device_id into btusb_data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit ff50db7a522e7bd3bd1c4db6da715e4bdb53af97 ]
Add @match_id to btusb_data to record the matched usb_device_id which will be used later.
Stable-dep-of: 33c6a8d01889 ("Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices")
--- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/bluetooth/btusb.c +2 -0
@@ -913,6 +913,7 @@ struct btusb_data {bool usb_alt6_packet_flow;int isoc_altsetting;int suspend_count; +const struct usb_device_id *match_id;int (*recv_event)(struct hci_dev *hdev,struct sk_buff *skb);int (*recv_acl)(struct hci_dev *hdev,struct sk_buff *skb);
@@ -3744,6 +3745,7 @@ static int btusb_probe(struct usb_interface *intf,if (!data)return -ENOMEM ; + data->match_id = id; err =usb_find_common_endpoints (intf->cur_altsetting, &data->bulk_rx_ep, &data->bulk_tx_ep, &data->intr_ep,NULL );if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1122/1424 Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit 33c6a8d01889a84cc773c0c20c8323bce84af27d ]
Devcoredump is not enabled for ATH3012 or QCA_ROME, but they unconditionally populate devcoredump fields in btusb_setup_qca().
Fix by populating devcoredump fields only when BTUSB_QCA_WCN6855 is set, which marks the first generation of QCA BT SoCs for which devcoredump is enabled.
--- drivers/bluetooth/btusb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/bluetooth/btusb.c +4 -2
@@ -3468,8 +3468,10 @@ static int btusb_setup_qca(struct hci_dev *hdev)if (err <0 )return err; - btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version); - btdata->qca_dump.controller_id =le32_to_cpu (ver.rom_version); +if (btdata->match_id->driver_info &BTUSB_QCA_WCN6855 ) { + btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version); + btdata->qca_dump.controller_id =le32_to_cpu (ver.rom_version); + }if (!(status &QCA_SYSCFG_UPDATED )) { err =btusb_setup_qca_load_nvm (hdev, &ver, info);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1123/1424 perf trace-event: Fix integer truncation in do_read() and skip()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanushree Shah <[email protected]>
[ Upstream commit c108c1391be0826920991d24532fbae8f6373ddc ]
The do_read() and skip() functions use 'int' for size parameters, truncating 64-bit sizes from callers. This causes two issues:
1. Uninitialized memory dump: do_read() reads fewer bytes than allocated, leaving uninitialized heap memory that gets written to output files.
2. Out-of-bounds read: Parsing functions process the full 64-bit size while only partial data was read into the buffer.
Change do_read(), __do_read(), and skip() to use size_t for size parameters and ssize_t for return values (where applicable), matching read()/write() system calls.
Update callers to use ssize_t for storing return values.
--- tools/perf/util/trace-event-read.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
tools/perf/util/trace-event-read.c +14 -14
@@ -25,18 +25,18 @@ static int input_fd;static ssize_t trace_data_size;static bool repipe; -static int __do_read (int fd,void *buf,int size) +static ssize_t __do_read (int fd,void *buf,size_t size) { -int rsize = size; +size_t rsize = size;while (size) { -int ret =read (fd, buf, size); +ssize_t ret =read (fd, buf, size);if (ret <=0 )return -1 ;if (repipe) { -int retw =write (STDOUT_FILENO , buf, ret); +ssize_t retw =write (STDOUT_FILENO , buf, ret);if (retw <=0 || retw != ret) {pr_debug ("repiping input file" );
@@ -51,13 +51,13 @@ static int __do_read(int fd, void *buf, int size)return rsize; } -static int do_read (void *data,int size) +static ssize_t do_read (void *data,size_t size) { -int r; +ssize_t r; r =__do_read (input_fd, data, size);if (r <=0 ) { -pr_debug ("reading input file (size expected=%d received=%d)" , +pr_debug ("reading input file (size expected=%zu received=%zd)" , size, r);return -1 ; }
@@ -68,10 +68,10 @@ static int do_read(void *data, int size) }/* If it fails, the next read will report it */ -static void skip (int size) +static void skip (size_t size) {char buf[BUFSIZ ]; -int r; +size_t r;while (size) { r = size >BUFSIZ ?BUFSIZ : size;
@@ -202,7 +202,7 @@ static int read_header_files(struct tep_handle *pevent)unsigned long long size;char *header_page;char buf[BUFSIZ ]; -int ret =0 ; +ssize_t ret =0 ;if (do_read (buf,12 ) <0 )return -1 ;
@@ -250,7 +250,7 @@ static int read_header_files(struct tep_handle *pevent)static int read_ftrace_file (struct tep_handle *pevent,unsigned long long size) { -int ret; +ssize_t ret;char *buf; buf =malloc (size);
@@ -276,7 +276,7 @@ static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)static int read_event_file (struct tep_handle *pevent,char *sys,unsigned long long size) { -int ret; +ssize_t ret;char *buf; buf =malloc (size);
@@ -322,7 +322,7 @@ static int read_event_files(struct tep_handle *pevent)int systems;int count;int i,x; -int ret; +ssize_t ret; systems =read4 (pevent);
@@ -350,7 +350,7 @@ static int read_saved_cmdline(struct tep_handle *pevent) {unsigned long long size;char *buf; -int ret; +ssize_t ret;/* it can have 0 size */ size =read8 (pevent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1124/1424 scsi: sd: Fix sd_done() sense handling condition
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <[email protected]>
[ Upstream commit a640d4546b11be5709a82bdc63d7dafd8ddc6c9e ]
Only enter the sense_key switch when the command returned CHECK CONDITION with valid, non-deferred sense. The old condition let deferred or invalid sense fall through and mis-handle the I/O.
--- drivers/scsi/sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/sd.c +2 -2
@@ -2167,8 +2167,8 @@ static int sd_done(struct scsi_cmnd *SCpnt) } sdkp->medium_access_timed_out =0 ; -if (!scsi_status_is_check_condition (result) && - (!sense_valid || sense_deferred)) +if (!scsi_status_is_check_condition (result) || + !sense_valid || sense_deferred) goto out;switch (sshdr.sense_key) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1125/1424 btrfs: retry verity reads for not-uptodate Merkle folios
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 8cc569696dac51fc62bb39b3b8f530582b916d29 ]
btrfs_read_merkle_tree_page() can find a folio in the mapping that is not uptodate. After taking the folio lock, the current code treats that state as a read error and returns -EIO.
That can make a previous transient read failure sticky. If the failed read left a not-uptodate folio in the mapping, later callers find that folio and fail instead of retrying the read.
Keep the existing page-cache insertion and locking order, but retry the Merkle item read when a not-uptodate folio is found in the mapping. Also unlock the folio when read_key_bytes() fails so that a later caller can lock it and retry the read.
--- fs/btrfs/verity.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
fs/btrfs/verity.c +11 -5
@@ -732,14 +732,18 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode, goto out;folio_lock (folio); -/* If it's not uptodate after we have the lock, we got a read error. */ -if (!folio_test_uptodate (folio)) { +/* Folio was truncated from mapping. */ +if (!folio->mapping) {folio_unlock (folio);folio_put (folio); -return ERR_PTR (-EIO ); + goto again; } -folio_unlock (folio); - goto out; +/* Another reader may have filled the folio while we waited. */ +if (folio_test_uptodate (folio)) { +folio_unlock (folio); + goto out; + } + goto read_folio; } folio = filemap_alloc_folio(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS),
@@ -756,6 +760,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,return ERR_PTR (ret); } +read_folio:/* * Merkle item keys are indexed from byte 0 in the merkle tree. * They have the form:
@@ -765,6 +770,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode, ret =read_key_bytes (BTRFS_I (inode),BTRFS_VERITY_MERKLE_ITEM_KEY , off,folio_address (folio),PAGE_SIZE , &folio->page);if (ret <0 ) { +folio_unlock (folio);folio_put (folio);return ERR_PTR (ret); }
Signature · 1 line
2.53.0