All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vlad Buslov <vladbu@mellanox.com>
To: netdev@vger.kernel.org
Cc: jhs@mojatatu.com, xiyou.wangcong@gmail.com, jiri@resnulli.us,
	davem@davemloft.net, ast@kernel.org, daniel@iogearbox.net,
	Vlad Buslov <vladbu@mellanox.com>
Subject: [PATCH net-next v3 07/16] net: sched: introduce reference counting for tcf_proto
Date: Mon,  4 Feb 2019 14:32:52 +0200	[thread overview]
Message-ID: <20190204123301.4223-8-vladbu@mellanox.com> (raw)
In-Reply-To: <20190204123301.4223-1-vladbu@mellanox.com>

In order to remove dependency on rtnl lock and allow concurrent tcf_proto
modification, extend tcf_proto with reference counter. Implement helper
get/put functions for tcf proto and use them to modify cls API to always
take reference to tcf_proto while using it. Only release reference to
parent chain after releasing last reference to tp.

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
---

Changes from V2 to V3:
  - Add local tp_next var to tcf_chain_flush() and use it to store
    tp->next pointer dereferenced with rcu_dereference_protected() to
    satisfy kbuild test robot.
  - Reset tp pointer to NULL at the beginning of tc_new_tfilter() to
    prevent its uninitialized usage in error handling code. This code
    was already implemented in patch 10, but must be in patch 8 to
    preserve code bisectability.
  - Put parent chain in tcf_proto_destroy(). In previous version this
    code was implemented in patch 1 which was removed in V3.

 include/net/sch_generic.h |  1 +
 net/sched/cls_api.c       | 53 ++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 85993d7efee6..4372c08fc4d9 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -322,6 +322,7 @@ struct tcf_proto {
 	void			*data;
 	const struct tcf_proto_ops	*ops;
 	struct tcf_chain	*chain;
+	refcount_t		refcnt;
 	struct rcu_head		rcu;
 };
 
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index d3fa1043b7fd..90a59b5966fe 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -172,6 +172,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
 	tp->protocol = protocol;
 	tp->prio = prio;
 	tp->chain = chain;
+	refcount_set(&tp->refcnt, 1);
 
 	err = tp->ops->init(tp);
 	if (err) {
@@ -185,14 +186,29 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
 	return ERR_PTR(err);
 }
 
+static void tcf_proto_get(struct tcf_proto *tp)
+{
+	refcount_inc(&tp->refcnt);
+}
+
+static void tcf_chain_put(struct tcf_chain *chain);
+
 static void tcf_proto_destroy(struct tcf_proto *tp,
 			      struct netlink_ext_ack *extack)
 {
 	tp->ops->destroy(tp, extack);
+	tcf_chain_put(tp->chain);
 	module_put(tp->ops->owner);
 	kfree_rcu(tp, rcu);
 }
 
+static void tcf_proto_put(struct tcf_proto *tp,
+			  struct netlink_ext_ack *extack)
+{
+	if (refcount_dec_and_test(&tp->refcnt))
+		tcf_proto_destroy(tp, extack);
+}
+
 #define ASSERT_BLOCK_LOCKED(block)					\
 	lockdep_assert_held(&(block)->lock)
 
@@ -437,18 +453,18 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
 
 static void tcf_chain_flush(struct tcf_chain *chain)
 {
-	struct tcf_proto *tp;
+	struct tcf_proto *tp, *tp_next;
 
 	mutex_lock(&chain->filter_chain_lock);
 	tp = tcf_chain_dereference(chain->filter_chain, chain);
+	RCU_INIT_POINTER(chain->filter_chain, NULL);
 	tcf_chain0_head_change(chain, NULL);
 	mutex_unlock(&chain->filter_chain_lock);
 
 	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);
+		tp_next = rcu_dereference_protected(tp->next, 1);
+		tcf_proto_put(tp, NULL);
+		tp = tp_next;
 	}
 }
 
@@ -1492,9 +1508,9 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
 {
 	if (*chain_info->pprev == chain->filter_chain)
 		tcf_chain0_head_change(chain, tp);
+	tcf_proto_get(tp);
 	RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain, chain_info));
 	rcu_assign_pointer(*chain_info->pprev, tp);
-	tcf_chain_hold(chain);
 }
 
 static void tcf_chain_tp_remove(struct tcf_chain *chain,
@@ -1506,7 +1522,6 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
 	if (tp == chain->filter_chain)
 		tcf_chain0_head_change(chain, next);
 	RCU_INIT_POINTER(*chain_info->pprev, next);
-	tcf_chain_put(chain);
 }
 
 static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
