The final intel_context_put() may drop the last reference to a signaler context. GuC parallel child contexts are freed immediately by __guc_context_destroy() rather than via call_rcu(), so reading ce->signal_link.next to advance the RCU iterator afterwards is a use-after-free. Cache the next context before the loop body instead. Fixes: c744d50363b7 ("drm/i915/gt: Split the breadcrumb spinlock between global and contexts") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang --- drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index c10ac0ab3bfa..f840e98792cd 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -174,7 +174,7 @@ static void signal_irq_work(struct irq_work *work) struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work); const ktime_t timestamp = ktime_get(); struct llist_node *signal, *sn; - struct intel_context *ce; + struct intel_context *ce, *cn; signal = NULL; if (unlikely(!llist_empty(&b->signaled_requests))) @@ -210,9 +210,19 @@ static void signal_irq_work(struct irq_work *work) rcu_read_lock(); atomic_inc(&b->signaler_active); - list_for_each_entry_rcu(ce, &b->signalers, signal_link) { + for (ce = list_first_or_null_rcu(&b->signalers, typeof(*ce), signal_link); + ce; + ce = cn) { struct i915_request *rq; + /* + * Grab the next signaler up front, as dropping the final + * reference below may free the current one before we + * advance the iterator. + */ + cn = list_next_or_null_rcu(&b->signalers, &ce->signal_link, + typeof(*cn), signal_link); + list_for_each_entry_rcu(rq, &ce->signals, signal_link) { bool release; -- 2.34.1