summaryrefslogtreecommitdiff
path: root/lib/dpif-netdev.c
diff options
context:
space:
mode:
authorAlex Wang <alexw@nicira.com>2014-11-07 13:27:05 -0800
committerAlex Wang <alexw@nicira.com>2014-11-12 15:59:12 -0800
commitaccf86266abbde21d5a8145bf14125db0f4e0e2d (patch)
treeb6734148d8d50d908ca15eaa93b38afbb5065a34 /lib/dpif-netdev.c
parent40a9c4c26be9b59c3494dd5900c21015ea7d27d4 (diff)
downloadopenvswitch-accf86266abbde21d5a8145bf14125db0f4e0e2d.tar.gz
dpif-netdev: Allow direct destroy of 'struct dp_netdev_port'.
Before this commit, when 'struct dp_netdev_port' is deleted from 'dpif-netdev' datapath, if there is pmd thread, the pmd thread will release the last reference to the port and ovs-rcu postpone the destroy. However, the delayed close of object like 'struct netdev' could cause failure in immediate re-add or reconfigure of the same device. To fix the above issue, this commit uses condition variable and makes the main thread wait for pmd thread to release the reference when deleting port. Then, the main thread can directly destroy the port. Reported-by: Cian Ferriter <cian.ferriter@intel.com> Signed-off-by: Alex Wang <alexw@nicira.com> Acked-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'lib/dpif-netdev.c')
-rw-r--r--lib/dpif-netdev.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index c134c4372..65df19b5b 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -372,6 +372,10 @@ static void dp_netdev_actions_free(struct dp_netdev_actions *);
struct dp_netdev_pmd_thread {
struct dp_netdev *dp;
struct cmap_node node; /* In 'dp->poll_threads'. */
+
+ pthread_cond_t cond; /* For synchronizing pmd thread reload. */
+ struct ovs_mutex cond_mutex; /* Mutex for condition variable. */
+
/* Per thread exact-match cache. Note, the instance for cpu core
* NON_PMD_CORE_ID can be accessed by multiple threads, and thusly
* need to be protected (e.g. by 'dp_netdev_mutex'). All other
@@ -418,6 +422,7 @@ static void dp_netdev_input(struct dp_netdev_pmd_thread *,
struct dpif_packet **, int cnt);
static void dp_netdev_disable_upcall(struct dp_netdev *);
+void dp_netdev_pmd_reload_done(struct dp_netdev_pmd_thread *pmd);
static void dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd,
struct dp_netdev *dp, int index,
int core_id, int numa_id);
@@ -764,7 +769,14 @@ dp_netdev_reload_pmd__(struct dp_netdev_pmd_thread *pmd)
{
int old_seq;
+ if (pmd->core_id == NON_PMD_CORE_ID) {
+ return;
+ }
+
+ ovs_mutex_lock(&pmd->cond_mutex);
atomic_add_relaxed(&pmd->change_seq, 1, &old_seq);
+ ovs_mutex_cond_wait(&pmd->cond, &pmd->cond_mutex);
+ ovs_mutex_unlock(&pmd->cond_mutex);
}
/* Causes all pmd threads to reload its tx/rx devices.
@@ -975,27 +987,21 @@ port_try_ref(struct dp_netdev_port *port)
}
static void
-port_destroy__(struct dp_netdev_port *port)
-{
- int n_rxq = netdev_n_rxq(port->netdev);
- int i;
-
- netdev_close(port->netdev);
- netdev_restore_flags(port->sf);
-
- for (i = 0; i < n_rxq; i++) {
- netdev_rxq_close(port->rxq[i]);
- }
- free(port->rxq);
- free(port->type);
- free(port);
-}
-
-static void
port_unref(struct dp_netdev_port *port)
{
if (port && ovs_refcount_unref_relaxed(&port->ref_cnt) == 1) {
- ovsrcu_postpone(port_destroy__, port);
+ int n_rxq = netdev_n_rxq(port->netdev);
+ int i;
+
+ netdev_close(port->netdev);
+ netdev_restore_flags(port->sf);
+
+ for (i = 0; i < n_rxq; i++) {
+ netdev_rxq_close(port->rxq[i]);
+ }
+ free(port->rxq);
+ free(port->type);
+ free(port);
}
}
@@ -2310,6 +2316,10 @@ reload:
emc_cache_init(&pmd->flow_cache);
poll_cnt = pmd_load_queues(pmd, &poll_list, poll_cnt);
+ /* Signal here to make sure the pmd finishes
+ * reloading the updated configuration. */
+ dp_netdev_pmd_reload_done(pmd);
+
for (;;) {
int i;
@@ -2342,6 +2352,8 @@ reload:
port_unref(poll_list[i].port);
}
+ dp_netdev_pmd_reload_done(pmd);
+
free(poll_list);
return NULL;
}
@@ -2376,6 +2388,14 @@ dpif_netdev_enable_upcall(struct dpif *dpif)
dp_netdev_enable_upcall(dp);
}
+void
+dp_netdev_pmd_reload_done(struct dp_netdev_pmd_thread *pmd)
+{
+ ovs_mutex_lock(&pmd->cond_mutex);
+ xpthread_cond_signal(&pmd->cond);
+ ovs_mutex_unlock(&pmd->cond_mutex);
+}
+
/* Returns the pointer to the dp_netdev_pmd_thread for non-pmd threads. */
static struct dp_netdev_pmd_thread *
dp_netdev_get_nonpmd(struct dp_netdev *dp)
@@ -2412,6 +2432,8 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct dp_netdev *dp,
pmd->numa_id = numa_id;
latch_init(&pmd->exit_latch);
atomic_init(&pmd->change_seq, PMD_INITIAL_SEQ);
+ xpthread_cond_init(&pmd->cond, NULL);
+ ovs_mutex_init(&pmd->cond_mutex);
/* init the 'flow_cache' since there is no
* actual thread created for NON_PMD_CORE_ID. */
if (core_id == NON_PMD_CORE_ID) {
@@ -2438,6 +2460,8 @@ dp_netdev_del_pmd(struct dp_netdev_pmd_thread *pmd)
}
cmap_remove(&pmd->dp->poll_threads, &pmd->node, hash_int(pmd->core_id, 0));
latch_destroy(&pmd->exit_latch);
+ xpthread_cond_destroy(&pmd->cond);
+ ovs_mutex_destroy(&pmd->cond_mutex);
free(pmd);
}