History

net_sched: introduce tcf_exts_get_net() and tcf_exts_put_net()

Instead of holding netns refcnt in tc actions, we can minimize the holding time by saving it in struct tcf_exts instead. This means we can just hold netns refcnt right before call_rcu() and release it after tcf_exts_destroy() is done. However, because on netns cleanup path we call tcf_proto_destroy() too, obviously we can not hold netns for a zero refcnt, in this case we have to do cleanup synchronously. It is fine for RCU too, the caller cleanup_net() already waits for a grace period. For other cases, refcnt is non-zero and we can safely grab it as normal and release it after we are done. This patch provides two new API for each filter to use: tcf_exts_get_net() and tcf_exts_put_net(). And all filters now can use the following pattern: void __destroy_filter() { tcf_exts_destroy(); tcf_exts_put_net(); // <== release netns refcnt kfree(); } void some_work() { rtnl_lock(); __destroy_filter(); rtnl_unlock(); } void some_rcu_callback() { tcf_queue_work(some_work); } if (tcf_exts_get_net()) // <== hold netns refcnt call_rcu(some_rcu_callback); else __destroy_filter();

Cong Wang committed 9 years ago

Commit e4b95c41 parent c7e460c2 files · +25 −0Browse files

Showing the changes to include (1 of 2 files). Show all

Unified · Split

include/net/pkt_cls.h+24−0
@@ -94,6 +94,7 @@ struct tcf_exts { · 93 unmodified lines
9494 __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
9595 int nr_actions;
9696 struct tc_action **actions;
97+ struct net *net;
9798 #endif
9899 /* Map to export classifier specific extension TLV types to the
99100 * generic extensions API. Unsupported extensions must be set to 0.
@@ -107,6 +108,7 @@ static inline int tcf_exts_init(struct tcf_exts *exts, int action, int police) · 7 unmodified lines
107108 #ifdef CONFIG_NET_CLS_ACT
108109 exts->type = 0;
109110 exts->nr_actions = 0;
111+ exts->net = NULL;
110112 exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
111113 GFP_KERNEL);
112114 if (!exts->actions)
@@ -117,6 +119,28 @@ static inline int tcf_exts_init(struct tcf_exts *exts, int action, int police) · 4 unmodified lines
117119 return 0;
118120 }
119121
122+/* Return false if the netns is being destroyed in cleanup_net(). Callers
123+ * need to do cleanup synchronously in this case, otherwise may race with
124+ * tc_action_net_exit(). Return true for other cases.
125+ */
126+static inline bool tcf_exts_get_net(struct tcf_exts *exts)
127+{
128+#ifdef CONFIG_NET_CLS_ACT
129+ exts->net = maybe_get_net(exts->net);
130+ return exts->net != NULL;
131+#else
132+ return true;
133+#endif
134+}
135+
136+static inline void tcf_exts_put_net(struct tcf_exts *exts)
137+{
138+#ifdef CONFIG_NET_CLS_ACT
139+ if (exts->net)
140+ put_net(exts->net);
141+#endif
142+}
143+
120144 static inline void tcf_exts_to_list(const struct tcf_exts *exts,
121145 struct list_head *actions)
122146 {