channel_remove() calls fsm_deltimer() which internally uses timer_delete(), then immediately frees the channel structure: fsm_deltimer(&ch->timer); kfree_fsm(ch->fsm); /* freed while callback may still run */ kfree(ch); timer_delete() returns immediately even if the timer callback is currently executing on another CPU, creating a window where fsm_expire_timer() accesses this->fi (which points to ch->fsm) after it has been freed by kfree_fsm(). Fix this by calling timer_delete_sync() directly on the underlying timer_list fields before freeing, instead of going through fsm_deltimer(). timer_delete_sync() is used rather than timer_shutdown_sync() because the channel is fully torn down by channel_remove() and the timer is never re-armed after this point, making the re-arm prevention of timer_shutdown_sync() unnecessary. This cannot be fixed in fsm_deltimer() itself because FSM action functions triggered by CTC_EVENT_TIMER call fsm_deltimer() from within the timer callback chain, which would cause a self-deadlock in timer_delete_sync(). Reported-by: Sashiko Link: https://sashiko.dev/#/patchset/20260803182736.2356374-1-nagamani@linux.ibm.com?part=1 Reviewed-by: Aswin Karuvally Tested-by: Aswin Karuvally Signed-off-by: Nagamani PV --- drivers/s390/net/ctcm_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 8b0d76a47d9f..63f8832f9b14 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -211,9 +211,9 @@ static void channel_remove(struct channel *ch) while (*c) { if (*c == ch) { *c = ch->next; - fsm_deltimer(&ch->timer); + timer_delete_sync(&ch->timer.tl); if (IS_MPC(ch)) - fsm_deltimer(&ch->sweep_timer); + timer_delete_sync(&ch->sweep_timer.tl); kfree_fsm(ch->fsm); clear_normalized_cda(&ch->ccw[4]); -- 2.53.0