diff options
author | Frank Pavlic <pavlic@de.ibm.com> | 2005-05-12 14:35:57 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-15 18:06:16 -0400 |
commit | b5f9d55b64a5c7193f8965c90ba62244ea3180b2 (patch) | |
tree | 8a2cb8b36047af6d4a228a24aa1c045a6ed1545c | |
parent | 109a260b66bfbab7ba9f985495791af21f910218 (diff) |
[PATCH] s390: set online race in the lcs driver
[patch 3/10] s390: set online race in the lcs driver.
From: Michael Holzheu <holzheu@de.ibm.com>
There is a race between lcs_stopcard() and lcs_open_device() which
can lead to the error 'lcs: Error in starting channel, rc=-16'.
lcs_open_device() is invoked when 'ifconfig up' is called due to a
hotplug event, which is caused by register_netdev(). In parallel
lcs_stopcard() is executed. Both functions are sending lcs commands.
The second invocation fails with -EBUSY (-16) as return value.
Move invocation of register_netdev() after invocation of lcs_stopcard
to avoid the race.
Signed-off-by: Frank Pavlic <pavlic@de.ibm.com>
-rw-r--r-- | drivers/s390/net/lcs.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 8d0262e4adc0..cccfed248e70 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * Frank Pavlic (pavlic@de.ibm.com) and | 11 | * Frank Pavlic (pavlic@de.ibm.com) and |
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
13 | * | 13 | * |
14 | * $Revision: 1.97 $ $Date: 2005/03/31 09:42:02 $ | 14 | * $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $ |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -59,7 +59,7 @@ | |||
59 | /** | 59 | /** |
60 | * initialization string for output | 60 | * initialization string for output |
61 | */ | 61 | */ |
62 | #define VERSION_LCS_C "$Revision: 1.97 $" | 62 | #define VERSION_LCS_C "$Revision: 1.98 $" |
63 | 63 | ||
64 | static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; | 64 | static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; |
65 | static char debug_buffer[255]; | 65 | static char debug_buffer[255]; |
@@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_card *card) | |||
1098 | PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); | 1098 | PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); |
1099 | return -EOPNOTSUPP; | 1099 | return -EOPNOTSUPP; |
1100 | } | 1100 | } |
1101 | /* Print out supported assists: IPv6 */ | ||
1102 | PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, | ||
1103 | (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? | ||
1104 | "with" : "without"); | ||
1105 | /* Print out supported assist: Multicast */ | ||
1106 | PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, | ||
1107 | (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? | ||
1108 | "with" : "without"); | ||
1109 | if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) | 1101 | if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) |
1110 | return 0; | 1102 | return 0; |
1111 | return -EOPNOTSUPP; | 1103 | return -EOPNOTSUPP; |
@@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) | |||
2198 | if (!dev) | 2190 | if (!dev) |
2199 | goto out; | 2191 | goto out; |
2200 | card->dev = dev; | 2192 | card->dev = dev; |
2201 | netdev_out: | ||
2202 | card->dev->priv = card; | 2193 | card->dev->priv = card; |
2203 | card->dev->open = lcs_open_device; | 2194 | card->dev->open = lcs_open_device; |
2204 | card->dev->stop = lcs_stop_device; | 2195 | card->dev->stop = lcs_stop_device; |
2205 | card->dev->hard_start_xmit = lcs_start_xmit; | 2196 | card->dev->hard_start_xmit = lcs_start_xmit; |
2206 | card->dev->get_stats = lcs_getstats; | 2197 | card->dev->get_stats = lcs_getstats; |
2207 | SET_MODULE_OWNER(dev); | 2198 | SET_MODULE_OWNER(dev); |
2208 | if (lcs_register_netdev(ccwgdev) != 0) | ||
2209 | goto out; | ||
2210 | memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); | 2199 | memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); |
2211 | #ifdef CONFIG_IP_MULTICAST | 2200 | #ifdef CONFIG_IP_MULTICAST |
2212 | if (!lcs_check_multicast_support(card)) | 2201 | if (!lcs_check_multicast_support(card)) |
2213 | card->dev->set_multicast_list = lcs_set_multicast_list; | 2202 | card->dev->set_multicast_list = lcs_set_multicast_list; |
2214 | #endif | 2203 | #endif |
2215 | netif_stop_queue(card->dev); | 2204 | netdev_out: |
2216 | lcs_set_allowed_threads(card,0xffffffff); | 2205 | lcs_set_allowed_threads(card,0xffffffff); |
2217 | if (recover_state == DEV_STATE_RECOVER) { | 2206 | if (recover_state == DEV_STATE_RECOVER) { |
2218 | lcs_set_multicast_list(card->dev); | 2207 | lcs_set_multicast_list(card->dev); |
2219 | card->dev->flags |= IFF_UP; | 2208 | card->dev->flags |= IFF_UP; |
2220 | netif_wake_queue(card->dev); | 2209 | netif_wake_queue(card->dev); |
2221 | card->state = DEV_STATE_UP; | 2210 | card->state = DEV_STATE_UP; |
2222 | } else | 2211 | } else { |
2223 | lcs_stopcard(card); | 2212 | lcs_stopcard(card); |
2213 | } | ||
2224 | 2214 | ||
2215 | if (lcs_register_netdev(ccwgdev) != 0) | ||
2216 | goto out; | ||
2217 | |||
2218 | /* Print out supported assists: IPv6 */ | ||
2219 | PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, | ||
2220 | (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? | ||
2221 | "with" : "without"); | ||
2222 | /* Print out supported assist: Multicast */ | ||
2223 | PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, | ||
2224 | (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? | ||
2225 | "with" : "without"); | ||
2225 | return 0; | 2226 | return 0; |
2226 | out: | 2227 | out: |
2227 | 2228 | ||