From: Ben Pfaff Date: Mon, 16 Mar 2009 20:14:18 +0000 (-0700) Subject: brcompat: Tolerate a race condition in deleting bridge ports. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b48ddf0464b8d498567240abac3fd1f457feb86c;p=openvswitch brcompat: Tolerate a race condition in deleting bridge ports. When we delete a bridge port (e.g. "brctl delif"), the port could get removed from the bridge we are interested in and then quickly added back into another bridge while sleeping. Return immediately in this case, since the port must really have been deleted from the bridge in question. There is a remaining race that the port could get deleted from the bridge and then added back to the same one. --- diff --git a/datapath/brcompat.c b/datapath/brcompat.c index 709c838c..ce152a28 100644 --- a/datapath/brcompat.c +++ b/datapath/brcompat.c @@ -402,15 +402,22 @@ int brc_send_port_add_del(struct net_device *dev, struct net_device *port, msleep(10); rtnl_lock(); + /* Since we released the RTNL lock, we have to make sure that + * our devices still exist. (But as long as they still exist, + * there's no point in refreshing 'dp' or 'dp_dev', since + * ifindexes are reused very slowly if ever.) */ dev = __dev_get_by_index(&init_net, dev_ifindex); port = __dev_get_by_index(&init_net, port_ifindex); if (!dev || !port) return -ENODEV; - if (add && port->br_port) - return port->br_port->dev ? 0 : -EBUSY; - else if (!add && !port->br_port) - return 0; + if (add) { + if (port->br_port) + return port->br_port->dp == dp ? 0 : -EBUSY; + } else { + if (!port->br_port || port->br_port->dp != dp) + return 0; + } } return -ETIMEDOUT;