Message ID | 20220210171331.1458807-1-eric.dumazet@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | dcd54265c8bc14bd023815e36e2d5f9d66ee1fee |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net] drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit | expand |
Hello: This patch was applied to netdev/net.git (master) by David S. Miller <davem@davemloft.net>: On Thu, 10 Feb 2022 09:13:31 -0800 you wrote: > From: Eric Dumazet <edumazet@google.com> > > trace_napi_poll_hit() is reading stat->dev while another thread can write > on it from dropmon_net_event() > > Use READ_ONCE()/WRITE_ONCE() here, RCU rules are properly enforced already, > we only have to take care of load/store tearing. > > [...] Here is the summary with links: - [net] drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit https://git.kernel.org/netdev/net/c/dcd54265c8bc You are awesome, thank you!
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 7b288a121a41a7b3f3e19e275d1da3ce50579b01..d5dc6be2522cbe50e53532a9a85f5bbb58b18f4f 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -283,13 +283,17 @@ static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi, rcu_read_lock(); list_for_each_entry_rcu(new_stat, &hw_stats_list, list) { + struct net_device *dev; + /* * only add a note to our monitor buffer if: * 1) this is the dev we received on * 2) its after the last_rx delta * 3) our rx_dropped count has gone up */ - if ((new_stat->dev == napi->dev) && + /* Paired with WRITE_ONCE() in dropmon_net_event() */ + dev = READ_ONCE(new_stat->dev); + if ((dev == napi->dev) && (time_after(jiffies, new_stat->last_rx + dm_hw_check_delta)) && (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) { trace_drop_common(NULL, NULL); @@ -1576,7 +1580,10 @@ static int dropmon_net_event(struct notifier_block *ev_block, mutex_lock(&net_dm_mutex); list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) { if (new_stat->dev == dev) { - new_stat->dev = NULL; + + /* Paired with READ_ONCE() in trace_napi_poll_hit() */ + WRITE_ONCE(new_stat->dev, NULL); + if (trace_state == TRACE_OFF) { list_del_rcu(&new_stat->list); kfree_rcu(new_stat, rcu);