Netdev List
 help / color / mirror / Atom feed
From: Vlad Buslov <vladbu@mellanox.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, jhs@mojatatu.com, xiyou.wangcong@gmail.com,
	jiri@resnulli.us, pablo@netfilter.org, kadlec@blackhole.kfki.hu,
	fw@strlen.de, ast@kernel.org, daniel@iogearbox.net,
	edumazet@google.com, keescook@chromium.org,
	marcelo.leitner@gmail.com, Vlad Buslov <vladbu@mellanox.com>
Subject: [PATCH net-next v2 13/15] net: sched: act_mirred: remove dependency on rtnl lock
Date: Fri, 10 Aug 2018 20:51:53 +0300	[thread overview]
Message-ID: <1533923515-5664-14-git-send-email-vladbu@mellanox.com> (raw)
In-Reply-To: <1533923515-5664-1-git-send-email-vladbu@mellanox.com>

Re-introduce mirred list spinlock, that was removed some time ago, in order
to protect it from concurrent modifications, instead of relying on rtnl
lock.

Use tcf spinlock to protect mirred action private data from concurrent
modification in init and dump. Rearrange access to mirred data in order to
be performed only while holding the lock.

Rearrange net dev access to always hold reference while working with it,
instead of relying on rntl lock.

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
---
 net/sched/act_mirred.c | 78 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 51 insertions(+), 27 deletions(-)

diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 7a045cc7fe3b..327be257033d 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -30,6 +30,7 @@
 #include <net/tc_act/tc_mirred.h>
 
 static LIST_HEAD(mirred_list);
+static DEFINE_SPINLOCK(mirred_list_lock);
 
 static bool tcf_mirred_is_act_redirect(int action)
 {
@@ -62,13 +63,23 @@ static bool tcf_mirred_can_reinsert(int action)
 	return false;
 }
 
+static struct net_device *tcf_mirred_dev_dereference(struct tcf_mirred *m)
+{
+	return rcu_dereference_protected(m->tcfm_dev,
+					 lockdep_is_held(&m->tcf_lock));
+}
+
 static void tcf_mirred_release(struct tc_action *a)
 {
 	struct tcf_mirred *m = to_mirred(a);
 	struct net_device *dev;
 
+	spin_lock(&mirred_list_lock);
 	list_del(&m->tcfm_list);
-	dev = rtnl_dereference(m->tcfm_dev);
+	spin_unlock(&mirred_list_lock);
+
+	/* last reference to action, no need to lock */
+	dev = rcu_dereference_protected(m->tcfm_dev, 1);
 	if (dev)
 		dev_put(dev);
 }
@@ -128,22 +139,9 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 		NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
 		return -EINVAL;
 	}
