When there are no references to struct net left, that is check_net(net) is false, we don't need to synchronize updates to flow_dissector prog with BPF prog attach/detach callbacks. That allows us to pull locking up from the shared detach routine and into the bpf prog detach callback. Signed-off-by: Jakub Sitnicki <jakub@xxxxxxxxxxxxxx> --- net/core/flow_dissector.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 5dceed467f64..73cc085dc2b7 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -164,22 +164,26 @@ static int flow_dissector_bpf_prog_detach(struct net *net) { struct bpf_prog *attached; - mutex_lock(&flow_dissector_mutex); + /* No need for update-side lock when net is going away. */ attached = rcu_dereference_protected(net->flow_dissector_prog, + !check_net(net) || lockdep_is_held(&flow_dissector_mutex)); - if (!attached) { - mutex_unlock(&flow_dissector_mutex); + if (!attached) return -ENOENT; - } RCU_INIT_POINTER(net->flow_dissector_prog, NULL); bpf_prog_put(attached); - mutex_unlock(&flow_dissector_mutex); return 0; } int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr) { - return flow_dissector_bpf_prog_detach(current->nsproxy->net_ns); + int ret; + + mutex_lock(&flow_dissector_mutex); + ret = flow_dissector_bpf_prog_detach(current->nsproxy->net_ns); + mutex_unlock(&flow_dissector_mutex); + + return ret; } static void __net_exit flow_dissector_pernet_pre_exit(struct net *net) -- 2.25.4