Skip to content

Commit c2c6331

Browse files
Andrea Righidavem330
authored andcommitted
xen-netfront: fix potential deadlock in xennet_remove()
There's a potential race in xennet_remove(); this is what the driver is doing upon unregistering a network device: 1. state = read bus state 2. if state is not "Closed": 3. request to set state to "Closing" 4. wait for state to be set to "Closing" 5. request to set state to "Closed" 6. wait for state to be set to "Closed" If the state changes to "Closed" immediately after step 1 we are stuck forever in step 4, because the state will never go back from "Closed" to "Closing". Make sure to check also for state == "Closed" in step 4 to prevent the deadlock. Also add a 5 sec timeout any time we wait for the bus state to change, to avoid getting stuck forever in wait_event(). Signed-off-by: Andrea Righi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c2b69f2 commit c2c6331

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

drivers/net/xen-netfront.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644);
6363
MODULE_PARM_DESC(max_queues,
6464
"Maximum number of queues per virtual interface");
6565

66+
#define XENNET_TIMEOUT (5 * HZ)
67+
6668
static const struct ethtool_ops xennet_ethtool_ops;
6769

6870
struct netfront_cb {
@@ -1334,12 +1336,15 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
13341336

13351337
netif_carrier_off(netdev);
13361338

1337-
xenbus_switch_state(dev, XenbusStateInitialising);
1338-
wait_event(module_wq,
1339-
xenbus_read_driver_state(dev->otherend) !=
1340-
XenbusStateClosed &&
1341-
xenbus_read_driver_state(dev->otherend) !=
1342-
XenbusStateUnknown);
1339+
do {
1340+
xenbus_switch_state(dev, XenbusStateInitialising);
1341+
err = wait_event_timeout(module_wq,
1342+
xenbus_read_driver_state(dev->otherend) !=
1343+
XenbusStateClosed &&
1344+
xenbus_read_driver_state(dev->otherend) !=
1345+
XenbusStateUnknown, XENNET_TIMEOUT);
1346+
} while (!err);
1347+
13431348
return netdev;
13441349

13451350
exit:
@@ -2139,28 +2144,43 @@ static const struct attribute_group xennet_dev_group = {
21392144
};
21402145
#endif /* CONFIG_SYSFS */
21412146

2142-
static int xennet_remove(struct xenbus_device *dev)
2147+
static void xennet_bus_close(struct xenbus_device *dev)
21432148
{
2144-
struct netfront_info *info = dev_get_drvdata(&dev->dev);
2145-
2146-
dev_dbg(&dev->dev, "%s\n", dev->nodename);
2149+
int ret;
21472150

2148-
if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) {
2151+
if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
2152+
return;
2153+
do {
21492154
xenbus_switch_state(dev, XenbusStateClosing);
2150-
wait_event(module_wq,
2151-
xenbus_read_driver_state(dev->otherend) ==
2152-
XenbusStateClosing ||
2153-
xenbus_read_driver_state(dev->otherend) ==
2154-
XenbusStateUnknown);
2155+
ret = wait_event_timeout(module_wq,
2156+
xenbus_read_driver_state(dev->otherend) ==
2157+
XenbusStateClosing ||
2158+
xenbus_read_driver_state(dev->otherend) ==
2159+
XenbusStateClosed ||
2160+
xenbus_read_driver_state(dev->otherend) ==
2161+
XenbusStateUnknown,
2162+
XENNET_TIMEOUT);
2163+
} while (!ret);
2164+
2165+
if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
2166+
return;
21552167

2168+
do {
21562169
xenbus_switch_state(dev, XenbusStateClosed);
2157-
wait_event(module_wq,
2158-
xenbus_read_driver_state(dev->otherend) ==
2159-
XenbusStateClosed ||
2160-
xenbus_read_driver_state(dev->otherend) ==
2161-
XenbusStateUnknown);
2162-
}
2170+
ret = wait_event_timeout(module_wq,
2171+
xenbus_read_driver_state(dev->otherend) ==
2172+
XenbusStateClosed ||
2173+
xenbus_read_driver_state(dev->otherend) ==
2174+
XenbusStateUnknown,
2175+
XENNET_TIMEOUT);
2176+
} while (!ret);
2177+
}
2178+
2179+
static int xennet_remove(struct xenbus_device *dev)
2180+
{
2181+
struct netfront_info *info = dev_get_drvdata(&dev->dev);
21632182

2183+
xennet_bus_close(dev);
21642184
xennet_disconnect_backend(info);
21652185

21662186
if (info->netdev->reg_state == NETREG_REGISTERED)

0 commit comments

Comments
 (0)