From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH 2/8] netfilter: ipset: Prepare ipset core for RCU locking instead of rwlock per set
Date: Thu, 18 Dec 2014 19:38:33 +0100 [thread overview]
Message-ID: <20141218183833.GA3552@salvia> (raw)
In-Reply-To: <1418421489-17411-3-git-send-email-kadlec@blackhole.kfki.hu>
Hi Jozsef,
Several comments to this new round.
On Fri, Dec 12, 2014 at 10:58:03PM +0100, Jozsef Kadlecsik wrote:
> @@ -1407,9 +1407,13 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
> bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
>
> do {
> - write_lock_bh(&set->lock);
> + spin_lock_bh(&set->lock);
> ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
> - write_unlock_bh(&set->lock);
> + spin_unlock_bh(&set->lock);
> + if (ret == -EINPROGRESS) {
> + synchronize_rcu_bh();
Let me zoom in to code that is related to this -EINPROGRESS case.
> + ret = 0;
> + }
> retried = true;
> } while (ret == -EAGAIN &&
> set->variant->resize &&
>From list_set_uadd():
...
if (n) {
list_set_replace(set, e, n);
ret = -EINPROGRESS;
This EINPROGRESS is propagated via set->variant->uadt(), which results
in th synchronize_rcu_bh() from the core.
Then, let's have a look at list_set_replace():
>static inline void
>list_set_replace(struct ip_set *set, struct set_elem *e, struct set_elem *old)
>{
> list_replace_rcu(&old->list, &e->list);
> __list_set_del(set, old);
>}
This uses list rcu safe variant, this is good.
>static void
>__list_set_del(struct ip_set *set, struct set_elem *e)
> {
[...]
> kfree_rcu(e, rcu);
>}
You use kfree_rcu() to defer the release of the object by when no
readers are walking over those bits, good.
But then, you don't need the synchronize_rcu(). To clarify:
1) If you release memory synchronously, you use this pattern:
list_replace_rcu(...);
synchronize_rcu(); <---- waits until no readers are referencing to
objects that we removes with the rcu safe list
variant
kfree(...);
2) If you release memory asynchronously, then:
list_replace_rcu(...);
kfree_rcu(...);
In this case, I think you don't need to call synchronize_rcu() since
you selected approach 2).
More concerns: Let's revisit __list_set_del():
>static void
>__list_set_del(struct ip_set *set, struct set_elem *e)
> {
> struct list_set *map = set->data;
>
> ip_set_put_byindex(map->net, e->id);
> /* We may call it, because we don't have a to be destroyed
> * extension which is used by the kernel.
> */
> ip_set_ext_destroy(set, e);
^.......................^
You may have a reader still walking on the extension area of the
element by when you call this.
> kfree_rcu(e, rcu);
>}
The alternative to make sure that everything is released by when no
readers are accessing the object anymore is to use call_rcu():
call_rcu(e, ipset_list_free_rcu);
Then:
static void ipset_list_free_rcu(struct rcu_head *rcu)
{
ip_set_put_byindex(...);
ip_set_ext_destroy(...);
kfree(set);
}
This safely release memory with 100% guarantee no readers are accesing
the object you're destroying.
*But* you have to make sure none of those function in the callback may
sleep. Since this callback is called from the rcu softirq (interrupt
context).
I suspect (actually I would need to make a closer look) you cannot use
this pattern easily unless elements keep a pointer to the set they
belong to, to access the data you need from the callback.
Let me know,
Thanks.
next prev parent reply other threads:[~2014-12-18 18:36 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-12 21:58 [PATCH 0/8] ipset patches for nf-next, v3 Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 1/8] netfilter: ipset: Remove rbtree from hash:net,iface in order to run under RCU Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 2/8] netfilter: ipset: Prepare ipset core for RCU locking instead of rwlock per set Jozsef Kadlecsik
2014-12-18 18:38 ` Pablo Neira Ayuso [this message]
2014-12-21 11:52 ` Jozsef Kadlecsik
2014-12-21 12:23 ` Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 3/8] netfilter: ipset: Introduce RCU locking in the bitmap types Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 4/8] netfilter: ipset: Introduce RCU locking in the list type Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 5/8] netfilter: ipset: Introduce RCU locking in the hash types Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 6/8] netfilter: ipset: styles warned by checkpatch.pl fixed Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 7/8] netfilter: ipset: Fix parallel resizing and listing of the same set Jozsef Kadlecsik
2014-12-12 21:58 ` [PATCH 8/8] netfilter: ipset: Fix sparse warning Jozsef Kadlecsik
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=20141218183833.GA3552@salvia \
--to=pablo@netfilter.org \
--cc=kadlec@blackhole.kfki.hu \
--cc=netfilter-devel@vger.kernel.org \
/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.