diff options
Diffstat (limited to 'drivers/hv/channel.c')
-rw-r--r-- | drivers/hv/channel.c | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 0b122f8c7005..6de6c98ce6eb 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -116,6 +116,15 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
116 | unsigned long flags; | 116 | unsigned long flags; |
117 | int ret, t, err = 0; | 117 | int ret, t, err = 0; |
118 | 118 | ||
119 | spin_lock_irqsave(&newchannel->sc_lock, flags); | ||
120 | if (newchannel->state == CHANNEL_OPEN_STATE) { | ||
121 | newchannel->state = CHANNEL_OPENING_STATE; | ||
122 | } else { | ||
123 | spin_unlock_irqrestore(&newchannel->sc_lock, flags); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | spin_unlock_irqrestore(&newchannel->sc_lock, flags); | ||
127 | |||
119 | newchannel->onchannel_callback = onchannelcallback; | 128 | newchannel->onchannel_callback = onchannelcallback; |
120 | newchannel->channel_callback_context = context; | 129 | newchannel->channel_callback_context = context; |
121 | 130 | ||
@@ -216,6 +225,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
216 | list_del(&open_info->msglistentry); | 225 | list_del(&open_info->msglistentry); |
217 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 226 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
218 | 227 | ||
228 | if (err == 0) | ||
229 | newchannel->state = CHANNEL_OPENED_STATE; | ||
230 | |||
219 | kfree(open_info); | 231 | kfree(open_info); |
220 | return err; | 232 | return err; |
221 | 233 | ||
@@ -500,15 +512,14 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) | |||
500 | } | 512 | } |
501 | EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); | 513 | EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); |
502 | 514 | ||
503 | /* | 515 | static void vmbus_close_internal(struct vmbus_channel *channel) |
504 | * vmbus_close - Close the specified channel | ||
505 | */ | ||
506 | void vmbus_close(struct vmbus_channel *channel) | ||
507 | { | 516 | { |
508 | struct vmbus_channel_close_channel *msg; | 517 | struct vmbus_channel_close_channel *msg; |
509 | int ret; | 518 | int ret; |
510 | unsigned long flags; | 519 | unsigned long flags; |
511 | 520 | ||
521 | channel->state = CHANNEL_OPEN_STATE; | ||
522 | channel->sc_creation_callback = NULL; | ||
512 | /* Stop callback and cancel the timer asap */ | 523 | /* Stop callback and cancel the timer asap */ |
513 | spin_lock_irqsave(&channel->inbound_lock, flags); | 524 | spin_lock_irqsave(&channel->inbound_lock, flags); |
514 | channel->onchannel_callback = NULL; | 525 | channel->onchannel_callback = NULL; |
@@ -538,6 +549,37 @@ void vmbus_close(struct vmbus_channel *channel) | |||
538 | 549 | ||
539 | 550 | ||
540 | } | 551 | } |
552 | |||
553 | /* | ||
554 | * vmbus_close - Close the specified channel | ||
555 | */ | ||
556 | void vmbus_close(struct vmbus_channel *channel) | ||
557 | { | ||
558 | struct list_head *cur, *tmp; | ||
559 | struct vmbus_channel *cur_channel; | ||
560 | |||
561 | if (channel->primary_channel != NULL) { | ||
562 | /* | ||
563 | * We will only close sub-channels when | ||
564 | * the primary is closed. | ||
565 | */ | ||
566 | return; | ||
567 | } | ||
568 | /* | ||
569 | * Close all the sub-channels first and then close the | ||
570 | * primary channel. | ||
571 | */ | ||
572 | list_for_each_safe(cur, tmp, &channel->sc_list) { | ||
573 | cur_channel = list_entry(cur, struct vmbus_channel, sc_list); | ||
574 | if (cur_channel->state != CHANNEL_OPENED_STATE) | ||
575 | continue; | ||
576 | vmbus_close_internal(cur_channel); | ||
577 | } | ||
578 | /* | ||
579 | * Now close the primary. | ||
580 | */ | ||
581 | vmbus_close_internal(channel); | ||
582 | } | ||
541 | EXPORT_SYMBOL_GPL(vmbus_close); | 583 | EXPORT_SYMBOL_GPL(vmbus_close); |
542 | 584 | ||
543 | /** | 585 | /** |