can_can_gw_rcv() is called under RCU protection, so after calling can_rx_unregister, we may call synchronize_rcu in order to wait for any RCU read-side critical sections to finish before removing the kmem_cache entry with the referenced gw job entry. Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx> --- net/can/gw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/can/gw.c b/net/can/gw.c index ba4124805602..d8861e862f15 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -594,10 +594,11 @@ static int cgw_notifier(struct notifier_block *nb, hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { if (gwj->src.dev == dev || gwj->dst.dev == dev) { hlist_del(&gwj->list); cgw_unregister_filter(net, gwj); + synchronize_rcu(); kmem_cache_free(cgw_cache, gwj); } } } @@ -1152,10 +1153,11 @@ static void cgw_remove_all_jobs(struct net *net) ASSERT_RTNL(); hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { hlist_del(&gwj->list); cgw_unregister_filter(net, gwj); + synchronize_rcu(); kmem_cache_free(cgw_cache, gwj); } } static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -1220,10 +1222,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) continue; hlist_del(&gwj->list); cgw_unregister_filter(net, gwj); + synchronize_rcu(); kmem_cache_free(cgw_cache, gwj); err = 0; break; } -- 2.30.2