From 256c5308423befddc20bdf7e59a663f3f1b683ae Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 21 Sep 2026 18:12:17 -0400 Subject: 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. --- kernel/gsp_emulation.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'kernel') 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; -- cgit v1.2.3