linuxkpi: Fix cancel_delayed_work_sync() return value#2268
Open
ryanfahy314 wants to merge 1 commit into
Open
Conversation
Align behavior between the Linux cancel_delayed_work_sync() function return value and the LinuxKPI equivalent. Linux cancel_delayed_work_sync() returns whether delayed work was pending, even if canceled before executing. This includes the case where the timer fired and work was queued but the callback had not yet started. The LinuxKPI version used the return value from taskqueue_cancel() as the return value of the public facing API, which inverted the behavior of two cases, violating the Linux API contract. Queued work which was removed before running would return false, and work whose callback was already executing would return true. Track the taskqueue pending count separately from the taskqueue_cancel() return value. Use the pending count for the public return value. Use taskqueue_cancel() return value only to decide whether state needs to be re-checked. This fixes behavior in consumers which use the return value of cancel_delayed_work_sync() to distinguish canceled pending work from work that was already running or idle. Signed-off-by: Ryan Fahy <ryan@rfahy.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes the LinuxKPI workqueue delayed work sync behavior to better match the Linux workqueue API contract.
I found this while debugging Intel Arc A770/DG2 support on 15.1-STABLE which showed GuC context scheduling failures under hardware-accelerated Xorg workloads.
Problem
There's a subtle difference in behavior between the Linux
cancel_delayed_work_sync()return value and the LinuxKPI equivalent.Expected Linux Behavior
The return value behavior of
cancel_delayed_work_sync()can be summarized as:Reference: https://docs.kernel.org/core-api/workqueue.html
Old LinuxKPI Behavior
The return value behavior diverges from this contract in two cases. In
linux_cancel_delayed_work_sync():This causes problems in consumers which use this return value to distinguish between "pending work was canceled" and "work already ran/is running/was idle."
Changes
taskqueue_cancel()return value.cancel_delayed_work_sync()return value.taskqueue_cancel()return value only to decide whether state needs to be re-checked.This brings the public-facing API into alignment with the Linux workqueue return value semantics.
Testing
I performed A/B testing of this change using an Intel Arc A770 GPU with Xorg direct rendering to exercise the context scheduling pipeline.
To simulate a workload with heavy GuC context scheduling, I ran a script that opened/moved/resized/closed Firefox windows repeatedly.
This testing was performed with a modified driver implementing the changes described in this drm-kmod pull request: freebsd/drm-kmod#468
In addition to the above PR, I also used temporary instrumentation of the i915 GuC scheduler pipeline.
Before LinuxKPI update
With the kernel LinuxKPI layer untouched and the modified driver, under hardware-accelerated loads, I experienced a crash anywhere between 5 and 60 minutes.
The targeted GuC instrumentation observed context 4107 entering a state where it was marked both destroyed and enabled
ctx_id=4107 sched_state=0x12 destroyed=1 pend_en=0 pend_dis=0 enabled=1 registered=0 closed=0 invalid_guc_id=0Within the same captured window, I observed the scheduled disable preparation updating that context to:
ctx_id=4107 sched_state=0x6 destroyed=1 pend_en=0 pend_dis=1 enabled=0 registered=0 closed=0 invalid_guc_id=0Leading to:
GUC: Bad context sched_state 0x6, ctx_id 4107Captured marker counts with the old behavior
Note: These are not necessarily unique failure counts as they were captured from overlapping logs, but they show that the failure was reproducible and showed the same repeated pattern.
I was able to trace this to the i915 GuC submission path, which consumes the return value here:
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.cSimplified:
A nearby comment explains that this path races with context close, so it uses the return value of cancel_delayed_work_sync() to determine whether this path should handle cancellation and unpin, or if it should wait for context close to complete.
After LinuxKPI update
After aligning the behavior of the LinuxKPI with the Linux workqueue return value semantics, I rebuilt and booted a test kernel on the same 15.1-STABLE commit as my baseline:
FreeBSD 15.1-STABLE amd64 15015017fa638d6f7cf9ee471648a794756cb9d0aa289baand ensured that Xorg was using direct rendering for the desktop display
After the same Firefox window churning workload, there was no recurrence of the bad GuC/CT/context scheduling markers after approximately 3.5 hours:
Contributor Note
For transparency, AI assistance was used in a limited scope during discovery and debugging. This included debugging, source navigation guidance, log/crashdump analysis, and temporary instrumentation of the i915 GuC context scheduler. All submitted code changes were written, reviewed, built, and tested by me.