From b48ddf0464b8d498567240abac3fd1f457feb86c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 16 Mar 2009 13:14:18 -0700 Subject: [PATCH] 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. --- datapath/brcompat.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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; -- 2.30.2