diff options
author | Haiyang Zhang <haiyangz@microsoft.com> | 2011-04-06 18:18:00 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-04-06 18:44:05 -0400 |
commit | c996edcf1c451b81740abbcca5257ed7e353fcc6 (patch) | |
tree | cb01c7e8c50eb3b8c380ff890c024c4f2a56f102 /drivers | |
parent | 6a6ec6233403ecdad0c042276e4479ca23716b1c (diff) |
staging: hv: Fix GARP not sent after Quick Migration
After Quick Migration, the network is not immediately operational in the
current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, I added
another netif_notify_peers() into a scheduled work, otherwise GARP packet will
not be sent after quick migration, and cause network disconnection.
Thanks to Mike Surcouf <mike@surcouf.co.uk> for reporting the bug and
testing the patch.
Reported-by: Mike Surcouf <mike@surcouf.co.uk>
Tested-by: Mike Surcouf <mike@surcouf.co.uk>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
Signed-off-by: Abhishek Kane <v-abkane@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/hv/netvsc_drv.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 2d40f5f86b24..33973568214f 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c | |||
@@ -46,6 +46,7 @@ struct net_device_context { | |||
46 | /* point back to our device context */ | 46 | /* point back to our device context */ |
47 | struct hv_device *device_ctx; | 47 | struct hv_device *device_ctx; |
48 | unsigned long avail; | 48 | unsigned long avail; |
49 | struct work_struct work; | ||
49 | }; | 50 | }; |
50 | 51 | ||
51 | 52 | ||
@@ -219,6 +220,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
219 | unsigned int status) | 220 | unsigned int status) |
220 | { | 221 | { |
221 | struct net_device *net = dev_get_drvdata(&device_obj->device); | 222 | struct net_device *net = dev_get_drvdata(&device_obj->device); |
223 | struct net_device_context *ndev_ctx; | ||
222 | 224 | ||
223 | if (!net) { | 225 | if (!net) { |
224 | DPRINT_ERR(NETVSC_DRV, "got link status but net device " | 226 | DPRINT_ERR(NETVSC_DRV, "got link status but net device " |
@@ -230,6 +232,8 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
230 | netif_carrier_on(net); | 232 | netif_carrier_on(net); |
231 | netif_wake_queue(net); | 233 | netif_wake_queue(net); |
232 | netif_notify_peers(net); | 234 | netif_notify_peers(net); |
235 | ndev_ctx = netdev_priv(net); | ||
236 | schedule_work(&ndev_ctx->work); | ||
233 | } else { | 237 | } else { |
234 | netif_carrier_off(net); | 238 | netif_carrier_off(net); |
235 | netif_stop_queue(net); | 239 | netif_stop_queue(net); |
@@ -328,6 +332,25 @@ static const struct net_device_ops device_ops = { | |||
328 | .ndo_set_mac_address = eth_mac_addr, | 332 | .ndo_set_mac_address = eth_mac_addr, |
329 | }; | 333 | }; |
330 | 334 | ||
335 | /* | ||
336 | * Send GARP packet to network peers after migrations. | ||
337 | * After Quick Migration, the network is not immediately operational in the | ||
338 | * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add | ||
339 | * another netif_notify_peers() into a scheduled work, otherwise GARP packet | ||
340 | * will not be sent after quick migration, and cause network disconnection. | ||
341 | */ | ||
342 | static void netvsc_send_garp(struct work_struct *w) | ||
343 | { | ||
344 | struct net_device_context *ndev_ctx; | ||
345 | struct net_device *net; | ||
346 | |||
347 | msleep(20); | ||
348 | ndev_ctx = container_of(w, struct net_device_context, work); | ||
349 | net = dev_get_drvdata(&ndev_ctx->device_ctx->device); | ||
350 | netif_notify_peers(net); | ||
351 | } | ||
352 | |||
353 | |||
331 | static int netvsc_probe(struct device *device) | 354 | static int netvsc_probe(struct device *device) |
332 | { | 355 | { |
333 | struct hv_driver *drv = | 356 | struct hv_driver *drv = |
@@ -353,6 +376,7 @@ static int netvsc_probe(struct device *device) | |||
353 | net_device_ctx->device_ctx = device_obj; | 376 | net_device_ctx->device_ctx = device_obj; |
354 | net_device_ctx->avail = ring_size; | 377 | net_device_ctx->avail = ring_size; |
355 | dev_set_drvdata(device, net); | 378 | dev_set_drvdata(device, net); |
379 | INIT_WORK(&net_device_ctx->work, netvsc_send_garp); | ||
356 | 380 | ||
357 | /* Notify the netvsc driver of the new device */ | 381 | /* Notify the netvsc driver of the new device */ |
358 | ret = net_drv_obj->base.dev_add(device_obj, &device_info); | 382 | ret = net_drv_obj->base.dev_add(device_obj, &device_info); |