Looks good to me, thx for adding these comments~! On Thu, Jun 11, 2015 at 4:49 PM, Jarno Rajahalme <jrajaha...@nicira.com> wrote:
> I sent a v3 that compiles also on clang. > > Jarno > > > On Jun 11, 2015, at 11:06 AM, Jarno Rajahalme <jrajaha...@nicira.com> > wrote: > > > > Postponed 'next' member poisoning was based on the faulty assumption > > that postponed functions would be called in the order they were > > postponed. This assumption holds only for the functions postponed by > > any single thread. When functions are postponed by different > > threads, there are no guarantees of the order in which the functions > > may be called, or timing between those calls after the next grace > > period has passed. > > > > Given this, the postponed poisoning could have executed after > > postponed destruction of the object containing the rculist element. > > > > This bug was revealed after the memory leaks on rule deletion were > > recently fixed. > > > > This patch removes the postponed 'next' member poisoning and adds > > documentation describing the ordering limitations in OVS RCU. > > > > Alex Wang dug out the root cause of the resulting crashes, thanks! > > > > Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> > > --- > > v2: rebase. > > > > lib/automake.mk | 1 - > > lib/classifier.c | 7 +++---- > > lib/ovs-rcu.c | 13 +++++++++++++ > > lib/ovs-rcu.h | 15 ++++++++++++++- > > lib/rculist.c | 27 --------------------------- > > lib/rculist.h | 36 +++++++++++++++++------------------- > > 6 files changed, 47 insertions(+), 52 deletions(-) > > delete mode 100644 lib/rculist.c > > > > diff --git a/lib/automake.mk b/lib/automake.mk > > index 7a34c1a..f082115 100644 > > --- a/lib/automake.mk > > +++ b/lib/automake.mk > > @@ -197,7 +197,6 @@ lib_libopenvswitch_la_SOURCES = \ > > lib/random.h \ > > lib/rconn.c \ > > lib/rconn.h \ > > - lib/rculist.c \ > > lib/rculist.h \ > > lib/reconnect.c \ > > lib/reconnect.h \ > > diff --git a/lib/classifier.c b/lib/classifier.c > > index 2b2d3f6..12d91e3 100644 > > --- a/lib/classifier.c > > +++ b/lib/classifier.c > > @@ -276,11 +276,10 @@ cls_rule_destroy(struct cls_rule *rule) > > { > > ovs_assert(!rule->cls_match); /* Must not be in a classifier. */ > > > > - /* Check that the rule has been properly removed from the > classifier and > > - * that the destruction only happens after the RCU grace period, or > that > > - * the rule was never inserted to the classifier in the first > place. */ > > - ovs_assert(rculist_next_protected(&rule->node) == RCULIST_POISON > > + /* Check that the rule has been properly removed from the > classifier. */ > > + ovs_assert(rule->node.prev == RCULIST_POISON > > || rculist_is_empty(&rule->node)); > > + rculist_poison__(&rule->node); /* Poisons also the next pointer. > */ > > > > minimatch_destroy(CONST_CAST(struct minimatch *, &rule->match)); > > } > > diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c > > index e0634cf..b8f8bc4 100644 > > --- a/lib/ovs-rcu.c > > +++ b/lib/ovs-rcu.c > > @@ -212,6 +212,19 @@ ovsrcu_synchronize(void) > > /* Registers 'function' to be called, passing 'aux' as argument, after > the > > * next grace period. > > * > > + * The call is guaranteed to happen after the next time all > participating > > + * threads have quiesced at least once, but there is no quarantee that > all > > + * registered functions are called as early as possible, or that the > functions > > + * registered by different threads would be called in the order the > > + * registrations took place. In particular, even if two threads > provably > > + * register a function each in a specific order, the functions may > still be > > + * called in the opposite order, depending on the timing of when the > threads > > + * call ovsrcu_quiesce(), how many functions they postpone, and when the > > + * ovs-rcu thread happens to grab the functions to be called. > > + * > > + * All functions registered by a single thread are guaranteed to > execute in the > > + * registering order, however. > > + * > > * This function is more conveniently called through the > ovsrcu_postpone() > > * macro, which provides a type-safe way to allow 'function''s parameter > to be > > * any pointer type. */ > > diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h > > index 1d79976..c1e3d60 100644 > > --- a/lib/ovs-rcu.h > > +++ b/lib/ovs-rcu.h > > @@ -60,12 +60,25 @@ > > * > > * When a quiescient state has occurred in every thread, we say that a > "grace > > * period" has occurred. Following a grace period, all of the callbacks > > - * postponed before the start of the grace period may be invoked. OVS > takes > > + * postponed before the start of the grace period MAY be invoked. OVS > takes > > * care of this automatically through the RCU mechanism: while a process > still > > * has only a single thread, it invokes the postponed callbacks directly > from > > * ovsrcu_quiesce() and ovsrcu_quiesce_start(); after additional threads > have > > * been created, it creates an extra helper thread to invoke callbacks. > > * > > + * Please note that while a postponed function call is guaranteed to > happen > > + * after the next time all participating threads have quiesced at least > once, > > + * there is no quarantee that all postponed functions are called as > early as > > + * possible, or that the functions postponed by different threads would > be > > + * called in the order the registrations took place. In particular, > even if > > + * two threads provably postpone a function each in a specific order, > the > > + * postponed functions may still be called in the opposite order, > depending on > > + * the timing of when the threads call ovsrcu_quiesce(), how many > functions > > + * they postpone, and when the ovs-rcu thread happens to grab the > functions to > > + * be called. > > + * > > + * All functions postponed by a single thread are guaranteed to execute > in the > > + * order they were postponed, however. > > * > > * Use > > * --- > > diff --git a/lib/rculist.c b/lib/rculist.c > > deleted file mode 100644 > > index 61a03d0..0000000 > > --- a/lib/rculist.c > > +++ /dev/null > > @@ -1,27 +0,0 @@ > > -/* > > - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. > > - * > > - * Licensed under the Apache License, Version 2.0 (the "License"); > > - * you may not use this file except in compliance with the License. > > - * You may obtain a copy of the License at: > > - * > > - * http://www.apache.org/licenses/LICENSE-2.0 > > - * > > - * Unless required by applicable law or agreed to in writing, software > > - * distributed under the License is distributed on an "AS IS" BASIS, > > - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > > - * See the License for the specific language governing permissions and > > - * limitations under the License. > > - */ > > -#include <config.h> > > -#include "rculist.h" > > - > > -/* Initializes 'list' with pointers that will (probably) cause > segfaults if > > - * dereferenced and, better yet, show up clearly in a debugger. */ > > -void > > -rculist_poison__(struct rculist *list) > > - OVS_NO_THREAD_SAFETY_ANALYSIS > > -{ > > - list->prev = RCULIST_POISON; > > - ovsrcu_set_hidden(&list->next, RCULIST_POISON); > > -} > > diff --git a/lib/rculist.h b/lib/rculist.h > > index f3c1475..7ba20e5 100644 > > --- a/lib/rculist.h > > +++ b/lib/rculist.h > > @@ -38,10 +38,7 @@ > > * - rculist_front() returns a const pointer to accommodate for an RCU > reader. > > * - rculist_splice_hidden(): Spliced elements may not have been visible > to > > * RCU readers before the operation. > > - * - rculist_poison(): Immediately poisons the 'prev' pointer, and > schedules > > - * ovsrcu_postpone() to poison the 'next' pointer. This issues a > memory > > - * write operation to the list element, hopefully crashing the > program if > > - * the list node was freed or re-used too early. > > + * - rculist_poison(): Only poisons the 'prev' pointer. > > * > > * The following functions are variations of the struct ovs_list > functions with > > * similar names, but are now restricted to the writer use: > > @@ -134,8 +131,6 @@ rculist_init(struct rculist *list) > > > > #define RCULIST_POISON (struct rculist *)(UINTPTR_MAX / 0xf * 0xc) > > > > -void rculist_poison__(struct rculist *list); > > - > > /* Initializes 'list' with pointers that will (probably) cause segfaults > if > > * dereferenced and, better yet, show up clearly in a debugger. */ > > static inline void > > @@ -143,7 +138,19 @@ rculist_poison(struct rculist *list) > > OVS_NO_THREAD_SAFETY_ANALYSIS > > { > > list->prev = RCULIST_POISON; > > - ovsrcu_postpone(rculist_poison__, list); > > +} > > + > > +/* Initializes 'list' with pointers that will (probably) cause > segfaults if > > + * dereferenced and, better yet, show up clearly in a debugger. > > + * > > + * This variant poisons also the next pointer, so this may not be > called if > > + * this list element is still visible to RCU readers. */ > > +static inline void > > +rculist_poison__(struct rculist *list) > > + OVS_NO_THREAD_SAFETY_ANALYSIS > > +{ > > + rculist_poison(list); > > + ovsrcu_set_hidden(&list->next, RCULIST_POISON); > > } > > > > /* rculist insertion. */ > > @@ -217,10 +224,7 @@ rculist_replace(struct rculist *element, struct > rculist *position) > > position_next->prev = element; > > element->prev = position->prev; > > ovsrcu_set(&element->prev->next, element); > > - > > -#ifndef NDEBUG > > - rculist_poison(position); /* XXX: Some overhead due to > ovsrcu_postpone() */ > > -#endif > > + rculist_poison(position); > > } > > > > /* Initializes 'dst' with the contents of 'src', compensating for moving > it > > @@ -244,10 +248,7 @@ rculist_move(struct rculist *dst, struct rculist > *src) > > } else { > > rculist_init(dst); > > } > > - > > -#ifndef NDEBUG > > - rculist_poison(src); /* XXX: Some overhead due to ovsrcu_postpone() > */ > > -#endif > > + rculist_poison(src); > > } > > > > /* Removes 'elem' from its list and returns the element that followed it. > > @@ -268,10 +269,7 @@ rculist_remove(struct rculist *elem) > > > > elem_next->prev = elem->prev; > > ovsrcu_set(&elem->prev->next, elem_next); > > - > > -#ifndef NDEBUG > > - rculist_poison(elem); /* XXX: Some overhead due to > ovsrcu_postpone() */ > > -#endif > > + rculist_poison(elem); > > return elem_next; > > } > > > > -- > > 1.7.10.4 > > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev