diff options
-rw-r--r-- | drivers/hv/channel.c | 10 | ||||
-rw-r--r-- | drivers/hv/channel_mgmt.c | 7 | ||||
-rw-r--r-- | include/linux/hyperv.h | 1 |
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 | ||