@@ -407,7 +407,15 @@ void hv_process_channel_removal(struct vmbus_channel *channel)
407
407
cpumask_clear_cpu (channel -> target_cpu ,
408
408
& primary_channel -> alloced_cpus_in_node );
409
409
410
- vmbus_release_relid (channel -> offermsg .child_relid );
410
+ /*
411
+ * Upon suspend, an in-use hv_sock channel is marked as "rescinded" and
412
+ * the relid is invalidated; after hibernation, when the user-space app
413
+ * destroys the channel, the relid is INVALID_RELID, and in this case
414
+ * it's unnecessary and unsafe to release the old relid, since the same
415
+ * relid can refer to a completely different channel now.
416
+ */
417
+ if (channel -> offermsg .child_relid != INVALID_RELID )
418
+ vmbus_release_relid (channel -> offermsg .child_relid );
411
419
412
420
free_channel (channel );
413
421
}
@@ -851,6 +859,36 @@ void vmbus_initiate_unload(bool crash)
851
859
vmbus_wait_for_unload ();
852
860
}
853
861
862
+ static void check_ready_for_resume_event (void )
863
+ {
864
+ /*
865
+ * If all the old primary channels have been fixed up, then it's safe
866
+ * to resume.
867
+ */
868
+ if (atomic_dec_and_test (& vmbus_connection .nr_chan_fixup_on_resume ))
869
+ complete (& vmbus_connection .ready_for_resume_event );
870
+ }
871
+
872
+ static void vmbus_setup_channel_state (struct vmbus_channel * channel ,
873
+ struct vmbus_channel_offer_channel * offer )
874
+ {
875
+ /*
876
+ * Setup state for signalling the host.
877
+ */
878
+ channel -> sig_event = VMBUS_EVENT_CONNECTION_ID ;
879
+
880
+ if (vmbus_proto_version != VERSION_WS2008 ) {
881
+ channel -> is_dedicated_interrupt =
882
+ (offer -> is_dedicated_interrupt != 0 );
883
+ channel -> sig_event = offer -> connection_id ;
884
+ }
885
+
886
+ memcpy (& channel -> offermsg , offer ,
887
+ sizeof (struct vmbus_channel_offer_channel ));
888
+ channel -> monitor_grp = (u8 )offer -> monitorid / 32 ;
889
+ channel -> monitor_bit = (u8 )offer -> monitorid % 32 ;
890
+ }
891
+
854
892
/*
855
893
* find_primary_channel_by_offer - Get the channel object given the new offer.
856
894
* This is only used in the resume path of hibernation.
@@ -902,21 +940,42 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
902
940
atomic_dec (& vmbus_connection .offer_in_progress );
903
941
904
942
/*
905
- * We're resuming from hibernation: we expect the host to send
906
- * exactly the same offers that we had before the hibernation.
943
+ * We're resuming from hibernation: all the sub-channel and
944
+ * hv_sock channels we had before the hibernation should have
945
+ * been cleaned up, and now we must be seeing a re-offered
946
+ * primary channel that we had before the hibernation.
907
947
*/
948
+
949
+ WARN_ON (oldchannel -> offermsg .child_relid != INVALID_RELID );
950
+ /* Fix up the relid. */
951
+ oldchannel -> offermsg .child_relid = offer -> child_relid ;
952
+
908
953
offer_sz = sizeof (* offer );
909
- if (memcmp (offer , & oldchannel -> offermsg , offer_sz ) == 0 )
954
+ if (memcmp (offer , & oldchannel -> offermsg , offer_sz ) == 0 ) {
955
+ check_ready_for_resume_event ();
910
956
return ;
957
+ }
911
958
912
- pr_debug ("Mismatched offer from the host (relid=%d)\n" ,
959
+ /*
960
+ * This is not an error, since the host can also change the
961
+ * other field(s) of the offer, e.g. on WS RS5 (Build 17763),
962
+ * the offer->connection_id of the Mellanox VF vmbus device
963
+ * can change when the host reoffers the device upon resume.
964
+ */
965
+ pr_debug ("vmbus offer changed: relid=%d\n" ,
913
966
offer -> child_relid );
914
967
915
968
print_hex_dump_debug ("Old vmbus offer: " , DUMP_PREFIX_OFFSET ,
916
969
16 , 4 , & oldchannel -> offermsg , offer_sz ,
917
970
false);
918
971
print_hex_dump_debug ("New vmbus offer: " , DUMP_PREFIX_OFFSET ,
919
972
16 , 4 , offer , offer_sz , false);
973
+
974
+ /* Fix up the old channel. */
975
+ vmbus_setup_channel_state (oldchannel , offer );
976
+
977
+ check_ready_for_resume_event ();
978
+
920
979
return ;
921
980
}
922
981
@@ -929,21 +988,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
929
988
return ;
930
989
}
931
990
932
- /*
933
- * Setup state for signalling the host.
934
- */
935
- newchannel -> sig_event = VMBUS_EVENT_CONNECTION_ID ;
936
-
937
- if (vmbus_proto_version != VERSION_WS2008 ) {
938
- newchannel -> is_dedicated_interrupt =
939
- (offer -> is_dedicated_interrupt != 0 );
940
- newchannel -> sig_event = offer -> connection_id ;
941
- }
942
-
943
- memcpy (& newchannel -> offermsg , offer ,
944
- sizeof (struct vmbus_channel_offer_channel ));
945
- newchannel -> monitor_grp = (u8 )offer -> monitorid / 32 ;
946
- newchannel -> monitor_bit = (u8 )offer -> monitorid % 32 ;
991
+ vmbus_setup_channel_state (newchannel , offer );
947
992
948
993
vmbus_process_offer (newchannel );
949
994
}
0 commit comments