@@ -1533,7 +1548,12 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
 		}
 	}
 	chain_info->pprev = pprev;
-	chain_info->next = tp ? tp->next : NULL;
+	if (tp) {
+		chain_info->next = tp->next;
+		tcf_proto_get(tp);
+	} else {
+		chain_info->next = NULL;
+	}
 	return tp;
 }
 
@@ -1691,6 +1711,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 	prio = TC_H_MAJ(t->tcm_info);
 	prio_allocate = false;
 	parent = t->tcm_parent;
+	tp = NULL;
 	cl = 0;
 
 	if (prio == 0) {
@@ -1808,6 +1829,12 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 errout:
 	if (chain)
 		tcf_chain_put(chain);
+	if (chain) {
+		if (tp && !IS_ERR(tp))
+			tcf_proto_put(tp, NULL);
+		if (!tp_created)
+			tcf_chain_put(chain);
+	}
 	tcf_block_release(q, block);
 	if (err == -EAGAIN)
 		/* Replay the request. */
@@ -1938,8 +1965,11 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 	}
 
 errout:
-	if (chain)
+	if (chain) {
+		if (tp && !IS_ERR(tp))
+			tcf_proto_put(tp, NULL);
 		tcf_chain_put(chain);
+	}
 	tcf_block_release(q, block);
 	return err;
 
@@ -2030,8 +2060,11 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 	}
 
 errout:
-	if (chain)
+	if (chain) {
+		if (tp && !IS_ERR(tp))
+			tcf_proto_put(tp, NULL);
 		tcf_chain_put(chain);
+	}
 	tcf_block_release(q, block);
 	return err;
 }
-- 
2.13.6


  parent reply	other threads:[~2019-02-04 12:34 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-04 12:32 [PATCH net-next v3 00/16] Refactor classifier API to work with chain/classifiers without rtnl lock Vlad Buslov
2019-02-04 12:32 ` [PATCH net-next v3 01/16] net: sched: protect block state with mutex Vlad Buslov
2019-02-04 15:23   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 02/16] net: sched: refactor tc_ctl_chain() to use block->lock Vlad Buslov
2019-02-04 16:21   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 03/16] net: sched: protect block->chain0 with block->lock Vlad Buslov
2019-02-04 16:30   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 04/16] net: sched: traverse chains in block with tcf_get_next_chain() Vlad Buslov
2019-02-05  9:35   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 05/16] net: sched: protect chain template accesses with block lock Vlad Buslov
2019-02-05  9:42   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 06/16] net: sched: protect filter_chain list with filter_chain_lock mutex Vlad Buslov
2019-02-05 10:04   ` Jiri Pirko
2019-02-04 12:32 ` Vlad Buslov [this message]
2019-02-05 11:22   ` [PATCH net-next v3 07/16] net: sched: introduce reference counting for tcf_proto Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 08/16] net: sched: traverse classifiers in chain with tcf_get_next_proto() Vlad Buslov
2019-02-05 13:07   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 09/16] net: sched: refactor tp insert/delete for concurrent execution Vlad Buslov
2019-02-05 13:08   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 10/16] net: sched: prevent insertion of new classifiers during chain flush Vlad Buslov
2019-02-05 13:08   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 11/16] net: sched: track rtnl lock status when validating extensions Vlad Buslov
2019-02-05 13:09   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 12/16] net: sched: extend proto ops with 'put' callback Vlad Buslov
2019-02-05 13:15   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 13/16] net: sched: extend proto ops to support unlocked classifiers Vlad Buslov
2019-02-05 13:29   ` Jiri Pirko
2019-02-04 12:32 ` [PATCH net-next v3 14/16] net: sched: add flags to Qdisc class ops struct Vlad Buslov
2019-02-05 13:29   ` Jiri Pirko
2019-02-04 12:33 ` [PATCH net-next v3 15/16] net: sched: refactor tcf_block_find() into standalone functions Vlad Buslov
2019-02-05 13:30   ` Jiri Pirko
2019-02-04 12:33 ` [PATCH net-next v3 16/16] net: sched: unlock rules update API Vlad Buslov
2019-02-05 13:31   ` Jiri Pirko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190204123301.4223-8-vladbu@mellanox.com \
    --to=vladbu@mellanox.com \
    --cc=ast@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=jhs@mojatatu.com \
    --cc=jiri@resnulli.us \
    --cc=netdev@vger.kernel.org \
    --cc=xiyou.wangcong@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.