aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hv/channel.c10
-rw-r--r--drivers/hv/channel_mgmt.c7
-rw-r--r--include/linux/hyperv.h1
3 files changed, 13 insertions, 5 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 19f0cf37e0ed..ba0a092ae085 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -659,22 +659,28 @@ void vmbus_close(struct vmbus_channel *channel)
659 */ 659 */
660 return; 660 return;
661 } 661 }
662 mutex_lock(&vmbus_connection.channel_mutex);
663 /* 662 /*
664 * Close all the sub-channels first and then close the 663 * Close all the sub-channels first and then close the
665 * primary channel. 664 * primary channel.
666 */ 665 */
667 list_for_each_safe(cur, tmp, &channel->sc_list) { 666 list_for_each_safe(cur, tmp, &channel->sc_list) {
668 cur_channel = list_entry(cur, struct vmbus_channel, sc_list); 667 cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
669 vmbus_close_internal(cur_channel);
670 if (cur_channel->rescind) { 668 if (cur_channel->rescind) {
669 wait_for_completion(&cur_channel->rescind_event);
670 mutex_lock(&vmbus_connection.channel_mutex);
671 vmbus_close_internal(cur_channel);
671 hv_process_channel_removal( 672 hv_process_channel_removal(
672 cur_channel->offermsg.child_relid); 673 cur_channel->offermsg.child_relid);
674 } else {
675 mutex_lock(&vmbus_connection.channel_mutex);
676 vmbus_close_internal(cur_channel);
673 } 677 }
678 mutex_unlock(&vmbus_connection.channel_mutex);
674 } 679 }
675 /* 680 /*
676 * Now close the primary. 681 * Now close the primary.
677 */ 682 */
683 mutex_lock(&vmbus_connection.channel_mutex);
678 vmbus_close_internal(channel); 684 vmbus_close_internal(channel);
679 mutex_unlock(&vmbus_connection.channel_mutex); 685 mutex_unlock(&vmbus_connection.channel_mutex);
680} 686}
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index ec5454f3f4a6..c21020b69114 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -333,6 +333,7 @@ static struct vmbus_channel *alloc_channel(void)
333 return NULL; 333 return NULL;
334 334
335 spin_lock_init(&channel->lock); 335 spin_lock_init(&channel->lock);
336 init_completion(&channel->rescind_event);
336 337
337 INIT_LIST_HEAD(&channel->sc_list); 338 INIT_LIST_HEAD(&channel->sc_list);
338 INIT_LIST_HEAD(&channel->percpu_list); 339 INIT_LIST_HEAD(&channel->percpu_list);
@@ -898,6 +899,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
898 /* 899 /*
899 * Now wait for offer handling to complete. 900 * Now wait for offer handling to complete.
900 */ 901 */
902 vmbus_rescind_cleanup(channel);
901 while (READ_ONCE(channel->probe_done) == false) { 903 while (READ_ONCE(channel->probe_done) == false) {
902 /* 904 /*
903 * We wait here until any channel offer is currently 905 * We wait here until any channel offer is currently
@@ -913,7 +915,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
913 if (channel->device_obj) { 915 if (channel->device_obj) {
914 if (channel->chn_rescind_callback) { 916 if (channel->chn_rescind_callback) {
915 channel->chn_rescind_callback(channel); 917 channel->chn_rescind_callback(channel);
916 vmbus_rescind_cleanup(channel);
917 return; 918 return;
918 } 919 }
919 /* 920 /*
@@ -922,7 +923,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
922 */ 923 */
923 dev = get_device(&channel->device_obj->device); 924 dev = get_device(&channel->device_obj->device);
924 if (dev) { 925 if (dev) {
925 vmbus_rescind_cleanup(channel);
926 vmbus_device_unregister(channel->device_obj); 926 vmbus_device_unregister(channel->device_obj);
927 put_device(dev); 927 put_device(dev);
928 } 928 }
@@ -936,13 +936,14 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
936 * 2. Then close the primary channel. 936 * 2. Then close the primary channel.
937 */ 937 */
938 mutex_lock(&vmbus_connection.channel_mutex); 938 mutex_lock(&vmbus_connection.channel_mutex);
939 vmbus_rescind_cleanup(channel);
940 if (channel->state == CHANNEL_OPEN_STATE) { 939 if (channel->state == CHANNEL_OPEN_STATE) {
941 /* 940 /*
942 * The channel is currently not open; 941 * The channel is currently not open;
943 * it is safe for us to cleanup the channel. 942 * it is safe for us to cleanup the channel.
944 */ 943 */
945 hv_process_channel_removal(rescind->child_relid); 944 hv_process_channel_removal(rescind->child_relid);
945 } else {
946 complete(&channel->rescind_event);
946 } 947 }
947 mutex_unlock(&vmbus_connection.channel_mutex); 948 mutex_unlock(&vmbus_connection.channel_mutex);
948 } 949 }
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index f3e97c5f94c9..6c9336626592 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -708,6 +708,7 @@ struct vmbus_channel {
708 u8 monitor_bit; 708 u8 monitor_bit;
709 709
710 bool rescind; /* got rescind msg */ 710 bool rescind; /* got rescind msg */
711 struct completion rescind_event;
711 712
712 u32 ringbuffer_gpadlhandle; 713 u32 ringbuffer_gpadlhandle;
713 714