-	if (parm->ifindex) {
-		dev = __dev_get_by_index(net, parm->ifindex);
-		if (dev == NULL) {
-			if (exists)
-				tcf_idr_release(*a, bind);
-			else
-				tcf_idr_cleanup(tn, parm->index);
-			return -ENODEV;
-		}
-		mac_header_xmit = dev_is_mac_header_xmit(dev);
-	} else {
-		dev = NULL;
-	}
 
 	if (!exists) {
-		if (!dev) {
+		if (!parm->ifindex) {
 			tcf_idr_cleanup(tn, parm->index);
 			NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
 			return -EINVAL;
@@ -161,19 +159,31 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 	}
 	m = to_mirred(*a);
 
-	ASSERT_RTNL();
+	spin_lock(&m->tcf_lock);
 	m->tcf_action = parm->action;
 	m->tcfm_eaction = parm->eaction;
-	if (dev != NULL) {
-		if (ret != ACT_P_CREATED)
-			dev_put(rcu_dereference_protected(m->tcfm_dev, 1));
-		dev_hold(dev);
-		rcu_assign_pointer(m->tcfm_dev, dev);
+
+	if (parm->ifindex) {
+		dev = dev_get_by_index(net, parm->ifindex);
+		if (!dev) {
+			spin_unlock(&m->tcf_lock);
+			tcf_idr_release(*a, bind);
+			return -ENODEV;
+		}
+		mac_header_xmit = dev_is_mac_header_xmit(dev);
+		rcu_swap_protected(m->tcfm_dev, dev,
+				   lockdep_is_held(&m->tcf_lock));
+		if (dev)
+			dev_put(dev);
 		m->tcfm_mac_header_xmit = mac_header_xmit;
 	}
+	spin_unlock(&m->tcf_lock);
 
 	if (ret == ACT_P_CREATED) {
+		spin_lock(&mirred_list_lock);
 		list_add(&m->tcfm_list, &mirred_list);
+		spin_unlock(&mirred_list_lock);
+
 		tcf_idr_insert(tn, *a);
 	}
 
@@ -287,26 +297,33 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind,
 {
 	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_mirred *m = to_mirred(a);
-	struct net_device *dev = rtnl_dereference(m->tcfm_dev);
 	struct tc_mirred opt = {
 		.index   = m->tcf_index,
-		.action  = m->tcf_action,
 		.refcnt  = refcount_read(&m->tcf_refcnt) - ref,
 		.bindcnt = atomic_read(&m->tcf_bindcnt) - bind,
-		.eaction = m->tcfm_eaction,
-		.ifindex = dev ? dev->ifindex : 0,
 	};
+	struct net_device *dev;
 	struct tcf_t t;
 
+	spin_lock(&m->tcf_lock);
+	opt.action = m->tcf_action;
+	opt.eaction = m->tcfm_eaction;
+	dev = tcf_mirred_dev_dereference(m);
+	if (dev)
+		opt.ifindex = dev->ifindex;
+
 	if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
 		goto nla_put_failure;
 
 	tcf_tm_dump(&t, &m->tcf_tm);
 	if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD))
 		goto nla_put_failure;
+	spin_unlock(&m->tcf_lock);
+
 	return skb->len;
 
 nla_put_failure:
+	spin_unlock(&m->tcf_lock);
 	nlmsg_trim(skb, b);
 	return -1;
 }
@@ -337,15 +354,19 @@ static int mirred_device_event(struct notifier_block *unused,
 
 	ASSERT_RTNL();
 	if (event == NETDEV_UNREGISTER) {
+		spin_lock(&mirred_list_lock);
 		list_for_each_entry(m, &mirred_list, tcfm_list) {
-			if (rcu_access_pointer(m->tcfm_dev) == dev) {
+			spin_lock(&m->tcf_lock);
+			if (tcf_mirred_dev_dereference(m) == dev) {
 				dev_put(dev);
 				/* Note : no rcu grace period necessary, as
 				 * net_device are already rcu protected.
 				 */
 				RCU_INIT_POINTER(m->tcfm_dev, NULL);
 			}
+			spin_unlock(&m->tcf_lock);
 		}
+		spin_unlock(&mirred_list_lock);
 	}
 
 	return NOTIFY_DONE;
@@ -358,10 +379,13 @@ static struct notifier_block mirred_device_notifier = {
 static struct net_device *tcf_mirred_get_dev(const struct tc_action *a)
 {
 	struct tcf_mirred *m = to_mirred(a);
-	struct net_device *dev = rtnl_dereference(m->tcfm_dev);
+	struct net_device *dev;
 
+	rcu_read_lock();
+	dev = rcu_dereference(m->tcfm_dev);
 	if (dev)
 		dev_hold(dev);
+	rcu_read_unlock();
 
 	return dev;
 }
-- 
2.7.5

  parent reply	other threads:[~2018-08-10 20:23 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-10 17:51 [PATCH net-next v2 00/15] Remove rtnl lock dependency from all action implementations Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 01/15] net: sched: act_bpf: remove dependency on rtnl lock Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 02/15] net: sched: act_csum: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 03/15] net: sched: act_gact: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 04/15] net: sched: act_ife: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 05/15] net: sched: act_ipt: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 06/15] net: sched: act_pedit: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 07/15] net: sched: act_sample: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 08/15] net: sched: act_simple: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 09/15] net: sched: act_skbmod: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 10/15] net: sched: act_tunnel_key: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 11/15] net: sched: act_vlan: " Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 12/15] net: sched: extend action ops with put_dev callback Vlad Buslov
2018-08-10 17:51 ` Vlad Buslov [this message]
2018-08-10 17:51 ` [PATCH net-next v2 14/15] net: core: protect rate estimator statistics pointer with lock Vlad Buslov
2018-08-10 17:51 ` [PATCH net-next v2 15/15] net: sched: act_police: remove dependency on rtnl lock Vlad Buslov
2018-08-11 19:38 ` [PATCH net-next v2 00/15] Remove rtnl lock dependency from all action implementations David Miller

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=1533923515-5664-14-git-send-email-vladbu@mellanox.com \
    --to=vladbu@mellanox.com \
    --cc=ast@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=jhs@mojatatu.com \
    --cc=jiri@resnulli.us \
    --cc=kadlec@blackhole.kfki.hu \
    --cc=keescook@chromium.org \
    --cc=marcelo.leitner@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pablo@netfilter.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox