Browse Source

Merge branch 'net-sched-cleanups'

Jiri Pirko says:

====================
net: sched: couple of adjustments/fixes
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
David S. Miller 7 years ago
parent
commit
cef238d71d
2 changed files with 62 additions and 54 deletions
  1. 0 3
      include/net/pkt_cls.h
  2. 62 51
      net/sched/cls_api.c

+ 0 - 3
include/net/pkt_cls.h

@@ -40,11 +40,8 @@ struct tcf_block_cb;
 bool tcf_queue_work(struct rcu_work *rwork, work_func_t func);
 
 #ifdef CONFIG_NET_CLS
-struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
-				bool create);
 struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block,
 				       u32 chain_index);
-void tcf_chain_put(struct tcf_chain *chain);
 void tcf_chain_put_by_act(struct tcf_chain *chain);
 void tcf_block_netif_keep_dst(struct tcf_block *block);
 int tcf_block_get(struct tcf_block **p_block,

+ 62 - 51
net/sched/cls_api.c

@@ -232,19 +232,6 @@ static void tcf_chain0_head_change(struct tcf_chain *chain,
 		tcf_chain_head_change_item(item, tp_head);
 }
 
-static void tcf_chain_flush(struct tcf_chain *chain)
-{
-	struct tcf_proto *tp = rtnl_dereference(chain->filter_chain);
-
-	tcf_chain0_head_change(chain, NULL);
-	while (tp) {
-		RCU_INIT_POINTER(chain->filter_chain, tp->next);
-		tcf_proto_destroy(tp, NULL);
-		tp = rtnl_dereference(chain->filter_chain);
-		tcf_chain_put(chain);
-	}
-}
-
 static void tcf_chain_destroy(struct tcf_chain *chain)
 {
 	struct tcf_block *block = chain->block;
@@ -262,21 +249,10 @@ static void tcf_chain_hold(struct tcf_chain *chain)
 	++chain->refcnt;
 }
 
-static void tcf_chain_hold_by_act(struct tcf_chain *chain)
-{
-	++chain->action_refcnt;
-}
-
-static void tcf_chain_release_by_act(struct tcf_chain *chain)
-{
-	--chain->action_refcnt;
-}
-
-static bool tcf_chain_is_zombie(struct tcf_chain *chain)
+static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain)
 {
 	/* In case all the references are action references, this
-	 * chain is a zombie and should not be listed in the chain
-	 * dump list.
+	 * chain should not be shown to the user.
 	 */
 	return chain->refcnt == chain->action_refcnt;
 }
@@ -296,52 +272,75 @@ static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
 static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
 			   u32 seq, u16 flags, int event, bool unicast);
 
-struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
-				bool create)
+static struct tcf_chain *__tcf_chain_get(struct tcf_block *block,
+					 u32 chain_index, bool create,
+					 bool by_act)
 {
 	struct tcf_chain *chain = tcf_chain_lookup(block, chain_index);
 
 	if (chain) {
 		tcf_chain_hold(chain);
-		return chain;
+	} else {
+		if (!create)
+			return NULL;
+		chain = tcf_chain_create(block, chain_index);
+		if (!chain)
+			return NULL;
 	}
 
-	if (!create)
-		return NULL;
-	chain = tcf_chain_create(block, chain_index);
-	if (!chain)
-		return NULL;
-	tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
-			RTM_NEWCHAIN, false);
+	if (by_act)
+		++chain->action_refcnt;
+
+	/* Send notification only in case we got the first
+	 * non-action reference. Until then, the chain acts only as
+	 * a placeholder for actions pointing to it and user ought
+	 * not know about them.
+	 */
+	if (chain->refcnt - chain->action_refcnt == 1 && !by_act)
+		tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
+				RTM_NEWCHAIN, false);
+
 	return chain;
 }
-EXPORT_SYMBOL(tcf_chain_get);
 
-struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
+static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
+				       bool create)
 {
-	struct tcf_chain *chain = tcf_chain_get(block, chain_index, true);
+	return __tcf_chain_get(block, chain_index, create, false);
+}
 
-	tcf_chain_hold_by_act(chain);
-	return chain;
+struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
+{
+	return __tcf_chain_get(block, chain_index, true, true);
 }
 EXPORT_SYMBOL(tcf_chain_get_by_act);
 
 static void tc_chain_tmplt_del(struct tcf_chain *chain);
 
-void tcf_chain_put(struct tcf_chain *chain)
+static void __tcf_chain_put(struct tcf_chain *chain, bool by_act)
 {
-	if (--chain->refcnt == 0) {
+	if (by_act)
+		chain->action_refcnt--;
+	chain->refcnt--;
+
+	/* The last dropped non-action reference will trigger notification. */
+	if (chain->refcnt - chain->action_refcnt == 0 && !by_act)
 		tc_chain_notify(chain, NULL, 0, 0, RTM_DELCHAIN, false);
+
+	if (chain->refcnt == 0) {
 		tc_chain_tmplt_del(chain);
 		tcf_chain_destroy(chain);
 	}
 }
-EXPORT_SYMBOL(tcf_chain_put);
+
+static void tcf_chain_put(struct tcf_chain *chain)
+{
+	__tcf_chain_put(chain, false);
+}
 
 void tcf_chain_put_by_act(struct tcf_chain *chain)
 {
-	tcf_chain_release_by_act(chain);
-	tcf_chain_put(chain);
+	__tcf_chain_put(chain, true);
 }
 EXPORT_SYMBOL(tcf_chain_put_by_act);
 
@@ -351,6 +350,19 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
 		tcf_chain_put(chain);
 }
 
+static void tcf_chain_flush(struct tcf_chain *chain)
+{
+	struct tcf_proto *tp = rtnl_dereference(chain->filter_chain);
+
+	tcf_chain0_head_change(chain, NULL);
+	while (tp) {
+		RCU_INIT_POINTER(chain->filter_chain, tp->next);
+		tcf_proto_destroy(tp, NULL);
+		tp = rtnl_dereference(chain->filter_chain);
+		tcf_chain_put(chain);
+	}
+}
+
 static bool tcf_block_offload_in_use(struct tcf_block *block)
 {
 	return block->offloadcnt;
@@ -1838,10 +1850,9 @@ replay:
 	chain = tcf_chain_lookup(block, chain_index);
 	if (n->nlmsg_type == RTM_NEWCHAIN) {
 		if (chain) {
-			if (tcf_chain_is_zombie(chain)) {
+			if (tcf_chain_held_by_acts_only(chain)) {
 				/* The chain exists only because there is
-				 * some action referencing it, meaning it
-				 * is a zombie.
+				 * some action referencing it.
 				 */
 				tcf_chain_hold(chain);
 			} else {
@@ -1860,7 +1871,7 @@ replay:
 			}
 		}
 	} else {
-		if (!chain || tcf_chain_is_zombie(chain)) {
+		if (!chain || tcf_chain_held_by_acts_only(chain)) {
 			NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
 			return -EINVAL;
 		}
@@ -1988,7 +1999,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
 			index++;
 			continue;
 		}
-		if (tcf_chain_is_zombie(chain))
+		if (tcf_chain_held_by_acts_only(chain))
 			continue;
 		err = tc_chain_fill_node(chain, net, skb, block,
 					 NETLINK_CB(cb->skb).portid,