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); |
