]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Steve Wise <swise@opengridcomputing.com> |
2 | Subject: RDMA/cxgb3: deadlock in iw_cxgb3 can cause hang when configuring interface. | |
3 | References: bnc#430998 | |
4 | ||
5 | When the iw_cxgb3 module's cxgb3_client "add" func gets called by the | |
6 | cxgb3 module, the iwarp driver ends up calling the ethtool ops get_drvinfo | |
7 | function in cxgb3 to get the fw version and other info. Currently the | |
8 | iwarp driver grabs the rtnl lock around this down call to serialize. | |
9 | As of 2.6.27 or so, things changed such that the rtnl lock is held around | |
10 | the call to the netdev driver open function. Also the cxgb3_client "add" | |
11 | function doesn't get called if the device is down. | |
12 | ||
13 | So, if you load cxgb3, then load iw_cxgb3, then ifconfig up the device, | |
14 | the iw_cxgb3 add func gets called with the rtnl_lock held. If you | |
15 | load cxgb3, ifconfig up the device, then load iw_cxgb3, the add func | |
16 | gets called without the rtnl_lock held. The former causes the deadlock, | |
17 | the latter does not. | |
18 | ||
19 | In addition, there are iw_cxgb3 sysfs handlers that also can call | |
20 | down into cxgb3 to gather the fw and hw versions. These can be called | |
21 | concurrently on different processors and at any time. Thus we need to | |
22 | push this serialization down in the cxgb3 driver get_drvinfo func. | |
23 | ||
24 | The fix is to remove rtnl lock usage, and use a per-device lock in cxgb3. | |
25 | ||
26 | Signed-off-by: Steve Wise <swise@opengridcomputing.com> | |
27 | Acked-by: Divy Le Ray <divy@chelsio.com> | |
28 | Acked-by: John Jolly <jjolly@suse.de> | |
29 | ||
30 | --- | |
31 | drivers/infiniband/hw/cxgb3/iwch_provider.c | 6 ------ | |
32 | drivers/net/cxgb3/cxgb3_main.c | 2 ++ | |
33 | 2 files changed, 2 insertions(+), 6 deletions(-) | |
34 | ||
35 | --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c | |
36 | +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c | |
37 | @@ -1102,9 +1102,7 @@ static u64 fw_vers_string_to_u64(struct | |
38 | char *cp, *next; | |
39 | unsigned fw_maj, fw_min, fw_mic; | |
40 | ||
41 | - rtnl_lock(); | |
42 | lldev->ethtool_ops->get_drvinfo(lldev, &info); | |
43 | - rtnl_unlock(); | |
44 | ||
45 | next = info.fw_version + 1; | |
46 | cp = strsep(&next, "."); | |
47 | @@ -1195,9 +1193,7 @@ static ssize_t show_fw_ver(struct device | |
48 | struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; | |
49 | ||
50 | PDBG("%s dev 0x%p\n", __func__, dev); | |
51 | - rtnl_lock(); | |
52 | lldev->ethtool_ops->get_drvinfo(lldev, &info); | |
53 | - rtnl_unlock(); | |
54 | return sprintf(buf, "%s\n", info.fw_version); | |
55 | } | |
56 | ||
57 | @@ -1210,9 +1206,7 @@ static ssize_t show_hca(struct device *d | |
58 | struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; | |
59 | ||
60 | PDBG("%s dev 0x%p\n", __func__, dev); | |
61 | - rtnl_lock(); | |
62 | lldev->ethtool_ops->get_drvinfo(lldev, &info); | |
63 | - rtnl_unlock(); | |
64 | return sprintf(buf, "%s\n", info.driver); | |
65 | } | |
66 | ||
67 | --- a/drivers/net/cxgb3/cxgb3_main.c | |
68 | +++ b/drivers/net/cxgb3/cxgb3_main.c | |
69 | @@ -1298,8 +1298,10 @@ static void get_drvinfo(struct net_devic | |
70 | u32 fw_vers = 0; | |
71 | u32 tp_vers = 0; | |
72 | ||
73 | + spin_lock(&adapter->stats_lock); | |
74 | t3_get_fw_version(adapter, &fw_vers); | |
75 | t3_get_tp_version(adapter, &tp_vers); | |
76 | + spin_unlock(&adapter->stats_lock); | |
77 | ||
78 | strcpy(info->driver, DRV_NAME); | |
79 | strcpy(info->version, DRV_VERSION); |