Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: vmbus: Fix a rescind issue

The current rescind processing code will not correctly handle
the case where the host immediately rescinds a channel that has
been offerred. In this case, we could be blocked in the open call and
since the channel is rescinded, the host will not respond and we could
be blocked forever in the vmbus open call.i Fix this problem.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

K. Y. Srinivasan and committed by
Greg Kroah-Hartman
7fa32e5e fb2c4452

+13 -5
+8 -2
drivers/hv/channel.c
··· 659 659 */ 660 660 return; 661 661 } 662 - mutex_lock(&vmbus_connection.channel_mutex); 663 662 /* 664 663 * Close all the sub-channels first and then close the 665 664 * primary channel. 666 665 */ 667 666 list_for_each_safe(cur, tmp, &channel->sc_list) { 668 667 cur_channel = list_entry(cur, struct vmbus_channel, sc_list); 669 - vmbus_close_internal(cur_channel); 670 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 672 hv_process_channel_removal( 672 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 681 * Now close the primary. 677 682 */ 683 + mutex_lock(&vmbus_connection.channel_mutex); 678 684 vmbus_close_internal(channel); 679 685 mutex_unlock(&vmbus_connection.channel_mutex); 680 686 }
+4 -3
drivers/hv/channel_mgmt.c
··· 333 333 return NULL; 334 334 335 335 spin_lock_init(&channel->lock); 336 + init_completion(&channel->rescind_event); 336 337 337 338 INIT_LIST_HEAD(&channel->sc_list); 338 339 INIT_LIST_HEAD(&channel->percpu_list); ··· 899 898 /* 900 899 * Now wait for offer handling to complete. 901 900 */ 901 + vmbus_rescind_cleanup(channel); 902 902 while (READ_ONCE(channel->probe_done) == false) { 903 903 /* 904 904 * We wait here until any channel offer is currently ··· 915 913 if (channel->device_obj) { 916 914 if (channel->chn_rescind_callback) { 917 915 channel->chn_rescind_callback(channel); 918 - vmbus_rescind_cleanup(channel); 919 916 return; 920 917 } 921 918 /* ··· 923 922 */ 924 923 dev = get_device(&channel->device_obj->device); 925 924 if (dev) { 926 - vmbus_rescind_cleanup(channel); 927 925 vmbus_device_unregister(channel->device_obj); 928 926 put_device(dev); 929 927 } ··· 936 936 * 2. Then close the primary channel. 937 937 */ 938 938 mutex_lock(&vmbus_connection.channel_mutex); 939 - vmbus_rescind_cleanup(channel); 940 939 if (channel->state == CHANNEL_OPEN_STATE) { 941 940 /* 942 941 * The channel is currently not open; 943 942 * it is safe for us to cleanup the channel. 944 943 */ 945 944 hv_process_channel_removal(rescind->child_relid); 945 + } else { 946 + complete(&channel->rescind_event); 946 947 } 947 948 mutex_unlock(&vmbus_connection.channel_mutex); 948 949 }
+1
include/linux/hyperv.h
··· 708 708 u8 monitor_bit; 709 709 710 710 bool rescind; /* got rescind msg */ 711 + struct completion rescind_event; 711 712 712 713 u32 ringbuffer_gpadlhandle; 713 714