Oops, I forgot my signoff.  Here it is:

Signed-off-by: Daniele Di Proietto <diproiet...@vmware.com>

On 23/03/2016 18:02, "Daniele Di Proietto" <diproiet...@vmware.com> wrote:

>A new thread must be started in a non quiescent state.  There is a call
>to ovsrcu_quiesce_end() in ovsthread_wrapper(), to enforce this.
>
>ovs_thread_create(), instead, is executed in the parent thread, and
>calling ovsrcu_quiesce_end() there will cause the parent to end its
>(possible) quiescing state, which it's not required to start a child
>thread.
>
>This fixes a bug in ovs-rcu where the first call in the process to
>ovsrcu_quiesce_start() will not be honored, because the calling thread
>will need to create the 'urcu' thread (and creating a thread will
>wrongly end its quiescent state).
>
>ovsrcu_quiesce_start()
>  ovs_rcu_quiesced()
>    if (ovsthread_once_start(&once)) {
>        ovs_thread_create("urcu") /*This will end the quiescent state*/
>    }
>
>This bug manifest itself especially when staring ovs-vswitchd with DPDK.
>In the DPDK case the first threads create are "vhost_thread" and
>"dpdk_watchdog".  If dpdk_watchdog is the first to call
>ovsrcu_quiesce_start() (via xsleep()), the call is not honored and
>the RCU grace period lasts at least for DPDK_PORT_WATCHDOG_INTERVAL
>(5s on current master).  If vhost_thread, on the other hand, is the
>first to call ovsrcu_quiesce_start(), the call is not honored and the
>RCU grace period lasts undefinitely, because no more calls to
>ovsrcu_quiesce_start() are issued from vhost_thread.
>
>For some reason (it's a race condition after all), on current master,
>dpdk_watchdog will always be the first to call ovsrcu_quiesce_start(),
>but with the upcoming DPDK database configuration changes, sometimes
>vhost_thread will issue the first call to ovsrcu_quiesce_start().
>
>Sample ovs-vswitchd.log:
>
>2016-03-23T22:34:28.532Z|00004|ovs_rcu(urcu3)|WARN|blocked 8000 ms
>waiting for vhost_thread2 to quiesce
>2016-03-23T22:34:30.501Z|00118|ovs_rcu|WARN|blocked 8000 ms waiting for
>vhost_thread2 to quiesce
>2016-03-23T22:34:36.532Z|00005|ovs_rcu(urcu3)|WARN|blocked 16000 ms
>waiting for vhost_thread2 to quiesce
>2016-03-23T22:34:38.501Z|00119|ovs_rcu|WARN|blocked 16000 ms waiting for
>vhost_thread2 to quiesce
>
>The commit also adds a test for the ovs-rcu module to make sure that:
>* A new thread is started in a non quiescent state.
>* The first call to ovsrcu_quiesce_start() is honored.
>---
> lib/ovs-thread.c  |  1 -
> tests/automake.mk |  1 +
> tests/library.at  |  4 ++++
> tests/test-rcu.c  | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 51 insertions(+), 1 deletion(-)
> create mode 100644 tests/test-rcu.c
>
>diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
>index 7777298..13bf6b0 100644
>--- a/lib/ovs-thread.c
>+++ b/lib/ovs-thread.c
>@@ -370,7 +370,6 @@ ovs_thread_create(const char *name, void
>*(*start)(void *), void *arg)
> 
>     forbid_forking("multiple threads exist");
>     multithreaded = true;
>-    ovsrcu_quiesce_end();
> 
>     aux = xmalloc(sizeof *aux);
>     aux->start = start;
>diff --git a/tests/automake.mk b/tests/automake.mk
>index 98c4df0..ca65ed5 100644
>--- a/tests/automake.mk
>+++ b/tests/automake.mk
>@@ -327,6 +327,7 @@ tests_ovstest_SOURCES = \
>       tests/test-ovn.c \
>       tests/test-packets.c \
>       tests/test-random.c \
>+      tests/test-rcu.c \
>       tests/test-reconnect.c \
>       tests/test-rstp.c \
>       tests/test-sflow.c \
>diff --git a/tests/library.at b/tests/library.at
>index 4094348..e1bac92 100644
>--- a/tests/library.at
>+++ b/tests/library.at
>@@ -230,3 +230,7 @@ AT_CLEANUP
> AT_SETUP([test ofpbuf module])
> AT_CHECK([ovstest test-ofpbuf], [0], [])
> AT_CLEANUP
>+
>+AT_SETUP([test rcu])
>+AT_CHECK([ovstest test-rcu-quiesce], [0], [])
>+AT_CLEANUP
>diff --git a/tests/test-rcu.c b/tests/test-rcu.c
>new file mode 100644
>index 0000000..7c0ffe4
>--- /dev/null
>+++ b/tests/test-rcu.c
>@@ -0,0 +1,46 @@
>+/*
>+ * Copyright (c) 2016 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>
>+#undef NDEBUG
>+#include "fatal-signal.h"
>+#include "ovs-rcu.h"
>+#include "ovs-thread.h"
>+#include "ovstest.h"
>+#include "util.h"
>+
>+static void *
>+quiescer_main(void *aux OVS_UNUSED)
>+{
>+    ovs_assert(!ovsrcu_is_quiescent());
>+    ovsrcu_quiesce_start();
>+    ovs_assert(ovsrcu_is_quiescent());
>+
>+    return NULL;
>+}
>+
>+static void
>+test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
>+{
>+    pthread_t quiescer;
>+
>+    fatal_signal_init();
>+    quiescer = ovs_thread_create("quiescer", quiescer_main, NULL);
>+
>+    xpthread_join(quiescer, NULL);
>+}
>+
>+OVSTEST_REGISTER("test-rcu-quiesce", test_rcu_quiesce);
>-- 
>2.1.4
>

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to