All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli.us>
To: Vlad Buslov <vladbu@mellanox.com>
Cc: netdev@vger.kernel.org, davem@davemloft.net, jhs@mojatatu.com,
	xiyou.wangcong@gmail.com, pablo@netfilter.org,
	kadlec@blackhole.kfki.hu, fw@strlen.de, ast@kernel.org,
	daniel@iogearbox.net, edumazet@google.com, keescook@chromium.org,
	linux-kernel@vger.kernel.org, netfilter-devel@vger.kernel.org,
	coreteam@netfilter.org, kliteyn@mellanox.com
Subject: Re: [PATCH 12/14] net: sched: retry action check-insert on concurrent modification
Date: Wed, 16 May 2018 16:13:19 +0200	[thread overview]
Message-ID: <20180516141319.GO1972@nanopsycho> (raw)
In-Reply-To: <vbfvabn1zic.fsf@reg-r-vrt-018-180.mtr.labs.mlnx>

Wed, May 16, 2018 at 03:52:20PM CEST, vladbu@mellanox.com wrote:
>
>On Wed 16 May 2018 at 13:21, Jiri Pirko <jiri@resnulli.us> wrote:
>> Wed, May 16, 2018 at 02:43:58PM CEST, vladbu@mellanox.com wrote:
>>>
>>>On Wed 16 May 2018 at 12:26, Jiri Pirko <jiri@resnulli.us> wrote:
>>>> Wed, May 16, 2018 at 01:55:06PM CEST, vladbu@mellanox.com wrote:
>>>>>
>>>>>On Wed 16 May 2018 at 09:59, Jiri Pirko <jiri@resnulli.us> wrote:
>>>>>> Mon, May 14, 2018 at 04:27:13PM CEST, vladbu@mellanox.com wrote:
>>>>>>>Retry check-insert sequence in action init functions if action with same
>>>>>>>index was inserted concurrently.
>>>>>>>
>>>>>>>Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
>>>>>>>---
>>>>>>> net/sched/act_bpf.c        | 8 +++++++-
>>>>>>> net/sched/act_connmark.c   | 8 +++++++-
>>>>>>> net/sched/act_csum.c       | 8 +++++++-
>>>>>>> net/sched/act_gact.c       | 8 +++++++-
>>>>>>> net/sched/act_ife.c        | 8 +++++++-
>>>>>>> net/sched/act_ipt.c        | 8 +++++++-
>>>>>>> net/sched/act_mirred.c     | 8 +++++++-
>>>>>>> net/sched/act_nat.c        | 8 +++++++-
>>>>>>> net/sched/act_pedit.c      | 8 +++++++-
>>>>>>> net/sched/act_police.c     | 9 ++++++++-
>>>>>>> net/sched/act_sample.c     | 8 +++++++-
>>>>>>> net/sched/act_simple.c     | 9 ++++++++-
>>>>>>> net/sched/act_skbedit.c    | 8 +++++++-
>>>>>>> net/sched/act_skbmod.c     | 8 +++++++-
>>>>>>> net/sched/act_tunnel_key.c | 9 ++++++++-
>>>>>>> net/sched/act_vlan.c       | 9 ++++++++-
>>>>>>> 16 files changed, 116 insertions(+), 16 deletions(-)
>>>>>>>
>>>>>>>diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
>>>>>>>index 5554bf7..7e20fdc 100644
>>>>>>>--- a/net/sched/act_bpf.c
>>>>>>>+++ b/net/sched/act_bpf.c
>>>>>>>@@ -299,10 +299,16 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
>>>>>>> 
>>>>>>> 	parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
>>>>>>> 
>>>>>>>+replay:
>>>>>>> 	if (!tcf_idr_check(tn, parm->index, act, bind)) {
>>>>>>> 		ret = tcf_idr_create(tn, parm->index, est, act,
>>>>>>> 				     &act_bpf_ops, bind, true);
>>>>>>>-		if (ret < 0)
>>>>>>>+		/* Action with specified index was created concurrently.
>>>>>>>+		 * Check again.
>>>>>>>+		 */
>>>>>>>+		if (parm->index && ret == -ENOSPC)
>>>>>>>+			goto replay;
>>>>>>>+		else if (ret)
>>>>>>
>>>>>> Hmm, looks like you are doing the same/very similar thing in every act
>>>>>> code. I think it would make sense to introduce a helper function for
>>>>>> this purpose.
>>>>>
>>>>>This code uses goto so it can't be easily refactored into standalone
>>>>>function. Could you specify which part of this code you suggest to
>>>>>extract?
>>>>
>>>> Hmm, looking at the code, I think that what would help is to have a
>>>> helper that would atomically check if index exists and if not, it would
>>>> allocate one. Something like:
>>>>
>>>>
>>>> int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
>>>> 			struct tc_action **a, int bind)
>>>> {
>>>> 	struct tcf_idrinfo *idrinfo = tn->idrinfo;
>>>> 	struct tc_action *p;
>>>> 	int err;
>>>>
>>>> 	spin_lock(&idrinfo->lock);
>>>> 	if (*index) {
>>>> 		p = idr_find(&idrinfo->action_idr, *index);
>>>> 		if (p) {
>>>> 			if (bind)
>>>> 	   			p->tcfa_bindcnt++;
>>>> 			p->tcfa_refcnt++;
>>>> 			*a = p;
>>>> 			err = 0;
>>>> 		} else {
>>>> 			*a = NULL;
>>>> 			err = idr_alloc_u32(idr, NULL, index,
>>>> 					    *index, GFP_ATOMIC);
>>>> 		}
>>>> 	} else {
>>>> 		*index = 1;
>>>> 		*a = NULL;
>>>> 		err = idr_alloc_u32(idr, NULL, index, UINT_MAX, GFP_ATOMIC);
>>>> 	}
>>>> 	spin_unlock(&idrinfo->lock);
>>>> 	return err;
>>>> }
>>>>
>>>> The act code would just check if "a" is NULL and if so, it would call
>>>> tcf_idr_create() with allocated index as arg.
>>>
>>>What about multiple actions that have arbitrary code between initial
>>>check and idr allocation that is currently inside tcf_idr_create()?
>>
>> Why it would be a problem to have them after the allocation?
>
>Lets look at mirred for exmple:
>	exists = tcf_idr_check(tn, parm->index, a, bind);
>	if (exists && bind)
>		return 0;
>
>	switch (parm->eaction) {
>	case TCA_EGRESS_MIRROR:
>	case TCA_EGRESS_REDIR:
>	case TCA_INGRESS_REDIR:
>	case TCA_INGRESS_MIRROR:
>		break;
>	default:
>		if (exists)
>			tcf_idr_release(*a, bind);
>		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);
>			return -ENODEV;
>		}
>		mac_header_xmit = dev_is_mac_header_xmit(dev);
>	} else {
>		dev = NULL;
>	}
>
>	if (!exists) {
>		if (!dev) {
>			NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
>			return -EINVAL;
>		}
>		ret = tcf_idr_create(tn, parm->index, est, a,
>				     &act_mirred_ops, bind, true);
>		/* Action with specified index was created concurrently.
>		 * Check again.
>		 */
>		if (parm->index && ret == -ENOSPC)
>			goto replay;
>		else if (ret)
>			return ret;
>
>There are several returns and cleanup is only performed when action
>exists. So all code like that will have to be audited to also remove
>index from idr, otherwise idr handles leak on return.

Yeah. You have to take care of the error path.


>
>>
>> There is one issue though with my draft. tcf_idr_insert() function
>> which actually assigns a "p" pointer to the idr index is called later on.
>> Until that happens, the idr_find() would return NULL even if the index
>> is actually allocated. We cannot assign "p" in tcf_idr_check_alloc()
>> because it is allocated only later on in tcf_idr_create(). But that is
>> resolvable by the following trick:
>>
>> int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
>> 			struct tc_action **a, int bind)
>> {
>> 	struct tcf_idrinfo *idrinfo = tn->idrinfo;
>> 	struct tc_action *p;
>> 	int err;
>>
>> again:
>> 	spin_lock(&idrinfo->lock);
>> 	if (*index) {
>>  		p = idr_find(&idrinfo->action_idr, *index);
>> 		if (IS_ERR(p)) {
>> 			/* This means that another process allocated
>> 			 * index but did not assign the pointer yet.
>> 			 */
>> 			spin_unlock(&idrinfo->lock);
>> 			goto again;
>> 		}
>>  		if (p) {
>>  			if (bind)
>>  	   			p->tcfa_bindcnt++;
>>  			p->tcfa_refcnt++;
>>  			*a = p;
>>  			err = 0;
>>  		} else {
>>  			*a = NULL;
>>  			err = idr_alloc_u32(idr, NULL, index,
>>  					    *index, GFP_ATOMIC);
>> 			idr_replace(&idrinfo->action_idr,
>> 				    ERR_PTR(-EBUSY), *index);
>>  		}
>>  	} else {
>>  		*index = 1;
>> 		*a = NULL;
>>  		err = idr_alloc_u32(idr, NULL, index, UINT_MAX, GFP_ATOMIC);
>> 		idr_replace(&idrinfo->action_idr, ERR_PTR(-EBUSY), *index);
>>  	}
>>  	spin_unlock(&idrinfo->lock);
>>  	return err;
>> }
>>
>
>So users of action idr that might perform concurrent lookups are also
>have to be changed to check for error pointers, that now can be inserted
>into idr? Seems like a complex change...

You can just add a simple check into tcf_idr_lookup(). Where else?


>
>>
>>
>>
>>
>>>
>>>>
>>>>
>>>>>
>>>>>>
>>>>>> [...]
>>>>>
>>>
>

  reply	other threads:[~2018-05-16 14:13 UTC|newest]

Thread overview: 103+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-14 14:27 [PATCH 00/14] Modify action API for implementing lockless actions Vlad Buslov
2018-05-14 14:27 ` [PATCH 01/14] net: sched: use rcu for action cookie update Vlad Buslov
2018-05-14 15:10   ` Jiri Pirko
2018-05-14 23:39   ` kbuild test robot
2018-05-14 14:27 ` [PATCH 02/14] net: sched: change type of reference and bind counters Vlad Buslov
2018-05-14 15:11   ` Jiri Pirko
2018-05-19 21:04   ` Marcelo Ricardo Leitner
2018-05-20 10:55     ` Vlad Buslov
2018-05-14 14:27 ` [PATCH 03/14] net: sched: add 'delete' function to action ops Vlad Buslov
2018-05-14 15:12   ` Jiri Pirko
2018-05-14 16:30     ` Jiri Pirko
2018-05-14 14:27 ` [PATCH 04/14] net: sched: implement unlocked action init API Vlad Buslov
2018-05-14 15:16   ` Jiri Pirko
2018-05-19 21:11     ` Marcelo Ricardo Leitner
2018-05-14 14:27 ` [PATCH 05/14] net: sched: always take reference to action Vlad Buslov
2018-05-14 16:23   ` Jiri Pirko
2018-05-14 18:49     ` Vlad Buslov
2018-05-15  8:58       ` Jiri Pirko
2018-05-15 11:52         ` Vlad Buslov
2018-05-15  1:38   ` kbuild test robot
2018-05-15  1:38   ` [RFC PATCH] net: sched: __tcf_idr_check() can be static kbuild test robot
2018-05-14 14:27 ` [PATCH 06/14] net: sched: implement reference counted action release Vlad Buslov
2018-05-14 16:28   ` Jiri Pirko
2018-05-14 16:47   ` Jiri Pirko
2018-05-14 19:07     ` Vlad Buslov
2018-05-15  9:03       ` Jiri Pirko
2018-05-15  9:16         ` Vlad Buslov
2018-05-19 21:43   ` Marcelo Ricardo Leitner
2018-05-20  6:22     ` Jiri Pirko
2018-05-20 10:59       ` Vlad Buslov
2018-05-14 14:27 ` [PATCH 07/14] net: sched: use reference counting action init Vlad Buslov
2018-05-15 11:24   ` Jiri Pirko
2018-05-15 11:32     ` Vlad Buslov
2018-05-15 11:39       ` Jiri Pirko
2018-05-15 11:41         ` Vlad Buslov
2018-05-15 11:57           ` Jiri Pirko
2018-05-15 12:00             ` Vlad Buslov
2018-05-14 14:27 ` [PATCH 08/14] net: sched: account for temporary action reference Vlad Buslov
2018-05-16  7:12   ` Jiri Pirko
2018-05-14 14:27 ` [PATCH 09/14] net: sched: don't release reference on action overwrite Vlad Buslov
2018-05-16  7:43   ` Jiri Pirko
2018-05-16  7:47     ` Vlad Buslov
2018-05-16  7:50       ` Jiri Pirko
2018-05-19 21:52   ` Marcelo Ricardo Leitner
2018-05-20 18:42     ` Vlad Buslov
2018-05-14 14:27 ` [PATCH 10/14] net: sched: extend act API for lockless actions Vlad Buslov
2018-05-16  7:50   ` Jiri Pirko
2018-05-16  8:16     ` Vlad Buslov
2018-05-16  8:56       ` Jiri Pirko
2018-05-16  9:39         ` Vlad Buslov
2018-05-19 22:17   ` Marcelo Ricardo Leitner
2018-05-14 14:27 ` [PATCH 11/14] net: core: add new/replace rate estimator lock parameter Vlad Buslov
2018-05-16  9:54   ` Jiri Pirko
2018-05-16 10:00     ` Vlad Buslov
2018-05-16 10:11       ` Jiri Pirko
2018-05-14 14:27 ` [PATCH 12/14] net: sched: retry action check-insert on concurrent modification Vlad Buslov
2018-05-16  9:59   ` Jiri Pirko
2018-05-16 11:55     ` Vlad Buslov
2018-05-16 12:26       ` Jiri Pirko
2018-05-16 12:43         ` Vlad Buslov
2018-05-16 13:21           ` Jiri Pirko
2018-05-16 13:52             ` Vlad Buslov
2018-05-16 14:13               ` Jiri Pirko [this message]
2018-05-16 14:26                 ` Vlad Buslov
2018-05-16 14:55                   ` Jiri Pirko
2018-05-19 22:35             ` Marcelo Ricardo Leitner
2018-05-14 14:27 ` [PATCH 13/14] net: sched: use unique idr insert function in unlocked actions Vlad Buslov
2018-05-16  9:50   ` Jiri Pirko
2018-05-16  9:54     ` Vlad Buslov
2018-05-19 22:20   ` Marcelo Ricardo Leitner
2018-05-20 21:13     ` Or Gerlitz
2018-05-20 21:33       ` Marcelo Ricardo Leitner
2018-05-20 21:40         ` Or Gerlitz
2018-05-20 22:43           ` Marcelo Ricardo Leitner
2018-05-14 14:27 ` [PATCH 14/14] net: sched: implement delete for all actions Vlad Buslov
2018-05-16  9:48   ` Jiri Pirko
2018-05-16  9:58     ` Vlad Buslov
2018-05-19 22:45       ` Marcelo Ricardo Leitner
2018-05-14 18:03 ` [PATCH 00/14] Modify action API for implementing lockless actions Jamal Hadi Salim
2018-05-14 20:46   ` Vlad Buslov
2018-05-15 18:25     ` Jamal Hadi Salim
2018-05-15 21:21       ` Vlad Buslov
2018-05-15 21:49         ` Jamal Hadi Salim
2018-05-15 22:03           ` Lucas Bates
2018-05-15 22:07             ` Lucas Bates
2018-05-16  7:13               ` Vlad Buslov
2018-05-16  6:43           ` Vlad Buslov
2018-05-16 14:38             ` Roman Mashak
2018-05-16 15:02               ` Jamal Hadi Salim
2018-05-16 15:53                 ` Vlad Buslov
2018-05-16 15:33               ` Vlad Buslov
2018-05-16 17:36                 ` Roman Mashak
2018-05-16 18:10                   ` Davide Caratti
2018-05-16 21:29                     ` Vlad Buslov
2018-05-16 21:23                   ` Vlad Buslov
2018-05-16 21:51                     ` Jiri Pirko
2018-05-17 13:35                       ` Vlad Buslov
2018-05-18 12:33                         ` Jamal Hadi Salim
2018-05-18 16:37                           ` Vlad Buslov
2018-05-15  8:20   ` Jiri Pirko
2018-05-24 23:34 ` Cong Wang
2018-05-25 20:39   ` Vlad Buslov
2018-05-25 21:40     ` Cong Wang

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=20180516141319.GO1972@nanopsycho \
    --to=jiri@resnulli.us \
    --cc=ast@kernel.org \
    --cc=coreteam@netfilter.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=jhs@mojatatu.com \
    --cc=kadlec@blackhole.kfki.hu \
    --cc=keescook@chromium.org \
    --cc=kliteyn@mellanox.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    --cc=vladbu@mellanox.com \
    --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.