From a3d79f7f20096df4e41d88a510dbfd6ff1956a70 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 14 Jul 2026 16:57:11 +0200 Subject: [PATCH] 5.10-stable patches added patches: cpufreq-fix-hotplug-suspend-race-during-reboot.patch cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch hid-wacom-stop-hardware-after-post-start-probe-failures.patch posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch --- ...x-hotplug-suspend-race-during-reboot.patch | 62 ++++++ ...e-and-double-free-in-_osc-evaluation.patch | 43 +++++ ...rk-on-remove-to-fix-a-use-after-free.patch | 68 +++++++ ...ttr_read_values-for-multi-byte-reads.patch | 179 ++++++++++++++++++ ...ware-after-post-start-probe-failures.patch | 80 ++++++++ ...-leak-in-do_cpu_nanosleep-error-path.patch | 40 ++++ ...pi-be-default-off-for-non-preempt_rt.patch | 100 ++++++++++ queue-5.10/series | 7 + 8 files changed, 579 insertions(+) create mode 100644 queue-5.10/cpufreq-fix-hotplug-suspend-race-during-reboot.patch create mode 100644 queue-5.10/cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch create mode 100644 queue-5.10/hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch create mode 100644 queue-5.10/hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch create mode 100644 queue-5.10/hid-wacom-stop-hardware-after-post-start-probe-failures.patch create mode 100644 queue-5.10/posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch create mode 100644 queue-5.10/sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch diff --git a/queue-5.10/cpufreq-fix-hotplug-suspend-race-during-reboot.patch b/queue-5.10/cpufreq-fix-hotplug-suspend-race-during-reboot.patch new file mode 100644 index 0000000000..3e2b967beb --- /dev/null +++ b/queue-5.10/cpufreq-fix-hotplug-suspend-race-during-reboot.patch @@ -0,0 +1,62 @@ +From a9029dd55696c651ee46912afa2a166fa456bb3e Mon Sep 17 00:00:00 2001 +From: Tianxiang Chen +Date: Wed, 8 Apr 2026 22:19:14 +0800 +Subject: cpufreq: Fix hotplug-suspend race during reboot + +From: Tianxiang Chen + +commit a9029dd55696c651ee46912afa2a166fa456bb3e upstream. + +During system reboot, cpufreq_suspend() is called via the +kernel_restart() -> device_shutdown() path. Unlike the normal system +suspend path, the reboot path does not call freeze_processes(), so +userspace processes and kernel threads remain active. + +This allows CPU hotplug operations to run concurrently with +cpufreq_suspend(). The original code has no synchronization with CPU +hotplug, leading to a race condition where governor_data can be freed +by the hotplug path while cpufreq_suspend() is still accessing it, +resulting in a null pointer dereference: + + Unable to handle kernel NULL pointer dereference + Call Trace: + do_kernel_fault+0x28/0x3c + cpufreq_suspend+0xdc/0x160 + device_shutdown+0x18/0x200 + kernel_restart+0x40/0x80 + arm64_sys_reboot+0x1b0/0x200 + +Fix this by adding cpus_read_lock()/cpus_read_unlock() to +cpufreq_suspend() to block CPU hotplug operations while suspend is in +progress. + +Fixes: 65650b35133f ("cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown") +Signed-off-by: Tianxiang Chen +Reviewed-by: Zhongqiu Han +Cc: All applicable +[ rjw: Changelog edits ] +Link: https://patch.msgid.link/20260408141914.35281-1-nanmu@xiaomi.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + drivers/cpufreq/cpufreq.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -1872,6 +1872,7 @@ void cpufreq_suspend(void) + if (!cpufreq_driver) + return; + ++ cpus_read_lock(); + if (!has_target() && !cpufreq_driver->suspend) + goto suspend; + +@@ -1891,6 +1892,7 @@ void cpufreq_suspend(void) + + suspend: + cpufreq_suspended = true; ++ cpus_read_unlock(); + } + + /** diff --git a/queue-5.10/cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch b/queue-5.10/cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch new file mode 100644 index 0000000000..b32f9db3d5 --- /dev/null +++ b/queue-5.10/cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch @@ -0,0 +1,43 @@ +From 266d3dd8b757b48a576e90f018b51f7b7563cc32 Mon Sep 17 00:00:00 2001 +From: Yuho Choi +Date: Thu, 16 Apr 2026 10:46:21 -0400 +Subject: cpufreq: pcc: fix use-after-free and double free in _OSC evaluation + +From: Yuho Choi + +commit 266d3dd8b757b48a576e90f018b51f7b7563cc32 upstream. + +pcc_cpufreq_do_osc() calls acpi_evaluate_object() twice for the +two-phase _OSC negotiation. Between the two calls it freed +output.pointer but left output.length unchanged. Since +acpi_evaluate_object() treats a non-zero length with a non-NULL +pointer as an existing buffer to write into, the second call wrote +into freed memory (use-after-free). The subsequent kfree(output.pointer) +at out_free then freed the same pointer a second time (double free). + +Reset output.pointer to NULL and output.length to ACPI_ALLOCATE_BUFFER +after freeing the first result, so ACPICA allocates a fresh buffer for +each phase independently. + +Fixes: 0f1d683fb35d ("[CPUFREQ] Processor Clocking Control interface driver") +Signed-off-by: Yuho Choi +Reviewed-by: Zhongqiu Han +Cc: All applicable +Link: https://patch.msgid.link/20260416144621.93964-1-dbgh9129@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + drivers/cpufreq/pcc-cpufreq.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/cpufreq/pcc-cpufreq.c ++++ b/drivers/cpufreq/pcc-cpufreq.c +@@ -351,6 +351,8 @@ static int __init pcc_cpufreq_do_osc(acp + } + + kfree(output.pointer); ++ output.pointer = NULL; ++ output.length = ACPI_ALLOCATE_BUFFER; + capabilities[0] = 0x0; + capabilities[1] = 0x1; + diff --git a/queue-5.10/hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch b/queue-5.10/hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch new file mode 100644 index 0000000000..dbd8817bcd --- /dev/null +++ b/queue-5.10/hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch @@ -0,0 +1,68 @@ +From 7705b4140d188ce22656f6e541ae7ef834c7e11a Mon Sep 17 00:00:00 2001 +From: Maoyi Xie +Date: Thu, 18 Jun 2026 15:06:35 +0800 +Subject: HID: lg-g15: cancel pending work on remove to fix a use-after-free + +From: Maoyi Xie + +commit 7705b4140d188ce22656f6e541ae7ef834c7e11a upstream. + +lg_g15_data is allocated with devm and holds a work item. The report +handlers schedule that work straight from device input. +lg_g15_event() and lg_g15_v2_event() do it on the backlight cycle key, +and lg_g510_leds_event() does it too. The worker dereferences the +lg_g15_data back through container_of. + +The driver had no remove callback and never cancelled the work. So if a +report scheduled the work and the keyboard was then unplugged, devres +freed lg_g15_data while the work was still pending or running, and the +worker touched freed memory. This is a use-after-free. It is reachable +as a race on device unplug. + +Add a remove callback that cancels the work before devres frees the +state. g15->work is only initialized for the models that schedule it +(G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so guard the +cancel on g15->work.func to avoid cancelling a work that was never set +up. The g15 NULL test mirrors the one already in lg_g15_raw_event(). + +Fixes: 97b741aba918 ("HID: lg-g15: Add keyboard and LCD backlight control") +Cc: stable@vger.kernel.org +Suggested-by: Hans de Goede +Signed-off-by: Maoyi Xie +Reviewed-by: Hans de Goede +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-lg-g15.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/hid/hid-lg-g15.c ++++ b/drivers/hid/hid-lg-g15.c +@@ -894,11 +894,27 @@ static const struct hid_device_id lg_g15 + }; + MODULE_DEVICE_TABLE(hid, lg_g15_devices); + ++static void lg_g15_remove(struct hid_device *hdev) ++{ ++ struct lg_g15_data *g15 = hid_get_drvdata(hdev); ++ ++ /* ++ * g15->work is only initialized for the models that schedule it ++ * (G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so only ++ * cancel it when it was set up. ++ */ ++ if (g15 && g15->work.func) ++ cancel_work_sync(&g15->work); ++ ++ hid_hw_stop(hdev); ++} ++ + static struct hid_driver lg_g15_driver = { + .name = "lg-g15", + .id_table = lg_g15_devices, + .raw_event = lg_g15_raw_event, + .probe = lg_g15_probe, ++ .remove = lg_g15_remove, + }; + module_hid_driver(lg_g15_driver); + diff --git a/queue-5.10/hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch b/queue-5.10/hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch new file mode 100644 index 0000000000..e92c6c2151 --- /dev/null +++ b/queue-5.10/hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch @@ -0,0 +1,179 @@ +From f784fcea450617055d2d12eec5b2f6e0e38bf878 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Wed, 10 Jun 2026 16:29:09 +0800 +Subject: HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads + +From: Srinivas Pandruvada + +commit f784fcea450617055d2d12eec5b2f6e0e38bf878 upstream. + +sensor_hub_input_attr_get_raw_value() is limited to returning a single +32-bit value, which is insufficient for sensors that report data larger +than 32 bits, such as a quaternion with four s16 elements. + +Add sensor_hub_input_attr_read_values() that accepts a caller-provided +buffer and accumulates incoming data until the buffer is full. The two +paths are distinguished in sensor_hub_raw_event() by pending.max_raw_size +being non-zero, preserving backward compatibility. + +Signed-off-by: Srinivas Pandruvada +Co-developed-by: Zhang Lixu +Signed-off-by: Zhang Lixu +Acked-by: Jiri Kosina +Reviewed-by: Andy Shevchenko +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-sensor-hub.c | 77 +++++++++++++++++++++++++++++++++++++---- + include/linux/hid-sensor-hub.h | 25 +++++++++++++ + 2 files changed, 96 insertions(+), 6 deletions(-) + +--- a/drivers/hid/hid-sensor-hub.c ++++ b/drivers/hid/hid-sensor-hub.c +@@ -287,6 +287,54 @@ done_proc: + } + EXPORT_SYMBOL_GPL(sensor_hub_get_feature); + ++int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev, ++ u32 usage_id, u32 attr_usage_id, ++ u32 report_id, ++ enum sensor_hub_read_flags flag, ++ u32 buffer_size, u8 *buffer) ++{ ++ struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); ++ struct hid_report *report; ++ unsigned long flags; ++ long cycles; ++ int ret; ++ ++ report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); ++ if (!report) ++ return -EINVAL; ++ ++ mutex_lock(hsdev->mutex_ptr); ++ if (flag == SENSOR_HUB_SYNC) { ++ memset(&hsdev->pending, 0, sizeof(hsdev->pending)); ++ init_completion(&hsdev->pending.ready); ++ hsdev->pending.usage_id = usage_id; ++ hsdev->pending.attr_usage_id = attr_usage_id; ++ hsdev->pending.max_raw_size = buffer_size; ++ hsdev->pending.raw_data = buffer; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ hsdev->pending.status = true; ++ spin_unlock_irqrestore(&data->lock, flags); ++ } ++ mutex_lock(&data->mutex); ++ hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); ++ mutex_unlock(&data->mutex); ++ ret = 0; ++ if (flag == SENSOR_HUB_SYNC) { ++ cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready, ++ HZ * 5); ++ if (cycles == 0) ++ ret = -ETIMEDOUT; ++ else if (cycles < 0) ++ ret = cycles; ++ ++ hsdev->pending.status = false; ++ } ++ mutex_unlock(hsdev->mutex_ptr); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values); + + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, +@@ -480,6 +528,8 @@ static int sensor_hub_raw_event(struct h + struct hid_collection *collection = NULL; + void *priv = NULL; + struct hid_sensor_hub_device *hsdev = NULL; ++ u32 copy_size; ++ u32 avail; + + hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n", + report->id, size, report->type); +@@ -519,12 +569,27 @@ static int sensor_hub_raw_event(struct h + hsdev->pending.attr_usage_id == + report->field[i]->logical)) { + hid_dbg(hdev, "data was pending ...\n"); +- hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); +- if (hsdev->pending.raw_data) +- hsdev->pending.raw_size = sz; +- else +- hsdev->pending.raw_size = 0; +- complete(&hsdev->pending.ready); ++ if (hsdev->pending.max_raw_size) { ++ if (hsdev->pending.index < hsdev->pending.max_raw_size) { ++ avail = hsdev->pending.max_raw_size - hsdev->pending.index; ++ copy_size = clamp(sz, 0U, avail); ++ ++ memcpy(hsdev->pending.raw_data + hsdev->pending.index, ++ ptr, copy_size); ++ hsdev->pending.index += copy_size; ++ if (hsdev->pending.index >= hsdev->pending.max_raw_size) { ++ hsdev->pending.raw_size = hsdev->pending.index; ++ complete(&hsdev->pending.ready); ++ } ++ } ++ } else { ++ hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); ++ if (hsdev->pending.raw_data) ++ hsdev->pending.raw_size = sz; ++ else ++ hsdev->pending.raw_size = 0; ++ complete(&hsdev->pending.ready); ++ } + } + if (callback->capture_sample) { + if (report->field[i]->logical) +--- a/include/linux/hid-sensor-hub.h ++++ b/include/linux/hid-sensor-hub.h +@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info { + * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. + * @raw_size: Response size for a read request. + * @raw_data: Place holder for received response. ++ * @index: Current write index into raw_data for multi-byte reads. ++ * @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads. + */ + struct sensor_hub_pending { + bool status; +@@ -51,6 +53,8 @@ struct sensor_hub_pending { + u32 attr_usage_id; + int raw_size; + u8 *raw_data; ++ u32 index; ++ u32 max_raw_size; + }; + + /** +@@ -183,6 +187,27 @@ int sensor_hub_input_attr_get_raw_value( + ); + + /** ++ * sensor_hub_input_attr_read_values() - Synchronous multi-byte read request ++ * @hsdev: Hub device instance. ++ * @usage_id: Attribute usage id of parent physical device as per spec ++ * @attr_usage_id: Attribute usage id as per spec ++ * @report_id: Report id to look for ++ * @flag: Synchronous or asynchronous read ++ * @buffer_size: Size of the buffer in bytes ++ * @buffer: Buffer to store the read data ++ * ++ * Issues a synchronous or asynchronous read request for an input attribute, ++ * accumulating data into the provided buffer until it is full. ++ * Return: 0 on success, -ETIMEDOUT if the device did not respond, or a ++ * negative error code. ++ */ ++int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev, ++ u32 usage_id, u32 attr_usage_id, ++ u32 report_id, ++ enum sensor_hub_read_flags flag, ++ u32 buffer_size, u8 *buffer); ++ ++/** + * sensor_hub_set_feature() - Feature set request + * @hsdev: Hub device instance. + * @report_id: Report id to look for diff --git a/queue-5.10/hid-wacom-stop-hardware-after-post-start-probe-failures.patch b/queue-5.10/hid-wacom-stop-hardware-after-post-start-probe-failures.patch new file mode 100644 index 0000000000..6bd4b77e83 --- /dev/null +++ b/queue-5.10/hid-wacom-stop-hardware-after-post-start-probe-failures.patch @@ -0,0 +1,80 @@ +From ec2612b8ad9e642596db011dd8b6568ef1edeaa1 Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Thu, 4 Jun 2026 13:56:58 +0900 +Subject: HID: wacom: stop hardware after post-start probe failures + +From: Myeonghun Pak + +commit ec2612b8ad9e642596db011dd8b6568ef1edeaa1 upstream. + +wacom_parse_and_register() starts HID hardware before registering inputs +and initializing pad LEDs/remotes. Those later steps can fail, but their +error paths currently release Wacom resources without stopping the HID +hardware. + +Route post-hid_hw_start() failures through hid_hw_stop() before +releasing driver resources. + +This issue was identified during our ongoing static-analysis research while +reviewing kernel code. + +Fixes: c1d6708bf0d3 ("HID: wacom: Do not register input devices until after hid_hw_start") +Cc: stable@vger.kernel.org +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Reviewed-by: Dmitry Torokhov +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/wacom_sys.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/hid/wacom_sys.c ++++ b/drivers/hid/wacom_sys.c +@@ -2427,16 +2427,16 @@ static int wacom_parse_and_register(stru + + error = wacom_register_inputs(wacom); + if (error) +- goto fail; ++ goto fail_hw_stop; + + if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) { + error = wacom_initialize_leds(wacom); + if (error) +- goto fail; ++ goto fail_hw_stop; + + error = wacom_initialize_remotes(wacom); + if (error) +- goto fail; ++ goto fail_hw_stop; + } + + if (!wireless) { +@@ -2450,14 +2450,14 @@ static int wacom_parse_and_register(stru + cancel_delayed_work_sync(&wacom->init_work); + _wacom_query_tablet_data(wacom); + error = -ENODEV; +- goto fail_quirks; ++ goto fail_hw_stop; + } + + if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) { + error = hid_hw_open(hdev); + if (error) { + hid_err(hdev, "hw open failed\n"); +- goto fail_quirks; ++ goto fail_hw_stop; + } + } + +@@ -2466,7 +2466,7 @@ static int wacom_parse_and_register(stru + + return 0; + +-fail_quirks: ++fail_hw_stop: + hid_hw_stop(hdev); + fail: + wacom_release_resources(wacom); diff --git a/queue-5.10/posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch b/queue-5.10/posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch new file mode 100644 index 0000000000..a194a40bf9 --- /dev/null +++ b/queue-5.10/posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch @@ -0,0 +1,40 @@ +From 87bd2ad568e15b90d5f7d4bcd70342d05dad649c Mon Sep 17 00:00:00 2001 +From: WenTao Liang +Date: Fri, 12 Jun 2026 00:17:38 +0800 +Subject: posix-cpu-timers: Fix pid refcount leak in do_cpu_nanosleep() error path + +From: WenTao Liang + +commit 87bd2ad568e15b90d5f7d4bcd70342d05dad649c upstream. + +In do_cpu_nanosleep(), posix_cpu_timer_create() takes a pid reference +via get_pid() and stores it in timer.it.cpu.pid. If the subsequent +posix_cpu_timer_set() call fails, the function returns immediately +without calling posix_cpu_timer_del() to release the pid reference, +causing a leak. + +Fix it by calling posix_cpu_timer_del() before the unlock-and-return +on the error path, consistent with the other exit paths in the same +function. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: WenTao Liang +Signed-off-by: Thomas Gleixner +Reviewed-by: Frederic Weisbecker +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260611161738.97043-1-vulab@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/posix-cpu-timers.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/kernel/time/posix-cpu-timers.c ++++ b/kernel/time/posix-cpu-timers.c +@@ -1472,6 +1472,7 @@ static int do_cpu_nanosleep(const clocki + spin_lock_irq(&timer.it_lock); + error = posix_cpu_timer_set(&timer, flags, &it, NULL); + if (error) { ++ posix_cpu_timer_del(&timer); + spin_unlock_irq(&timer.it_lock); + return error; + } diff --git a/queue-5.10/sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch b/queue-5.10/sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch new file mode 100644 index 0000000000..22a80b41f0 --- /dev/null +++ b/queue-5.10/sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch @@ -0,0 +1,100 @@ +From dd29c017aed628076e915fe4cdfb5392fd4c5cab Mon Sep 17 00:00:00 2001 +From: Steven Rostedt +Date: Fri, 15 May 2026 10:37:40 -0400 +Subject: sched/rt: Have RT_PUSH_IPI be default off for non PREEMPT_RT + +From: Steven Rostedt + +commit dd29c017aed628076e915fe4cdfb5392fd4c5cab upstream. + +RT migration is done aggressively. When a CPU schedules out a high +priority RT task for a lower priority task, it will look to see if there's +any RT tasks that are waiting to run on another CPU that is of higher +priority than the task this CPU is about to run. If it finds one, it will +pull that task over to the CPU and allow it to run there instead. + +Normally, this pulling is done by looking at the RT overloaded mask (rto) +which contains all the CPUs in the scheduler domain with RT tasks that are +waiting to run due to a higher priority RT task currently running on their +CPU. The CPU that is about to schedule a lower priority task will grab the +rq lock of the overloaded CPU and move the RT task from that CPU's runqueue +to the local one and schedule the higher priority RT task. + +This caused issues when a lot of CPUs would schedule a lower priority task +at the same time. They would all try to grab the same runqueue lock of +the CPU with the overloaded RT tasks. Only the first CPU that got in will +get that task. All the others would wait until they got the runqueue lock +and see there's nothing to pull and do nothing. On systems with lots of +CPUs, this caused a large latency (up to 500us) which is beyond what +PREEMPT_RT is to allow. + +The solution to that was to create an RT_PUSH_IPI logic. When any CPU +wanted to pull a task, instead of grabbing the runqueue lock of the +overloaded CPU, it would start by sending an IPI to the overloaded CPU, +and that IPI handler would have the CPU with the waiting RT task do a push +instead. Then that handler would send an IPI to the next CPU with +overloaded RT tasks, and so on. Note, after the first CPU starts this +process, if another CPU wanted to do a pull, it would see that the process +has already begun and would only increment a counter to have the IPIs +continue again. + +The RT_PUSH_IPI solved the latency problem with PREEMPT_RT but could cause +a new issue with non PREEMPT_RT. Namely, softirqs run in a threaded +context on PREEMPT_RT but they can run in an interrupt context in non-RT. + +If an IPI lands on a CPU that has just woken up multiple RT tasks and the +current CPU is running a non RT or a low priority RT task, instead of +doing a push, it would simply do a schedule on that CPU. But if a softirq +was also executing on this CPU, the schedule would need to wait until the +softirq finished. Until then, the CPU would still be considered overloaded +as there are RT tasks still waiting to run on it. + +A live lock occurred on a workload that was doing heavy networking traffic +on a large machine where the softirqs would run 500us out of 750us. And it +would also be waking up RT tasks, causing the RT pull logic to be +constantly executed. + +When a softirq triggered on a CPU with RT tasks queued but not running +yet, and the other CPUs would see this CPU as being overloaded, they would +send an IPI over to it. The CPU would notice that the waiting RT tasks are +of higher priority than the currently running task and simply schedule +that CPU instead. But because the softirq was executing, before it could +schedule, it would receive another IPI to do the same. The amount of IPIs +would slow down the currently running softirq so much that before it could +return back to task context, it would execute another softirq never +allowing the CPU to schedule. This live locked that CPU. + +As RT_PUSH_IPI was created to help PREEMPT_RT, make it default off if +PREEMPT_RT is not enabled. + +Fixes: b6366f048e0c ("sched/rt: Use IPI to trigger RT task push migration instead of pulling") +Closes: https://lore.kernel.org/all/20260506235716.2530720-1-tj@kernel.org/ +Reported-by: Tejun Heo +Signed-off-by: Steven Rostedt +Signed-off-by: Peter Zijlstra (Intel) +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260515103740.25ccbed8@gandalf.local.home +Signed-off-by: Greg Kroah-Hartman +--- + kernel/sched/features.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/kernel/sched/features.h ++++ b/kernel/sched/features.h +@@ -73,8 +73,16 @@ SCHED_FEAT(WARN_DOUBLE_CLOCK, false) + * rq lock and possibly create a large contention, sending an + * IPI to that CPU and let that CPU push the RT task to where + * it should go may be a better scenario. ++ * ++ * This is best for PREEMPT_RT, but for non-RT it can cause issues ++ * when preemption is disabled for long periods of time. Have ++ * it only default enabled for PREEMPT_RT. + */ ++# ifdef CONFIG_PREEMPT_RT + SCHED_FEAT(RT_PUSH_IPI, true) ++# else ++SCHED_FEAT(RT_PUSH_IPI, false) ++# endif + #endif + + SCHED_FEAT(RT_RUNTIME_SHARE, false) diff --git a/queue-5.10/series b/queue-5.10/series index 63e8f442f9..5108ade063 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -84,3 +84,10 @@ bluetooth-bnep-pin-l2cap-connection-during-netdev-registration.patch bluetooth-fix-uaf-in-bt_accept_dequeue.patch bluetooth-l2cap-validate-option-length-before-reading-conf-opt-value.patch net-drop-the-lock-in-skb_may_tx_timestamp.patch +sched-rt-have-rt_push_ipi-be-default-off-for-non-preempt_rt.patch +cpufreq-fix-hotplug-suspend-race-during-reboot.patch +cpufreq-pcc-fix-use-after-free-and-double-free-in-_osc-evaluation.patch +posix-cpu-timers-fix-pid-refcount-leak-in-do_cpu_nanosleep-error-path.patch +hid-wacom-stop-hardware-after-post-start-probe-failures.patch +hid-lg-g15-cancel-pending-work-on-remove-to-fix-a-use-after-free.patch +hid-sensor-hub-add-sensor_hub_input_attr_read_values-for-multi-byte-reads.patch -- 2.47.3