From: Marco Pagani <marco.pagani@linux.dev>
To: "Tvrtko Ursulin" <tursulin@ursulin.net>,
"Matthew Brost" <matthew.brost@intel.com>,
"Danilo Krummrich" <dakr@kernel.org>,
"Philipp Stanner" <phasta@kernel.org>,
"Christian König" <ckoenig.leichtzumerken@gmail.com>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>
Cc: Marco Pagani <marco.pagani@linux.dev>,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH] drm/sched/tests: Let the DRM scheduler manage job lifetimes
Date: Tue, 7 Jul 2026 13:48:06 +0200 [thread overview]
Message-ID: <20260707114807.154572-1-marco.pagani@linux.dev> (raw)
Currently, the mock scheduler uses KUnit-managed memory for jobs. This ties
the job's memory lifetime to the test suite rather than the DRM scheduler's
callbacks. This does not represent real driver behavior and can lead to
potential Use-After-Free bugs in the tests.
Update the mock scheduler to let the lifetime of jobs be managed by the DRM
scheduler's asynchronous callbacks instead of KUnit managed memory. Add a
kref reference counter to track the job's lifetime between test suites and
the scheduler.
Finally, to avoid memory leaks in the event of an early test abortion,
register a cleanup KUnit action that automatically puts the reference to
the job.
Signed-off-by: Marco Pagani <marco.pagani@linux.dev>
---
.../gpu/drm/scheduler/tests/mock_scheduler.c | 68 ++++++++++++++-----
drivers/gpu/drm/scheduler/tests/sched_tests.h | 6 ++
2 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c
index 14403a762335..51f81082f37a 100644
--- a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c
+++ b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c
@@ -96,6 +96,14 @@ drm_mock_sched_job_signal_timer(struct hrtimer *hrtimer)
return HRTIMER_NORESTART;
}
+static void drm_mock_sched_job_cleanup_action(void *ptr)
+{
+ struct drm_mock_sched_job *job = ptr;
+
+ job->test = NULL;
+ drm_mock_sched_job_put(job);
+}
+
/**
* drm_mock_sched_job_new - Create a new mock scheduler job
*
@@ -111,23 +119,34 @@ drm_mock_sched_job_new(struct kunit *test,
struct drm_mock_sched_job *job;
int ret;
- job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL);
+ /* Let the DRM Scheduler manage the lifetime of the job */
+ job = kzalloc_obj(*job, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, job);
+ kref_init(&job->refcount);
+ job->test = test;
+
ret = drm_sched_job_init(&job->base,
&entity->base,
1,
NULL,
1);
- KUNIT_ASSERT_EQ(test, ret, 0);
-
- job->test = test;
+ if (ret) {
+ kfree(job);
+ KUNIT_ASSERT_EQ_MSG(test, ret, 0, "drm_sched_job_init failed");
+ }
init_completion(&job->done);
INIT_LIST_HEAD(&job->link);
hrtimer_setup(&job->timer, drm_mock_sched_job_signal_timer,
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ ret = kunit_add_action(test, drm_mock_sched_job_cleanup_action, job);
+ if (ret) {
+ drm_mock_sched_job_put(job);
+ KUNIT_ASSERT_EQ_MSG(test, ret, 0, "kunit_add_action failed");
+ }
+
return job;
}
@@ -152,7 +171,7 @@ static void drm_mock_sched_hw_fence_release(struct dma_fence *fence)
hrtimer_cancel(&job->timer);
- /* Containing job is freed by the kunit framework */
+ drm_mock_sched_job_put(job);
}
static const struct dma_fence_ops drm_mock_sched_hw_fence_ops = {
@@ -173,6 +192,8 @@ static struct dma_fence *mock_sched_run_job(struct drm_sched_job *sched_job)
sched->hw_timeline.context,
atomic_inc_return(&sched->hw_timeline.next_seqno));
+ kref_get(&job->refcount);
+
dma_fence_get(&job->hw_fence); /* Reference for the job_list */
spin_lock_irq(&sched->lock);
@@ -200,6 +221,17 @@ static struct dma_fence *mock_sched_run_job(struct drm_sched_job *sched_job)
return &job->hw_fence;
}
+static void mock_sched_free_job(struct drm_sched_job *sched_job)
+{
+ struct drm_mock_sched_job *job = drm_sched_job_to_mock_job(sched_job);
+
+ /* Only if the fence has been successfully initialized */
+ if (job->hw_fence.ops)
+ dma_fence_put(&job->hw_fence);
+
+ drm_mock_sched_job_put(job);
+}
+
/*
* Normally, drivers would take appropriate measures in this callback, such as
* killing the entity the faulty job is associated with, resetting the hardware
@@ -232,21 +264,26 @@ mock_sched_timedout_job(struct drm_sched_job *sched_job)
}
spin_unlock_irqrestore(&sched->lock, flags);
- dma_fence_put(&job->hw_fence);
- drm_sched_job_cleanup(sched_job);
- /* Mock job itself is freed by the kunit framework. */
+ mock_sched_free_job(sched_job);
return DRM_GPU_SCHED_STAT_RESET;
}
-static void mock_sched_free_job(struct drm_sched_job *sched_job)
+static void drm_mock_sched_job_release(struct kref *ref)
{
- struct drm_mock_sched_job *job = drm_sched_job_to_mock_job(sched_job);
+ struct drm_mock_sched_job *job;
+
+ job = container_of(ref, struct drm_mock_sched_job, refcount);
- dma_fence_put(&job->hw_fence);
- drm_sched_job_cleanup(sched_job);
+ drm_sched_job_cleanup(&job->base);
- /* Mock job itself is freed by the kunit framework. */
+ kfree(job);
+}
+
+void drm_mock_sched_job_put(struct drm_mock_sched_job *job)
+{
+ if (job)
+ kref_put(&job->refcount, drm_mock_sched_job_release);
}
static void mock_sched_cancel_job(struct drm_sched_job *sched_job)
@@ -265,10 +302,7 @@ static void mock_sched_cancel_job(struct drm_sched_job *sched_job)
}
spin_unlock_irqrestore(&sched->lock, flags);
- /*
- * The GPU Scheduler will call drm_sched_backend_ops.free_job(), still.
- * Mock job itself is freed by the kunit framework.
- */
+ /* The GPU Scheduler will call drm_sched_backend_ops.free_job() */
}
static const struct drm_sched_backend_ops drm_mock_scheduler_ops = {
diff --git a/drivers/gpu/drm/scheduler/tests/sched_tests.h b/drivers/gpu/drm/scheduler/tests/sched_tests.h
index 553d45abd057..e4d33f0bf935 100644
--- a/drivers/gpu/drm/scheduler/tests/sched_tests.h
+++ b/drivers/gpu/drm/scheduler/tests/sched_tests.h
@@ -13,6 +13,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
+#include <linux/kref.h>
#include <drm/gpu_scheduler.h>
@@ -90,6 +91,7 @@ struct drm_mock_sched_entity {
*/
struct drm_mock_sched_job {
struct drm_sched_job base;
+ struct kref refcount;
struct completion done;
@@ -144,6 +146,8 @@ struct drm_mock_sched_job *
drm_mock_sched_job_new(struct kunit *test,
struct drm_mock_sched_entity *entity);
+void drm_mock_sched_job_put(struct drm_mock_sched_job *job);
+
/**
* drm_mock_sched_job_submit - Arm and submit a job in one go
*
@@ -151,6 +155,8 @@ drm_mock_sched_job_new(struct kunit *test,
*/
static inline void drm_mock_sched_job_submit(struct drm_mock_sched_job *job)
{
+ kref_get(&job->refcount);
+
drm_sched_job_arm(&job->base);
drm_sched_entity_push_job(&job->base);
}
--
2.55.0
next reply other threads:[~2026-07-07 11:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 11:48 Marco Pagani [this message]
2026-07-07 12:05 ` [RFC PATCH] drm/sched/tests: Let the DRM scheduler manage job lifetimes sashiko-bot
2026-07-08 9:20 ` Tvrtko Ursulin
2026-07-09 21:53 ` Marco Pagani
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260707114807.154572-1-marco.pagani@linux.dev \
--to=marco.pagani@linux.dev \
--cc=airlied@gmail.com \
--cc=ckoenig.leichtzumerken@gmail.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=matthew.brost@intel.com \
--cc=mripard@kernel.org \
--cc=phasta@kernel.org \
--cc=simona@ffwll.ch \
--cc=tursulin@ursulin.net \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox