diff options
| author | Haiyang Zhang <haiyangz@microsoft.com> | 2010-05-28 19:22:44 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-30 11:18:14 -0400 |
| commit | 8b5d6d3bd3e34e4cc67d875c8c88007c1c9aa960 (patch) | |
| tree | 2f923d8299574a31799c14bfd9ecc10520ed9b02 | |
| parent | 6c2fd308045ba902fbe9f4408daa7b949fa8f5a1 (diff) | |
staging: hv: Fix race condition on vmbus channel initialization
There is a possible race condition when hv_utils starts to load immediately
after hv_vmbus is loading - null pointer error could happen.
This patch added wait/completion to ensure all channels are ready before
vmbus loading completes. So another module won't have any uninitialized channel.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/staging/hv/channel_mgmt.c | 41 | ||||
| -rw-r--r-- | drivers/staging/hv/vmbus.h | 2 | ||||
| -rw-r--r-- | drivers/staging/hv/vmbus_drv.c | 3 |
3 files changed, 35 insertions, 11 deletions
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index 3f53b4d1e4cf..12db555a3a5d 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
| 25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/completion.h> | ||
| 26 | #include "osd.h" | 27 | #include "osd.h" |
| 27 | #include "logging.h" | 28 | #include "logging.h" |
| 28 | #include "vmbus_private.h" | 29 | #include "vmbus_private.h" |
| @@ -293,6 +294,25 @@ void FreeVmbusChannel(struct vmbus_channel *Channel) | |||
| 293 | Channel); | 294 | Channel); |
| 294 | } | 295 | } |
| 295 | 296 | ||
| 297 | |||
| 298 | DECLARE_COMPLETION(hv_channel_ready); | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Count initialized channels, and ensure all channels are ready when hv_vmbus | ||
| 302 | * module loading completes. | ||
| 303 | */ | ||
| 304 | static void count_hv_channel(void) | ||
| 305 | { | ||
| 306 | static int counter; | ||
| 307 | unsigned long flags; | ||
| 308 | |||
| 309 | spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); | ||
| 310 | if (++counter == MAX_MSG_TYPES) | ||
| 311 | complete(&hv_channel_ready); | ||
| 312 | spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); | ||
| 313 | } | ||
| 314 | |||
| 315 | |||
| 296 | /* | 316 | /* |
| 297 | * VmbusChannelProcessOffer - Process the offer by creating a channel/device | 317 | * VmbusChannelProcessOffer - Process the offer by creating a channel/device |
| 298 | * associated with this offer | 318 | * associated with this offer |
| @@ -373,22 +393,21 @@ static void VmbusChannelProcessOffer(void *context) | |||
| 373 | * can cleanup properly | 393 | * can cleanup properly |
| 374 | */ | 394 | */ |
| 375 | newChannel->State = CHANNEL_OPEN_STATE; | 395 | newChannel->State = CHANNEL_OPEN_STATE; |
| 376 | cnt = 0; | ||
| 377 | 396 | ||
| 378 | while (cnt != MAX_MSG_TYPES) { | 397 | /* Open IC channels */ |
| 398 | for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) { | ||
| 379 | if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType, | 399 | if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType, |
| 380 | &hv_cb_utils[cnt].data, | 400 | &hv_cb_utils[cnt].data, |
| 381 | sizeof(struct hv_guid)) == 0) { | 401 | sizeof(struct hv_guid)) == 0 && |
| 402 | VmbusChannelOpen(newChannel, 2 * PAGE_SIZE, | ||
| 403 | 2 * PAGE_SIZE, NULL, 0, | ||
| 404 | hv_cb_utils[cnt].callback, | ||
| 405 | newChannel) == 0) { | ||
| 406 | hv_cb_utils[cnt].channel = newChannel; | ||
| 382 | DPRINT_INFO(VMBUS, "%s", | 407 | DPRINT_INFO(VMBUS, "%s", |
| 383 | hv_cb_utils[cnt].log_msg); | 408 | hv_cb_utils[cnt].log_msg); |
| 384 | 409 | count_hv_channel(); | |
| 385 | if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE, | ||
| 386 | 2 * PAGE_SIZE, NULL, 0, | ||
| 387 | hv_cb_utils[cnt].callback, | ||
| 388 | newChannel) == 0) | ||
| 389 | hv_cb_utils[cnt].channel = newChannel; | ||
| 390 | } | 410 | } |
| 391 | cnt++; | ||
| 392 | } | 411 | } |
| 393 | } | 412 | } |
| 394 | DPRINT_EXIT(VMBUS); | 413 | DPRINT_EXIT(VMBUS); |
diff --git a/drivers/staging/hv/vmbus.h b/drivers/staging/hv/vmbus.h index 0c6ee0f487f3..3c14b2926e00 100644 --- a/drivers/staging/hv/vmbus.h +++ b/drivers/staging/hv/vmbus.h | |||
| @@ -74,4 +74,6 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx); | |||
| 74 | void vmbus_child_driver_unregister(struct driver_context *driver_ctx); | 74 | void vmbus_child_driver_unregister(struct driver_context *driver_ctx); |
| 75 | void vmbus_get_interface(struct vmbus_channel_interface *interface); | 75 | void vmbus_get_interface(struct vmbus_channel_interface *interface); |
| 76 | 76 | ||
| 77 | extern struct completion hv_channel_ready; | ||
| 78 | |||
| 77 | #endif /* _VMBUS_H_ */ | 79 | #endif /* _VMBUS_H_ */ |
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index c21731a12ca7..22c80ece6388 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
| 28 | #include <linux/dmi.h> | 28 | #include <linux/dmi.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/completion.h> | ||
| 30 | #include "version_info.h" | 31 | #include "version_info.h" |
| 31 | #include "osd.h" | 32 | #include "osd.h" |
| 32 | #include "logging.h" | 33 | #include "logging.h" |
| @@ -356,6 +357,8 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) | |||
| 356 | 357 | ||
| 357 | vmbus_drv_obj->GetChannelOffers(); | 358 | vmbus_drv_obj->GetChannelOffers(); |
| 358 | 359 | ||
| 360 | wait_for_completion(&hv_channel_ready); | ||
| 361 | |||
| 359 | cleanup: | 362 | cleanup: |
| 360 | DPRINT_EXIT(VMBUS_DRV); | 363 | DPRINT_EXIT(VMBUS_DRV); |
| 361 | 364 | ||
