summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:12:17 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:12:17 -0400
commit256c5308423befddc20bdf7e59a663f3f1b683ae (patch)
treeba8acb7489cf6c59720eba2cd627ed2befee470e /kernel
parent4266fffc45352bee58323b7903354df00b3df03d (diff)
downloadopen-iov-256c5308423befddc20bdf7e59a663f3f1b683ae.tar.gz
open-iov-256c5308423befddc20bdf7e59a663f3f1b683ae.zip
kernel: Fix gsp_emu_cleanup crash on dead thread (refcount saturation)
Root cause: when the gsp_emu thread crashes (e.g. fortify_panic in gsp_rm_send), the kernel kills it. Later, gsp_emu_cleanup() calls kthread_stop() on the dead thread, hitting refcount_warn_saturate on the freed/saturated task_struct. Fixes: 1. pid_alive() check before kthread_stop() - skip if thread already dead 2. get_task_struct() after kthread_run() - hold reference so the task_struct stays valid even after a crash 3. put_task_struct() in cleanup - release the reference This prevents the module from getting stuck in 'going' state during mdev removal after a gsp_emu thread crash.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_emulation.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c
index f96e521..3b6f6e5 100644
--- a/kernel/gsp_emulation.c
+++ b/kernel/gsp_emulation.c
@@ -575,6 +575,10 @@ int gsp_emu_init(struct nv_vgpu_device *vgpu)
nv_vgpu_err(vgpu, "Failed to start GSP emulation thread: %d", ret);
goto err_fini_client;
}
+ /* Hold a reference on the thread's task_struct so it stays valid
+ * even if the thread crashes (e.g. fortify_panic). Without this,
+ * cleanup could dereference a freed task_struct. */
+ get_task_struct(ctx->thread);
ctx->running = true;
ctx->initialized = true;
@@ -604,11 +608,20 @@ void gsp_emu_cleanup(struct nv_vgpu_device *vgpu)
/* Stop emulation thread with timeout */
if (ctx->thread) {
ctx->stopping = true;
- kthread_stop(ctx->thread);
- /* Wait for thread to actually stop with timeout (5 seconds) */
- if (!wait_for_completion_timeout(&ctx->thread_stopped, msecs_to_jiffies(5000))) {
- nv_vgpu_warn(vgpu, "GSP emulation thread did not stop in time, forcing cleanup");
+ /* Only call kthread_stop() if the thread is still alive.
+ * If the thread crashed (e.g. fortify_panic), the kernel already
+ * killed it and kthread_stop() would hit a refcount saturation
+ * warning on the dead task_struct. */
+ if (pid_alive(ctx->thread)) {
+ kthread_stop(ctx->thread);
+ /* Wait for thread to actually stop with timeout (5 seconds) */
+ if (!wait_for_completion_timeout(&ctx->thread_stopped, msecs_to_jiffies(5000))) {
+ nv_vgpu_warn(vgpu, "GSP emulation thread did not stop in time, forcing cleanup");
+ }
+ } else {
+ nv_vgpu_warn(vgpu, "GSP emulation thread already dead (crashed), skipping kthread_stop");
}
+ put_task_struct(ctx->thread);
ctx->thread = NULL;
}
ctx->running = false;