2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

dpif-netdev: Introduce port_try_ref() to prevent a race.

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 <alexw@nicira.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
This commit is contained in:
Alex Wang
2014-08-21 15:54:07 -07:00
parent 16ee1400bb
commit a1fdee136b

View File

@@ -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,20 +1874,27 @@ pmd_load_queues(struct pmd_thread *f,
index = 0;
CMAP_FOR_EACH (port, node, &f->dp->ports) {
if (netdev_is_pmd(port->netdev)) {
int i;
/* Calls port_try_ref() to prevent the main thread
* from deleting the port. */
if (port_try_ref(port)) {
if (netdev_is_pmd(port->netdev)) {
int i;
for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
if ((index % dp->n_pmd_threads) == id) {
poll_list = xrealloc(poll_list, sizeof *poll_list * (poll_cnt + 1));
for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
if ((index % dp->n_pmd_threads) == id) {
poll_list = xrealloc(poll_list,
sizeof *poll_list * (poll_cnt + 1));
port_ref(port);
poll_list[poll_cnt].port = port;
poll_list[poll_cnt].rx = port->rxq[i];
poll_cnt++;
port_ref(port);
poll_list[poll_cnt].port = port;
poll_list[poll_cnt].rx = port->rxq[i];
poll_cnt++;
}
index++;
}
index++;
}
/* Unrefs the port_try_ref(). */
port_unref(port);
}
}