When pmd thread interates through all ports for queue loading,
the main thread may unreference and 'rcu-free' a port before
pmd thread take new reference of it.  This could cause pmd
thread fail the reference and access freed memory later.

This commit fixes this race by introducing port_try_ref()
which uses ovs_refcount_try_ref_rcu().  And the pmd thread
will only load the port's queue, if port_try_ref() returns
true.

Found by inspection.

Signed-off-by: Alex Wang <al...@nicira.com>
---
 lib/dpif-netdev.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 2476435..4297db0 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -880,6 +880,16 @@ port_ref(struct dp_netdev_port *port)
     }
 }
 
+static bool
+port_try_ref(struct dp_netdev_port *port)
+{
+    if (port) {
+        return ovs_refcount_try_ref_rcu(&port->ref_cnt);
+    }
+
+    return false;
+}
+
 static void
 port_destroy__(struct dp_netdev_port *port)
 {
@@ -1864,7 +1874,10 @@ pmd_load_queues(struct pmd_thread *f,
     index = 0;
 
     CMAP_FOR_EACH (port, node, &f->dp->ports) {
-        if (netdev_is_pmd(port->netdev)) {
+        /* Calls port_try_ref() to prevent the main thread
+         * from deleting the port. */
+        if (netdev_is_pmd(port->netdev)
+            && port_try_ref(port)) {
             int i;
 
             for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
@@ -1878,6 +1891,8 @@ pmd_load_queues(struct pmd_thread *f,
                 }
                 index++;
             }
+            /* Unrefs the port_try_ref(). */
+            port_unref(port);
         }
     }
 
-- 
1.7.9.5

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

Reply via email to