--- y/net/can/j1939/transport.c +++ x/net/can/j1939/transport.c @@ -280,12 +280,20 @@ static void j1939_session_destroy(struct kfree(session); } +static void j1939_session_destroy_workfn(struct work_struct *work) +{ + struct j1939_session *session = container_of(work, struct j1939_session, + destroy_work); + j1939_session_destroy(session); +} + static void __j1939_session_release(struct kref *kref) { struct j1939_session *session = container_of(kref, struct j1939_session, kref); - j1939_session_destroy(session); + INIT_WORK(&session->destroy_work, j1939_session_destroy_workfn); + queue_work(system_unbound_wq, &session->destroy_work); } void j1939_session_put(struct j1939_session *session) @@ -1117,25 +1125,30 @@ static void __j1939_session_cancel(struc !session->transmission, err, session->skcb.addr.pgn); } - - if (session->sk) - j1939_sk_send_loop_abort(session->sk, session->err); - else - j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); } static void j1939_session_cancel(struct j1939_session *session, enum j1939_xtp_abort err) { + int canceled = 0; + j1939_session_list_lock(session->priv); if (session->state >= J1939_SESSION_ACTIVE && session->state < J1939_SESSION_WAITING_ABORT) { j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS); __j1939_session_cancel(session, err); + canceled = 1; } j1939_session_list_unlock(session->priv); + + if (canceled) { + if (session->sk) + j1939_sk_send_loop_abort(session->sk, session->err); + else + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); + } } static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer) @@ -1237,6 +1250,7 @@ static enum hrtimer_restart j1939_tp_rxt session->err = -ETIME; j1939_session_deactivate(session); } else { + int canceled = 0; j1939_session_list_lock(session->priv); if (session->state >= J1939_SESSION_ACTIVE && session->state < J1939_SESSION_ACTIVE_MAX) { @@ -1247,8 +1261,16 @@ static enum hrtimer_restart j1939_tp_rxt ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS), HRTIMER_MODE_REL_SOFT); __j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT); + canceled = 1; } j1939_session_list_unlock(session->priv); + + if (canceled) { + if (session->sk) + j1939_sk_send_loop_abort(session->sk, session->err); + else + j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT); + } } j1939_session_put(session); --- y/net/can/j1939/j1939-priv.h +++ x/net/can/j1939/j1939-priv.h @@ -286,6 +286,7 @@ struct j1939_session { unsigned int dpo; } pkt; struct hrtimer txtimer, rxtimer; + struct work_struct destroy_work; }; struct j1939_sock {